ht.c revision 1.7
1/* $OpenBSD: ht.c,v 1.7 2005/11/13 21:48:16 drahn 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 194 printf(": %d devices\n", sc->sc_maxdevs); 195 196 extern void fix_node_irq(int, struct pcibus_attach_args *); 197 198 for (node = OF_child(ca->ca_node); node; node = nn) { 199 fix_node_irq(node, &pba); 200 201 if ((nn = OF_child(node)) != 0) 202 continue; 203 204 while ((nn = OF_peer(node)) == 0) { 205 node = OF_parent(node); 206 if (node == ca->ca_node) { 207 nn = 0; 208 break; 209 } 210 } 211 } 212 213 config_found(self, &pba, ht_print); 214} 215 216void 217ht_attach_hook(struct device *parent, struct device *self, 218 struct pcibus_attach_args *pba) 219{ 220} 221 222int 223ht_bus_maxdevs(void *cpv, int bus) 224{ 225 struct ht_softc *sc = cpv; 226 227 /* XXX Probing more busses doesn't work. */ 228 if (bus == 0) 229 return sc->sc_maxdevs; 230 return 32; 231} 232 233pcitag_t 234ht_make_tag(void *cpv, int bus, int dev, int fnc) 235{ 236 return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT); 237} 238 239void 240ht_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp) 241{ 242 if (busp != NULL) 243 *busp = (tag >> BUS_SHIFT) & 0xff; 244 if (devp != NULL) 245 *devp = (tag >> DEVICE_SHIFT) & 0x1f; 246 if (fncp != NULL) 247 *fncp = (tag >> FNC_SHIFT) & 0x7; 248} 249 250pcireg_t 251ht_conf_read(void *cpv, pcitag_t tag, int offset) 252{ 253 struct ht_softc *sc = cpv; 254 int bus, dev, fcn; 255 pcireg_t reg; 256 257#ifdef DEBUG 258 printf("ht_conf_read: tag=%x, offset=%x\n", tag, offset); 259#endif 260 ht_decompose_tag(NULL, tag, &bus, &dev, &fcn); 261 if (bus == 0 && dev == 0) { 262 tag |= (offset << 2); 263 reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); 264 reg = letoh32(reg); 265 } else if (bus == 0) { 266 /* XXX Needed on some PowerMac G5's. Why? */ 267 if (fcn > 1) 268 return ~0; 269 tag |= offset; 270 reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); 271 } else { 272 tag |= offset; 273 reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); 274 } 275#ifdef DEBUG 276 printf("ht_conf_read: reg=%x\n", reg); 277#endif 278 return reg; 279} 280 281void 282ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) 283{ 284 struct ht_softc *sc = cpv; 285 int bus, dev; 286 287#ifdef DEBUG 288 printf("ht_conf_write: tag=%x, offset=%x, data = %x\n", 289 tag, offset, data); 290#endif 291 ht_decompose_tag(NULL, tag, &bus, &dev, NULL); 292 if (bus == 0 && dev == 0) { 293 tag |= (offset << 2); 294 data = htole32(data); 295 bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, tag, data); 296 bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, tag); 297 } else if (bus == 0) { 298 tag |= offset; 299 bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, tag, data); 300 bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, tag); 301 } else { 302 tag |= offset; 303 bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, tag, data); 304 bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, tag); 305 } 306} 307 308/* XXX */ 309#define PCI_INTERRUPT_NO_CONNECTION 0xff 310 311int 312ht_intr_map(void *cpv, pcitag_t tag, int pin, int line, 313 pci_intr_handle_t *ihp) 314{ 315 int error = 0; 316 317#ifdef DEBUG 318 printf("ht_intr_map: tag=%x, pin=%d, line=%d\n", tag, pin, line); 319#endif 320 321 *ihp = -1; 322 if (line == PCI_INTERRUPT_NO_CONNECTION) 323 error = 1; /* No IRQ used. */ 324 else if (pin > PCI_INTERRUPT_PIN_MAX) { 325 printf("ht_intr_map: bad interrupt pin %d\n", pin); 326 error = 1; 327 } 328 329 if (!error) 330 *ihp = line; 331 return error; 332} 333 334const char * 335ht_intr_string(void *cpv, pci_intr_handle_t ih) 336{ 337 static char str[16]; 338 339 snprintf(str, sizeof str, "irq %ld", ih); 340 return (str); 341} 342 343int 344ht_intr_line(void *cpv, pci_intr_handle_t ih) 345{ 346 return (ih); 347} 348 349void * 350ht_intr_establish(void *cpv, pci_intr_handle_t ih, int level, 351 int (*func)(void *), void *arg, char *name) 352{ 353 return (*intr_establish_func)(cpv, ih, IST_LEVEL, level, func, arg, 354 name); 355} 356 357void 358ht_intr_disestablish(void *lcv, void *cookie) 359{ 360} 361 362int 363ht_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr) 364{ 365 u_int8_t laddr[6]; 366 int node; 367 int len; 368 369 node = OF_finddevice("enet"); 370 len = OF_getprop(node, "local-mac-address", laddr, sizeof(laddr)); 371 if (sizeof(laddr) == len) { 372 memcpy(oaddr, laddr, sizeof(laddr)); 373 return 1; 374 } 375 376 oaddr[0] = oaddr[1] = oaddr[2] = 0xff; 377 oaddr[3] = oaddr[4] = oaddr[5] = 0xff; 378 return 0; 379} 380 381int 382ht_print(void *aux, const char *pnp) 383{ 384 struct pcibus_attach_args *pba = aux; 385 386 if (pnp) 387 printf("%s at %s", pba->pba_busname, pnp); 388 printf(" bus %d", pba->pba_bus); 389 return (UNCONF); 390} 391