ht.c revision 1.14
1/* $OpenBSD: ht.c,v 1.14 2010/12/04 17:06:31 miod 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 *); 42int ht_conf_size(void *, pcitag_t); 43pcireg_t ht_conf_read(void *, pcitag_t, int); 44void ht_conf_write(void *, pcitag_t, int, pcireg_t); 45int ht_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *); 46const char *ht_intr_string(void *, pci_intr_handle_t); 47int ht_intr_line(void *, pci_intr_handle_t); 48void *ht_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), 49 void *, const char *); 50void ht_intr_disestablish(void *, void *); 51 52int ht_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *); 53 54int ht_print(void *, const char *); 55 56#define BUS_SHIFT 16 57#define DEVICE_SHIFT 11 58#define FNC_SHIFT 8 59 60struct ht_softc { 61 struct device sc_dev; 62 int sc_maxdevs; 63 struct ppc_bus_space sc_mem_bus_space; 64 struct ppc_bus_space sc_io_bus_space; 65 struct ppc_pci_chipset sc_pc; 66 bus_space_tag_t sc_memt; 67 bus_space_handle_t sc_config0_memh; 68 bus_space_handle_t sc_config1_memh; 69 bus_space_tag_t sc_iot; 70 bus_space_handle_t sc_config0_ioh; 71}; 72 73struct cfattach ht_ca = { 74 sizeof(struct ht_softc), ht_match, ht_attach 75}; 76 77struct cfdriver ht_cd = { 78 NULL, "ht", DV_DULL, 79}; 80 81#if 0 82struct powerpc_bus_dma_tag pci_bus_dma_tag = { 83 NULL, 84 _dmamap_create, 85 _dmamap_destroy, 86 _dmamap_load, 87 _dmamap_load_mbuf, 88 _dmamap_load_uio, 89 _dmamap_load_raw, 90 _dmamap_unload, 91 _dmamap_sync, 92 _dmamem_alloc, 93 _dmamem_free, 94 _dmamem_map, 95 _dmamem_unmap, 96 _dmamem_mmap 97}; 98#else 99extern struct powerpc_bus_dma_tag pci_bus_dma_tag; 100#endif 101 102int 103ht_match(struct device *parent, void *cf, void *aux) 104{ 105 struct confargs *ca = aux; 106 107 if (strcmp(ca->ca_name, "ht") == 0) 108 return (1); 109 return (0); 110} 111 112void 113ht_attach(struct device *parent, struct device *self, void *aux) 114{ 115 struct ht_softc *sc = (struct ht_softc *)self; 116 struct confargs *ca = aux; 117 struct pcibus_attach_args pba; 118 u_int32_t regs[6]; 119 char compat[32]; 120 int node, nn; 121 int len; 122 123 if (ca->ca_node == 0) { 124 printf(": invalid node on ht config\n"); 125 return; 126 } 127 128 len = OF_getprop(ca->ca_node, "reg", regs, sizeof(regs)); 129 if (len < sizeof(regs)) { 130 printf(": regs lookup failed, node %x\n", ca->ca_node); 131 return; 132 } 133 134 sc->sc_mem_bus_space.bus_base = 0x80000000; 135 sc->sc_mem_bus_space.bus_size = 0; 136 sc->sc_mem_bus_space.bus_io = 0; 137 sc->sc_memt = &sc->sc_mem_bus_space; 138 139 sc->sc_io_bus_space.bus_base = 0x80000000; 140 sc->sc_io_bus_space.bus_size = 0; 141 sc->sc_io_bus_space.bus_io = 1; 142 sc->sc_iot = &sc->sc_io_bus_space; 143 144 sc->sc_maxdevs = 1; 145 for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) 146 sc->sc_maxdevs++; 147 148 if (bus_space_map(sc->sc_memt, regs[1], 149 (1 << DEVICE_SHIFT)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) { 150 printf(": can't map PCI config0 memory\n"); 151 return; 152 } 153 154 if (bus_space_map(sc->sc_memt, regs[1] + 0x01000000, 0x80000, 0, 155 &sc->sc_config1_memh)) { 156 printf(": can't map PCI config1 memory\n"); 157 return; 158 } 159 160 if (bus_space_map(sc->sc_iot, regs[4], 0x1000, 0, 161 &sc->sc_config0_ioh)) { 162 printf(": can't map PCI config0 io\n"); 163 return; 164 } 165 166 len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat)); 167 if (len <= 0) 168 printf(": unknown"); 169 else 170 printf(": %s", compat); 171 172 sc->sc_pc.pc_conf_v = sc; 173 sc->sc_pc.pc_attach_hook = ht_attach_hook; 174 sc->sc_pc.pc_bus_maxdevs = ht_bus_maxdevs; 175 sc->sc_pc.pc_make_tag = ht_make_tag; 176 sc->sc_pc.pc_decompose_tag = ht_decompose_tag; 177 sc->sc_pc.pc_conf_size = ht_conf_size; 178 sc->sc_pc.pc_conf_read = ht_conf_read; 179 sc->sc_pc.pc_conf_write = ht_conf_write; 180 181 sc->sc_pc.pc_intr_v = sc; 182 sc->sc_pc.pc_intr_map = ht_intr_map; 183 sc->sc_pc.pc_intr_string = ht_intr_string; 184 sc->sc_pc.pc_intr_line = ht_intr_line; 185 sc->sc_pc.pc_intr_establish = ht_intr_establish; 186 sc->sc_pc.pc_intr_disestablish = ht_intr_disestablish; 187 sc->sc_pc.pc_ether_hw_addr = ht_ether_hw_addr; 188 189 bzero(&pba, sizeof(pba)); 190 pba.pba_busname = "pci"; 191 pba.pba_iot = sc->sc_iot; 192 pba.pba_memt = sc->sc_memt; 193 pba.pba_dmat = &pci_bus_dma_tag; 194 pba.pba_pc = &sc->sc_pc; 195 pba.pba_domain = pci_ndomains++; 196 pba.pba_bus = 0; 197 198 printf(", %d devices\n", sc->sc_maxdevs); 199 200 extern void fix_node_irq(int, struct pcibus_attach_args *); 201 202 for (node = OF_child(ca->ca_node); node; node = nn) { 203 fix_node_irq(node, &pba); 204 205 if ((nn = OF_child(node)) != 0) 206 continue; 207 208 while ((nn = OF_peer(node)) == 0) { 209 node = OF_parent(node); 210 if (node == ca->ca_node) { 211 nn = 0; 212 break; 213 } 214 } 215 } 216 217 config_found(self, &pba, ht_print); 218} 219 220void 221ht_attach_hook(struct device *parent, struct device *self, 222 struct pcibus_attach_args *pba) 223{ 224} 225 226int 227ht_bus_maxdevs(void *cpv, int bus) 228{ 229 struct ht_softc *sc = cpv; 230 231 /* XXX Probing more busses doesn't work. */ 232 if (bus == 0) 233 return sc->sc_maxdevs; 234 return 32; 235} 236 237pcitag_t 238ht_make_tag(void *cpv, int bus, int dev, int fnc) 239{ 240 return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT); 241} 242 243void 244ht_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp) 245{ 246 if (busp != NULL) 247 *busp = (tag >> BUS_SHIFT) & 0xff; 248 if (devp != NULL) 249 *devp = (tag >> DEVICE_SHIFT) & 0x1f; 250 if (fncp != NULL) 251 *fncp = (tag >> FNC_SHIFT) & 0x7; 252} 253 254int 255ht_conf_size(void *cpv, pcitag_t tag) 256{ 257 return PCI_CONFIG_SPACE_SIZE; 258} 259 260pcireg_t 261ht_conf_read(void *cpv, pcitag_t tag, int offset) 262{ 263 struct ht_softc *sc = cpv; 264 int bus, dev, fcn; 265 pcireg_t reg; 266 267#ifdef DEBUG 268 printf("ht_conf_read: tag=%x, offset=%x\n", tag, offset); 269#endif 270 ht_decompose_tag(NULL, tag, &bus, &dev, &fcn); 271 if (bus == 0 && dev == 0) { 272 tag |= (offset << 2); 273 reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); 274 reg = letoh32(reg); 275 } else if (bus == 0) { 276 /* XXX Why can we only access function 0? */ 277 if (fcn > 0) 278 return ~0; 279 tag |= offset; 280 reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); 281 } else { 282 tag |= offset; 283 reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); 284 } 285#ifdef DEBUG 286 printf("ht_conf_read: reg=%x\n", reg); 287#endif 288 return reg; 289} 290 291void 292ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) 293{ 294 struct ht_softc *sc = cpv; 295 int bus, dev, fcn; 296 297#ifdef DEBUG 298 printf("ht_conf_write: tag=%x, offset=%x, data = %x\n", 299 tag, offset, data); 300#endif 301 ht_decompose_tag(NULL, tag, &bus, &dev, &fcn); 302 if (bus == 0 && dev == 0) { 303 tag |= (offset << 2); 304 data = htole32(data); 305 bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, tag, data); 306 bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); 307 } else if (bus == 0) { 308 /* XXX Why can we only access function 0? */ 309 if (fcn > 0) 310 return; 311 tag |= offset; 312 bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, tag, data); 313 bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); 314 } else { 315 tag |= offset; 316 bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, tag, data); 317 bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); 318 } 319} 320 321/* XXX */ 322#define PCI_INTERRUPT_NO_CONNECTION 0xff 323 324int 325ht_intr_map(void *cpv, pcitag_t tag, int pin, int line, 326 pci_intr_handle_t *ihp) 327{ 328 int error = 0; 329 330#ifdef DEBUG 331 printf("ht_intr_map: tag=%x, pin=%d, line=%d\n", tag, pin, line); 332#endif 333 334 *ihp = -1; 335 if (line == PCI_INTERRUPT_NO_CONNECTION) 336 error = 1; /* No IRQ used. */ 337 else if (pin > PCI_INTERRUPT_PIN_MAX) { 338 printf("ht_intr_map: bad interrupt pin %d\n", pin); 339 error = 1; 340 } 341 342 if (!error) 343 *ihp = line; 344 return error; 345} 346 347const char * 348ht_intr_string(void *cpv, pci_intr_handle_t ih) 349{ 350 static char str[16]; 351 352 snprintf(str, sizeof str, "irq %ld", ih); 353 return (str); 354} 355 356int 357ht_intr_line(void *cpv, pci_intr_handle_t ih) 358{ 359 return (ih); 360} 361 362void * 363ht_intr_establish(void *cpv, pci_intr_handle_t ih, int level, 364 int (*func)(void *), void *arg, const char *name) 365{ 366 return (*intr_establish_func)(cpv, ih, IST_LEVEL, level, func, arg, 367 name); 368} 369 370void 371ht_intr_disestablish(void *lcv, void *cookie) 372{ 373} 374 375int 376ht_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr) 377{ 378 u_int8_t laddr[6]; 379 int node; 380 int len; 381 382 node = OF_finddevice("enet"); 383 len = OF_getprop(node, "local-mac-address", laddr, sizeof(laddr)); 384 if (sizeof(laddr) == len) { 385 memcpy(oaddr, laddr, sizeof(laddr)); 386 return 1; 387 } 388 389 oaddr[0] = oaddr[1] = oaddr[2] = 0xff; 390 oaddr[3] = oaddr[4] = oaddr[5] = 0xff; 391 return 0; 392} 393 394int 395ht_print(void *aux, const char *pnp) 396{ 397 struct pcibus_attach_args *pba = aux; 398 399 if (pnp) 400 printf("%s at %s", pba->pba_busname, pnp); 401 printf(" bus %d", pba->pba_bus); 402 return (UNCONF); 403} 404