xref: /netbsd/sys/arch/sparc64/sparc64/rbus_machdep.c (revision fd4710db)
1*fd4710dbSmsaitoh /*	$NetBSD: rbus_machdep.c,v 1.17 2019/03/01 09:25:59 msaitoh Exp $	*/
2b1a9940dSnakayama 
3b1a9940dSnakayama /*
4b1a9940dSnakayama  * Copyright (c) 2003 Takeshi Nakayama.
5b1a9940dSnakayama  * All rights reserved.
6b1a9940dSnakayama  *
7b1a9940dSnakayama  * Redistribution and use in source and binary forms, with or without
8b1a9940dSnakayama  * modification, are permitted provided that the following conditions
9b1a9940dSnakayama  * are met:
10b1a9940dSnakayama  * 1. Redistributions of source code must retain the above copyright
11b1a9940dSnakayama  *    notice, this list of conditions and the following disclaimer.
12b1a9940dSnakayama  * 2. Redistributions in binary form must reproduce the above copyright
13b1a9940dSnakayama  *    notice, this list of conditions and the following disclaimer in the
14b1a9940dSnakayama  *    documentation and/or other materials provided with the distribution.
15b1a9940dSnakayama  *
16b1a9940dSnakayama  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17b1a9940dSnakayama  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18b1a9940dSnakayama  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19b1a9940dSnakayama  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20b1a9940dSnakayama  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21b1a9940dSnakayama  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22b1a9940dSnakayama  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23b1a9940dSnakayama  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24b1a9940dSnakayama  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25b1a9940dSnakayama  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26b1a9940dSnakayama  */
27b1a9940dSnakayama 
28ed517291Slukem #include <sys/cdefs.h>
29*fd4710dbSmsaitoh __KERNEL_RCSID(0, "$NetBSD: rbus_machdep.c,v 1.17 2019/03/01 09:25:59 msaitoh Exp $");
30ed517291Slukem 
31b1a9940dSnakayama #include <sys/param.h>
32b1a9940dSnakayama #include <sys/device.h>
33b1a9940dSnakayama #include <sys/extent.h>
34b1a9940dSnakayama #include <sys/systm.h>
35b1a9940dSnakayama 
368cf919c1Sdyoung #include <sys/bus.h>
37b1a9940dSnakayama #include <machine/openfirm.h>
38d1fa565fSnakayama #include <machine/promlib.h>
39b1a9940dSnakayama #include <dev/pci/pcivar.h>
40b1a9940dSnakayama #include <dev/pci/ppbreg.h>
41b1a9940dSnakayama #include <sparc64/dev/iommuvar.h>
42b1a9940dSnakayama #include <sparc64/dev/psychovar.h>
43b1a9940dSnakayama 
44b1a9940dSnakayama #include <dev/cardbus/rbus.h>
4588b527f6Snakayama #include <dev/pcmcia/pcmciachip.h>
4688b527f6Snakayama #include <dev/ic/i82365reg.h>
47b1a9940dSnakayama #include <dev/pci/pccbbreg.h>
48b1a9940dSnakayama #include <dev/pci/pccbbvar.h>
49b1a9940dSnakayama 
50b1a9940dSnakayama #ifdef RBUS_DEBUG
51b1a9940dSnakayama # define DPRINTF printf
52b1a9940dSnakayama #else
53b1a9940dSnakayama # define DPRINTF while (0) printf
54b1a9940dSnakayama #endif
55b1a9940dSnakayama 
56d50f0c62Scdi static int pccbb_cardbus_isvalid(void *);
57b1a9940dSnakayama 
58b1a9940dSnakayama int
md_space_map(bus_space_tag_t t,bus_addr_t bpa,bus_size_t size,int flags,bus_space_handle_t * bshp)5988b527f6Snakayama md_space_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags,
6088b527f6Snakayama 	     bus_space_handle_t *bshp)
61b1a9940dSnakayama {
62b1a9940dSnakayama 	DPRINTF("md_space_map: 0x%" PRIxPTR ", 0x%" PRIx64 ", 0x%" PRIx64 "\n",
63b1a9940dSnakayama 		(u_long)t->cookie, bpa, size);
64b1a9940dSnakayama 
65b1a9940dSnakayama 	return bus_space_map(t, bpa, size, flags, bshp);
66b1a9940dSnakayama }
67b1a9940dSnakayama 
68b1a9940dSnakayama void
md_space_unmap(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t size,bus_addr_t * adrp)6982357f6dSdsl md_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size, bus_addr_t *adrp)
70b1a9940dSnakayama {
71b1a9940dSnakayama 	DPRINTF("md_space_unmap: 0x%" PRIxPTR ", 0x%" PRIx64 ", 0x%" PRIx64
72b1a9940dSnakayama 		"\n", (u_long)t->cookie, bsh._ptr, size);
73b1a9940dSnakayama 
74b1a9940dSnakayama 	/* return the PCI offset address if required */
75b1a9940dSnakayama 	if (adrp != NULL)
76b1a9940dSnakayama 		*adrp = psycho_bus_offset(t, &bsh);
77b1a9940dSnakayama 	bus_space_unmap(t, bsh, size);
78b1a9940dSnakayama }
79b1a9940dSnakayama 
80b1a9940dSnakayama rbus_tag_t
rbus_pccbb_parent_mem(struct pci_attach_args * pa)8188b527f6Snakayama rbus_pccbb_parent_mem(struct pci_attach_args *pa)
82b1a9940dSnakayama {
83b1a9940dSnakayama 	pci_chipset_tag_t pc = pa->pa_pc;
84b1a9940dSnakayama 	struct psycho_pbm *pp = pc->cookie;
85b1a9940dSnakayama 	struct extent *ex = pp->pp_exmem;
86b1a9940dSnakayama 	bus_addr_t start;
87b1a9940dSnakayama 	bus_size_t size;
88b1a9940dSnakayama 
89b1a9940dSnakayama 	if (ex == NULL)
90b1a9940dSnakayama 		panic("rbus_pccbb_parent_mem: extent is not initialized");
91b1a9940dSnakayama 
92b1a9940dSnakayama 	start = ex->ex_start;
93b1a9940dSnakayama 	size = ex->ex_end - start;
94b1a9940dSnakayama 
95b1a9940dSnakayama 	return rbus_new_root_share(pa->pa_memt, ex, start, size, 0);
96b1a9940dSnakayama }
97b1a9940dSnakayama 
98b1a9940dSnakayama rbus_tag_t
rbus_pccbb_parent_io(struct pci_attach_args * pa)9988b527f6Snakayama rbus_pccbb_parent_io(struct pci_attach_args *pa)
100b1a9940dSnakayama {
101b1a9940dSnakayama 	pci_chipset_tag_t pc = pa->pa_pc;
102b1a9940dSnakayama 	struct psycho_pbm *pp = pc->cookie;
103b1a9940dSnakayama 	struct extent *ex = pp->pp_exio;
104b1a9940dSnakayama 	bus_addr_t start;
105b1a9940dSnakayama 	bus_size_t size;
106b1a9940dSnakayama 
107b1a9940dSnakayama 	if (ex == NULL)
108b1a9940dSnakayama 		panic("rbus_pccbb_parent_io: extent is not initialized");
109b1a9940dSnakayama 
110b1a9940dSnakayama 	start = ex->ex_start;
111b1a9940dSnakayama 	size = ex->ex_end - start;
112b1a9940dSnakayama 
113b1a9940dSnakayama 	return rbus_new_root_share(pa->pa_iot, ex, start, size, 0);
114b1a9940dSnakayama }
115b1a9940dSnakayama 
116b1a9940dSnakayama /*
117b1a9940dSnakayama  * Machine dependent part for the attachment of PCI-CardBus bridge.
118b1a9940dSnakayama  * This function is called from pccbb_attach() in sys/dev/pci/pccbb.c.
119b1a9940dSnakayama  */
120b1a9940dSnakayama void
pccbb_attach_hook(device_t parent,device_t self,struct pci_attach_args * pa)12188b527f6Snakayama pccbb_attach_hook(device_t parent, device_t self, struct pci_attach_args *pa)
122b1a9940dSnakayama {
123b1a9940dSnakayama 	pci_chipset_tag_t pc = pa->pa_pc;
124b1a9940dSnakayama 	pcireg_t reg;
125b1a9940dSnakayama 	int node = PCITAG_NODE(pa->pa_tag);
1260d449edaSpk 	int error;
127d1fa565fSnakayama 	int bus, br[2], *brp;
128b1a9940dSnakayama 	int len, intr;
129b1a9940dSnakayama 
130b1a9940dSnakayama 	/*
131b1a9940dSnakayama 	 * bus fixup:
132b1a9940dSnakayama 	 *	if OBP didn't assign a bus number to the cardbus bridge,
1330f9cf6edSnakayama 	 *	then assign it here.
134b1a9940dSnakayama 	 */
135d1fa565fSnakayama 	brp = br;
136d1fa565fSnakayama 	len = 2;
137d1fa565fSnakayama 	error = prom_getprop(node, "bus-range", sizeof(*brp), &len, &brp);
1380d449edaSpk 	if (error == 0 && len == 2) {
139b1a9940dSnakayama 		bus = br[0];
140b1a9940dSnakayama 		DPRINTF("pccbb_attach_hook: bus-range %d-%d\n", br[0], br[1]);
141b1a9940dSnakayama 		if (bus < 0 || bus >= 256)
142b1a9940dSnakayama 			printf("pccbb_attach_hook: broken bus %d\n", bus);
143b1a9940dSnakayama 		else {
144b1a9940dSnakayama #ifdef DIAGNOSTIC
145f7575540Smrg 			if ((*pc->spc_busnode)[bus].node != 0)
146b1a9940dSnakayama 				printf("pccbb_attach_hook: override bus %d"
147b1a9940dSnakayama 				       " node %08x -> %08x\n",
148f7575540Smrg 				       bus, (*pc->spc_busnode)[bus].node, node);
149b1a9940dSnakayama #endif
150f7575540Smrg 			(*pc->spc_busnode)[bus].arg = device_private(self);
151f7575540Smrg 			(*pc->spc_busnode)[bus].valid = pccbb_cardbus_isvalid;
152f7575540Smrg 			(*pc->spc_busnode)[bus].node = node;
153b1a9940dSnakayama 		}
154b1a9940dSnakayama 	} else {
155f7575540Smrg 		bus = ++pc->spc_busmax;
156b1a9940dSnakayama 		DPRINTF("pccbb_attach_hook: bus %d\n", bus);
157b1a9940dSnakayama 		if (bus >= 256)
158b1a9940dSnakayama 			printf("pccbb_attach_hook: 256 >= busses exist\n");
159b1a9940dSnakayama 		else {
160*fd4710dbSmsaitoh 			reg = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_BUS_REG);
161b1a9940dSnakayama 			reg &= 0xff000000;
162fd41cea7Snakayama 			reg |= pa->pa_bus | (bus << 8) | (bus << 16);
163*fd4710dbSmsaitoh 			pci_conf_write(pc, pa->pa_tag, PCI_BRIDGE_BUS_REG, reg);
164b1a9940dSnakayama #ifdef DIAGNOSTIC
165f7575540Smrg 			if ((*pc->spc_busnode)[bus].node != 0)
166b1a9940dSnakayama 				printf("pccbb_attach_hook: override bus %d"
167b1a9940dSnakayama 				       " node %08x -> %08x\n",
168f7575540Smrg 				       bus, (*pc->spc_busnode)[bus].node, node);
169b1a9940dSnakayama #endif
170f7575540Smrg 			(*pc->spc_busnode)[bus].arg = device_private(self);
171f7575540Smrg 			(*pc->spc_busnode)[bus].valid = pccbb_cardbus_isvalid;
172f7575540Smrg 			(*pc->spc_busnode)[bus].node = node;
173b1a9940dSnakayama 		}
174b1a9940dSnakayama 	}
175b1a9940dSnakayama 
176b1a9940dSnakayama 	/*
177b1a9940dSnakayama 	 * interrupt fixup:
178b1a9940dSnakayama 	 *	fake interrupt line not for giving up the probe.
179625feacdSnakayama 	 *	interrupt numbers assigned by OBP are [0x00,0x3f],
180625feacdSnakayama 	 *	so they map to [0x40,0x7f] due to inhibit the value 0x00.
181b1a9940dSnakayama 	 */
182d1fa565fSnakayama 	if ((intr = prom_getpropint(node, "interrupts", -1)) == -1) {
183b1a9940dSnakayama 		printf("pccbb_attach_hook: could not read interrupts\n");
1840d449edaSpk 		return;
1850d449edaSpk 	}
1860d449edaSpk 
1870d449edaSpk 	if (OF_mapintr(node, &intr, sizeof(intr), sizeof(intr)) < 0) {
188b1a9940dSnakayama 		printf("pccbb_attach_hook: OF_mapintr failed\n");
1890d449edaSpk 		return;
1900d449edaSpk 	}
1910d449edaSpk 
192625feacdSnakayama 	pa->pa_intrline = intr | 0x40;
193b1a9940dSnakayama 	DPRINTF("pccbb_attach_hook: interrupt line %d\n", intr);
194b1a9940dSnakayama }
195b1a9940dSnakayama 
196b1a9940dSnakayama /*
197b1a9940dSnakayama  * Detect a validity of CardBus bus, since it occurs PCI bus error
198b1a9940dSnakayama  * when a CardBus card is not present or power-off.
199b1a9940dSnakayama  */
200b1a9940dSnakayama static int
pccbb_cardbus_isvalid(void * arg)201d50f0c62Scdi pccbb_cardbus_isvalid(void *arg)
202b1a9940dSnakayama {
203b1a9940dSnakayama 	struct pccbb_softc *sc = arg;
204b1a9940dSnakayama 	bus_space_tag_t memt = sc->sc_base_memt;
205b1a9940dSnakayama 	bus_space_handle_t memh = sc->sc_base_memh;
206d50f0c62Scdi 	uint32_t sockstat, sockctrl;
207b1a9940dSnakayama 
208b1a9940dSnakayama 	/* check CardBus card is present */
209b1a9940dSnakayama 	sockstat = bus_space_read_4(memt, memh, CB_SOCKET_STAT);
210b1a9940dSnakayama 	DPRINTF("%s: pccbb_cardbus_isvalid: sockstat %08x\n",
21188b527f6Snakayama 		device_xname(sc->sc_dev), sockstat);
212b1a9940dSnakayama 	if ((sockstat & CB_SOCKET_STAT_CB) == 0 ||
213b1a9940dSnakayama 	    (sockstat & CB_SOCKET_STAT_CD) != 0)
214b1a9940dSnakayama 		return 0;
215b1a9940dSnakayama 
216b1a9940dSnakayama 	/* check card is powered on */
217b1a9940dSnakayama 	sockctrl = bus_space_read_4(memt, memh, CB_SOCKET_CTRL);
218b1a9940dSnakayama 	DPRINTF("%s: pccbb_cardbus_isvalid: sockctrl %08x\n",
21988b527f6Snakayama 		device_xname(sc->sc_dev), sockctrl);
220b1a9940dSnakayama 	if ((sockctrl & CB_SOCKET_CTRL_VCCMASK) == 0)
221b1a9940dSnakayama 		return 0;
222b1a9940dSnakayama 
223b1a9940dSnakayama 	/* card is present and powered on */
224b1a9940dSnakayama 	return 1;
225b1a9940dSnakayama }
226