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