1 /* $NetBSD: rbus_machdep.c,v 1.15 2009/03/14 21:04:16 dsl 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.15 2009/03/14 21:04:16 dsl 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 <machine/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 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 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 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 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 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, PPB_REG_BUSINFO); 161 reg &= 0xff000000; 162 reg |= pa->pa_bus | (bus << 8) | (bus << 16); 163 pci_conf_write(pc, pa->pa_tag, PPB_REG_BUSINFO, 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 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