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