ht.c revision 1.5
1/* $OpenBSD: ht.c,v 1.5 2005/09/30 21:37:21 kettenis Exp $ */ 2 3/* 4 * Copyright (c) 2005 Mark Kettenis 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/systm.h> 21#include <sys/device.h> 22 23#include <machine/autoconf.h> 24#include <machine/bus.h> 25 26#include <dev/pci/pcireg.h> 27#include <dev/pci/pcivar.h> 28#include <dev/pci/pcidevs.h> 29 30#include <macppc/pci/pcibrvar.h> 31 32#include <dev/ofw/openfirm.h> 33 34int ht_match(struct device *, void *, void *); 35void ht_attach(struct device *, struct device *, void *); 36 37void ht_attach_hook(struct device *, struct device *, 38 struct pcibus_attach_args *); 39int ht_bus_maxdevs(void *, int); 40pcitag_t ht_make_tag(void *, int, int, int); 41void ht_decompose_tag(void *, pcitag_t, int *, int *, int *); 42pcireg_t ht_conf_read(void *, pcitag_t, int); 43void ht_conf_write(void *, pcitag_t, int, pcireg_t); 44int ht_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *); 45const char *ht_intr_string(void *, pci_intr_handle_t); 46int ht_intr_line(void *, pci_intr_handle_t); 47void *ht_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), 48 void *, char *); 49void ht_intr_disestablish(void *, void *); 50 51int ht_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *); 52 53int ht_print(void *, const char *); 54 55struct ht_softc { 56 struct device sc_dev; 57 int sc_maxdevs; 58 struct ppc_bus_space sc_mem_bus_space; 59 struct ppc_bus_space sc_io_bus_space; 60 struct ppc_pci_chipset sc_pc; 61 bus_space_tag_t sc_memt; 62 bus_space_handle_t sc_config0_memh; 63 bus_space_handle_t sc_config1_memh; 64 bus_space_tag_t sc_iot; 65 bus_space_handle_t sc_config0_ioh; 66}; 67 68struct cfattach ht_ca = { 69 sizeof(struct ht_softc), ht_match, ht_attach 70}; 71 72struct cfdriver ht_cd = { 73 NULL, "ht", DV_DULL, 74}; 75 76#if 0 77struct powerpc_bus_dma_tag pci_bus_dma_tag = { 78 NULL, 79 _dmamap_create, 80 _dmamap_destroy, 81 _dmamap_load, 82 _dmamap_load_mbuf, 83 _dmamap_load_uio, 84 _dmamap_load_raw, 85 _dmamap_unload, 86 _dmamap_sync, 87 _dmamem_alloc, 88 _dmamem_free, 89 _dmamem_map, 90 _dmamem_unmap, 91 _dmamem_mmap 92}; 93#else 94extern struct powerpc_bus_dma_tag pci_bus_dma_tag; 95#endif 96 97int 98ht_match(struct device *parent, void *cf, void *aux) 99{ 100 struct confargs *ca = aux; 101 102 if (strcmp(ca->ca_name, "ht") == 0) 103 return (1); 104 return (0); 105} 106 107void 108ht_attach(struct device *parent, struct device *self, void *aux) 109{ 110 struct ht_softc *sc = (struct ht_softc *)self; 111 struct confargs *ca = aux; 112 struct pcibus_attach_args pba; 113 u_int32_t regs[6]; 114 char compat[32]; 115 int node, nn; 116 int len; 117 118 if (ca->ca_node == 0) { 119 printf("invalid node on ht config\n"); 120 return; 121 } 122 123 len = OF_getprop(ca->ca_node, "reg", regs, sizeof(regs)); 124 if (len < sizeof(regs)) { 125 printf(": regs lookup failed, node %x\n", ca->ca_node); 126 return; 127 } 128 129 sc->sc_mem_bus_space.bus_base = 0x80000000; 130 sc->sc_mem_bus_space.bus_size = 0; 131 sc->sc_mem_bus_space.bus_io = 0; 132 sc->sc_memt = &sc->sc_mem_bus_space; 133 134 sc->sc_io_bus_space.bus_base = 0x80000000; 135 sc->sc_io_bus_space.bus_size = 0; 136 sc->sc_io_bus_space.bus_io = 1; 137 sc->sc_iot = &sc->sc_io_bus_space; 138 139 if (bus_space_map(sc->sc_memt, regs[1], 0x4000, 0, 140 &sc->sc_config0_memh)) { 141 printf(": can't map PCI config0 memory\n"); 142 return; 143 } 144 145 if (bus_space_map(sc->sc_memt, regs[1] + 0x01000000, 0x80000, 0, 146 &sc->sc_config1_memh)) { 147 printf(": can't map PCI config1 memory\n"); 148 return; 149 } 150 151 if (bus_space_map(sc->sc_iot, regs[4], 0x1000, 0, 152 &sc->sc_config0_ioh)) { 153 printf(": can't map PCI config0 io\n"); 154 return; 155 } 156 157 len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat)); 158 if (len <= 0) 159 printf(": unknown"); 160 else 161 printf(": %s", compat); 162 163 sc->sc_pc.pc_conf_v = sc; 164 sc->sc_pc.pc_attach_hook = ht_attach_hook; 165 sc->sc_pc.pc_bus_maxdevs = ht_bus_maxdevs; 166 sc->sc_pc.pc_make_tag = ht_make_tag; 167 sc->sc_pc.pc_decompose_tag = ht_decompose_tag; 168 sc->sc_pc.pc_conf_read = ht_conf_read; 169 sc->sc_pc.pc_conf_write = ht_conf_write; 170 171 sc->sc_pc.pc_intr_v = sc; 172 sc->sc_pc.pc_intr_map = ht_intr_map; 173 sc->sc_pc.pc_intr_string = ht_intr_string; 174 sc->sc_pc.pc_intr_line = ht_intr_line; 175 sc->sc_pc.pc_intr_establish = ht_intr_establish; 176 sc->sc_pc.pc_intr_disestablish = ht_intr_disestablish; 177 sc->sc_pc.pc_ether_hw_addr = ht_ether_hw_addr; 178 179 pba.pba_busname = "pci"; 180 pba.pba_iot = sc->sc_iot; 181 pba.pba_memt = sc->sc_memt; 182 pba.pba_dmat = &pci_bus_dma_tag; 183 pba.pba_pc = &sc->sc_pc; 184 pba.pba_bus = 0; 185 186 sc->sc_maxdevs = 1; 187 for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) 188 sc->sc_maxdevs++; 189 printf(": %d devices\n", sc->sc_maxdevs); 190 191 extern void fix_node_irq(int, struct pcibus_attach_args *); 192 193 for (node = OF_child(ca->ca_node); node; node = nn) { 194 fix_node_irq(node, &pba); 195 196 if ((nn = OF_child(node)) != 0) 197 continue; 198 199 while ((nn = OF_peer(node)) == 0) { 200 node = OF_parent(node); 201 if (node == ca->ca_node) { 202 nn = 0; 203 break; 204 } 205 } 206 } 207 208 config_found(self, &pba, ht_print); 209} 210 211void 212ht_attach_hook(struct device *parent, struct device *self, 213 struct pcibus_attach_args *pba) 214{ 215} 216 217int 218ht_bus_maxdevs(void *cpv, int bus) 219{ 220 struct ht_softc *sc = cpv; 221 222 /* XXX Probing more busses doesn't work. */ 223 if (bus == 0) 224 return sc->sc_maxdevs; 225 return 32; 226} 227 228#define BUS_SHIFT 16 229#define DEVICE_SHIFT 11 230#define FNC_SHIFT 8 231 232pcitag_t 233ht_make_tag(void *cpv, int bus, int dev, int fnc) 234{ 235 return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT); 236} 237 238void 239ht_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp) 240{ 241 if (busp != NULL) 242 *busp = (tag >> BUS_SHIFT) & 0xff; 243 if (devp != NULL) 244 *devp = (tag >> DEVICE_SHIFT) & 0x1f; 245 if (fncp != NULL) 246 *fncp = (tag >> FNC_SHIFT) & 0x7; 247} 248 249pcireg_t 250ht_conf_read(void *cpv, pcitag_t tag, int offset) 251{ 252 struct ht_softc *sc = cpv; 253 int bus, dev, fcn; 254 pcireg_t reg; 255 256#ifdef DEBUG 257 printf("ht_conf_read: tag=%x, offset=%x\n", tag, offset); 258#endif 259 ht_decompose_tag(NULL, tag, &bus, &dev, &fcn); 260 if (bus == 0 && dev == 0) { 261 tag |= (offset << 2); 262 reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); 263 reg = letoh32(reg); 264 } else if (bus == 0) { 265 if (tag >= 0x4000) 266 panic("tag >= 0x4000"); 267 /* XXX Needed on some PowerMac G5's. Why? */ 268 if (fcn > 1) 269 return ~0; 270 tag |= offset; 271 reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); 272 } else { 273 tag |= offset; 274 reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); 275 } 276#ifdef DEBUG 277 printf("ht_conf_read: reg=%x\n", reg); 278#endif 279 return reg; 280} 281 282void 283ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) 284{ 285 struct ht_softc *sc = cpv; 286 int bus, dev; 287 288#ifdef DEBUG 289 printf("ht_conf_write: tag=%x, offset=%x, data = %x\n", 290 tag, offset, data); 291#endif 292 ht_decompose_tag(NULL, tag, &bus, &dev, NULL); 293 if (bus == 0 && dev == 0) { 294 tag |= (offset << 2); 295 data = htole32(data); 296 bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, tag, data); 297 bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); 298 } else if (bus == 0) { 299 tag |= offset; 300 bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, tag, data); 301 bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); 302 } else { 303 tag |= offset; 304 bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, tag, data); 305 bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); 306 } 307} 308 309/* XXX */ 310#define PCI_INTERRUPT_NO_CONNECTION 0xff 311 312int 313ht_intr_map(void *cpv, pcitag_t tag, int pin, int line, 314 pci_intr_handle_t *ihp) 315{ 316 int error = 0; 317 318#ifdef DEBUG 319 printf("ht_intr_map: tag=%x, pin=%d, line=%d\n", tag, pin, line); 320#endif 321 322 *ihp = -1; 323 if (pin == PCI_INTERRUPT_PIN_NONE || 324 line == PCI_INTERRUPT_NO_CONNECTION) 325 error = 1; /* No IRQ used. */ 326 else if (pin > PCI_INTERRUPT_PIN_MAX) { 327 printf("ht_intr_map: bad interrupt pin %d\n", pin); 328 error = 1; 329 } 330 331 if (!error) 332 *ihp = line; 333 return error; 334} 335 336const char * 337ht_intr_string(void *cpv, pci_intr_handle_t ih) 338{ 339 static char str[16]; 340 341 snprintf(str, sizeof str, "irq %ld", ih); 342 return (str); 343} 344 345int 346ht_intr_line(void *cpv, pci_intr_handle_t ih) 347{ 348 return (ih); 349} 350 351void * 352ht_intr_establish(void *cpv, pci_intr_handle_t ih, int level, 353 int (*func)(void *), void *arg, char *name) 354{ 355 return (*intr_establish_func)(cpv, ih, IST_LEVEL, level, func, arg, 356 name); 357} 358 359void 360ht_intr_disestablish(void *lcv, void *cookie) 361{ 362} 363 364int 365ht_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr) 366{ 367 u_int8_t laddr[6]; 368 int node; 369 int len; 370 371 node = OF_finddevice("enet"); 372 len = OF_getprop(node, "local-mac-address", laddr, sizeof(laddr)); 373 if (sizeof(laddr) == len) { 374 memcpy(oaddr, laddr, sizeof(laddr)); 375 return 1; 376 } 377 378 oaddr[0] = oaddr[1] = oaddr[2] = 0xff; 379 oaddr[3] = oaddr[4] = oaddr[5] = 0xff; 380 return 0; 381} 382 383int 384ht_print(void *aux, const char *pnp) 385{ 386 struct pcibus_attach_args *pba = aux; 387 388 if (pnp) 389 printf("%s at %s", pba->pba_busname, pnp); 390 printf(" bus %d", pba->pba_bus); 391 return (UNCONF); 392} 393