1 /* $OpenBSD: octeon_pcibus.c,v 1.6 2011/05/08 13:24:55 syuu Exp $ */ 2 /* $OpenBSD: octeon_pcibus.c,v 1.6 2011/05/08 13:24:55 syuu Exp $ */ 3 /* $NetBSD: bonito_mainbus.c,v 1.11 2008/04/28 20:23:10 martin Exp $ */ 4 /* $NetBSD: bonito_pci.c,v 1.5 2008/04/28 20:23:28 martin Exp $ */ 5 6 /* 7 * Copyright (c) 2009, 2010 Miodrag Vallat. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 /*- 22 * Copyright (c) 2001 The NetBSD Foundation, Inc. 23 * All rights reserved. 24 * 25 * This code is derived from software contributed to The NetBSD Foundation 26 * by Jason R. Thorpe. 27 * 28 * Redistribution and use in source and binary forms, with or without 29 * modification, are permitted provided that the following conditions 30 * are met: 31 * 1. Redistributions of source code must retain the above copyright 32 * notice, this list of conditions and the following disclaimer. 33 * 2. Redistributions in binary form must reproduce the above copyright 34 * notice, this list of conditions and the following disclaimer in the 35 * documentation and/or other materials provided with the distribution. 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 38 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 39 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 40 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 41 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 42 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 43 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 44 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 45 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 47 * POSSIBILITY OF SUCH DAMAGE. 48 */ 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/device.h> 53 #include <sys/extent.h> 54 #include <sys/malloc.h> 55 56 #include <machine/autoconf.h> 57 #include <machine/bus.h> 58 #include <machine/intr.h> 59 60 #include <dev/pci/pcidevs.h> 61 #include <dev/pci/pcireg.h> 62 #include <dev/pci/pcivar.h> 63 #include <dev/pci/ppbreg.h> 64 65 #include <octeon/dev/iobusvar.h> 66 #include <octeon/dev/octeon_pcibus.h> 67 #include <octeon/dev/octeon_pcibusvar.h> 68 69 #include <uvm/uvm_extern.h> 70 71 #if 1 72 #define OCTEON_PCIBUS_DEBUG 73 #endif 74 75 #ifdef OCTEON_PCIBUS_DEBUG 76 #define DEBUG_PRINT(p) printf p 77 #else 78 #define DEBUG_PRINT(p) 79 #endif 80 81 #define REG_READ32(addr) (*(volatile uint32_t *)(addr)) 82 #define REG_WRITE32(addr, data) (*(volatile uint32_t *)(addr) = (uint32_t)(data)) 83 84 int octeon_pcibus_match(struct device *, void *, void *); 85 void octeon_pcibus_attach(struct device *, struct device *, void *); 86 int octeon_pcibus_intr_map(int dev, int fn, int pin); 87 88 const struct cfattach pcibus_ca = { 89 sizeof(struct octeon_pcibus_softc), 90 octeon_pcibus_match, octeon_pcibus_attach 91 }; 92 93 struct cfdriver pcibus_cd = { 94 NULL, "pcibus", DV_DULL 95 }; 96 97 bus_addr_t octeon_pcibus_pa_to_device(paddr_t); 98 paddr_t octeon_pcibus_device_to_pa(bus_addr_t); 99 void octeon_pcibus_attach_hook(struct device *, struct device *, 100 struct pcibus_attach_args *); 101 int octeon_pcibus_bus_maxdevs(void *, int); 102 pcitag_t octeon_pcibus_make_tag(void *, int, int, int); 103 void octeon_pcibus_decompose_tag(void *, pcitag_t, int *, int *, int *); 104 int octeon_pcibus_pci_conf_size(void *, pcitag_t); 105 pcireg_t octeon_pcibus_pci_conf_read(void *, pcitag_t, int); 106 void octeon_pcibus_pci_conf_write(void *, pcitag_t, int, pcireg_t); 107 int octeon_pcibus_pci_intr_map(struct pci_attach_args *, 108 pci_intr_handle_t *); 109 const char *octeon_pcibus_pci_intr_string(void *, pci_intr_handle_t); 110 void *octeon_pcibus_pci_intr_establish(void *, pci_intr_handle_t, int, 111 int (*)(void *), void *, char *); 112 void octeon_pcibus_pci_intr_disestablish(void *, void *); 113 114 115 struct machine_bus_dma_tag octeon_pcibus_bus_dma_tag = { 116 ._cookie = NULL, 117 ._dmamap_create = _dmamap_create, 118 ._dmamap_destroy = _dmamap_destroy, 119 ._dmamap_load = _dmamap_load, 120 ._dmamap_load_mbuf = _dmamap_load_mbuf, 121 ._dmamap_load_uio = _dmamap_load_uio, 122 ._dmamap_load_raw = _dmamap_load_raw, 123 ._dmamap_load_buffer = _dmamap_load_buffer, 124 ._dmamap_unload = _dmamap_unload, 125 ._dmamap_sync = _dmamap_sync, 126 ._dmamem_alloc = _dmamem_alloc, 127 ._dmamem_free = _dmamem_free, 128 ._dmamem_map = _dmamem_map, 129 ._dmamem_unmap = _dmamem_unmap, 130 ._dmamem_mmap = _dmamem_mmap, 131 ._pa_to_device = octeon_pcibus_pa_to_device, 132 ._device_to_pa = octeon_pcibus_device_to_pa 133 }; 134 135 int octeon_pcibus_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 136 bus_space_handle_t *); 137 int octeon_pcibus_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 138 bus_space_handle_t *); 139 140 #define _OCTEON_PCIBUS_PCIIO_BASE 0x00001000 141 #define _OCTEON_PCIBUS_PCIIO_SIZE 0x08000000 142 #define _OCTEON_PCIBUS_PCIMEM_BASE 0x80000000 143 #define _OCTEON_PCIBUS_PCIMEM_SIZE 0x40000000 144 145 struct mips_bus_space octeon_pcibus_pci_io_space_tag = { 146 .bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIIO_BASE, CCA_NC), 147 .bus_private = NULL, 148 ._space_read_1 = generic_space_read_1, 149 ._space_write_1 = generic_space_write_1, 150 ._space_read_2 = generic_space_read_2, 151 ._space_write_2 = generic_space_write_2, 152 ._space_read_4 = generic_space_read_4, 153 ._space_write_4 = generic_space_write_4, 154 ._space_read_8 = generic_space_read_8, 155 ._space_write_8 = generic_space_write_8, 156 ._space_read_raw_2 = generic_space_read_raw_2, 157 ._space_write_raw_2 = generic_space_write_raw_2, 158 ._space_read_raw_4 = generic_space_read_raw_4, 159 ._space_write_raw_4 = generic_space_write_raw_4, 160 ._space_read_raw_8 = generic_space_read_raw_8, 161 ._space_write_raw_8 = generic_space_write_raw_8, 162 ._space_map = octeon_pcibus_io_map, 163 ._space_unmap = generic_space_unmap, 164 ._space_subregion = generic_space_region, 165 ._space_vaddr = generic_space_vaddr 166 }; 167 168 struct mips_bus_space octeon_pcibus_pci_mem_space_tag = { 169 .bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIMEM_BASE, CCA_NC), 170 .bus_private = NULL, 171 ._space_read_1 = generic_space_read_1, 172 ._space_write_1 = generic_space_write_1, 173 ._space_read_2 = generic_space_read_2, 174 ._space_write_2 = generic_space_write_2, 175 ._space_read_4 = generic_space_read_4, 176 ._space_write_4 = generic_space_write_4, 177 ._space_read_8 = generic_space_read_8, 178 ._space_write_8 = generic_space_write_8, 179 ._space_read_raw_2 = generic_space_read_raw_2, 180 ._space_write_raw_2 = generic_space_write_raw_2, 181 ._space_read_raw_4 = generic_space_read_raw_4, 182 ._space_write_raw_4 = generic_space_write_raw_4, 183 ._space_read_raw_8 = generic_space_read_raw_8, 184 ._space_write_raw_8 = generic_space_write_raw_8, 185 ._space_map = octeon_pcibus_mem_map, 186 ._space_unmap = generic_space_unmap, 187 ._space_subregion = generic_space_region, 188 ._space_vaddr = generic_space_vaddr 189 }; 190 191 int 192 octeon_pcibus_match(struct device *parent, void *vcf, void *aux) 193 { 194 struct iobus_attach_args *aa = aux; 195 196 if (strcmp(aa->aa_name, pcibus_cd.cd_name) == 0) 197 return 1; 198 199 return 0; 200 } 201 202 void 203 octeon_pcibus_attach(struct device *parent, struct device *self, void *aux) 204 { 205 struct octeon_pcibus_softc *sc; 206 struct iobus_attach_args *aa; 207 struct pcibus_attach_args pba; 208 209 sc = (struct octeon_pcibus_softc *)self; 210 aa = aux; 211 sc->sc_aa = aa; 212 213 /* 214 * Attach PCI bus. 215 */ 216 sc->sc_pc.pc_attach_hook = octeon_pcibus_attach_hook; 217 sc->sc_pc.pc_bus_maxdevs = octeon_pcibus_bus_maxdevs; 218 sc->sc_pc.pc_make_tag = octeon_pcibus_make_tag; 219 sc->sc_pc.pc_decompose_tag = octeon_pcibus_decompose_tag; 220 221 sc->sc_pc.pc_conf_v = sc; 222 sc->sc_pc.pc_conf_size = octeon_pcibus_pci_conf_size; 223 sc->sc_pc.pc_conf_read = octeon_pcibus_pci_conf_read; 224 sc->sc_pc.pc_conf_write = octeon_pcibus_pci_conf_write; 225 226 sc->sc_pc.pc_intr_v = sc; 227 sc->sc_pc.pc_intr_map = octeon_pcibus_pci_intr_map; 228 sc->sc_pc.pc_intr_string = octeon_pcibus_pci_intr_string; 229 sc->sc_pc.pc_intr_establish = octeon_pcibus_pci_intr_establish; 230 sc->sc_pc.pc_intr_disestablish = octeon_pcibus_pci_intr_disestablish; 231 232 bzero(&pba, sizeof pba); 233 pba.pba_busname = "pci"; 234 pba.pba_iot = &octeon_pcibus_pci_io_space_tag; 235 pba.pba_memt = &octeon_pcibus_pci_mem_space_tag; 236 pba.pba_dmat = &octeon_pcibus_bus_dma_tag; 237 pba.pba_pc = &sc->sc_pc; 238 pba.pba_domain = pci_ndomains++; 239 pba.pba_bus = 0; 240 pba.pba_ioex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 1); 241 pba.pba_memex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 0); 242 243 config_found(&sc->sc_dev, &pba, octeon_pcibus_print); 244 } 245 246 bus_addr_t 247 octeon_pcibus_pa_to_device(paddr_t pa) 248 { 249 printf("%s:%d: pa=%p\n", __func__, __LINE__, pa); 250 251 return pa & 0x1ffffffffffffUL; 252 } 253 254 paddr_t 255 octeon_pcibus_device_to_pa(bus_addr_t addr) 256 { 257 printf("%s:%d: addr=%p\n", __func__, __LINE__, addr); 258 259 return PHYS_TO_XKPHYS(addr, CCA_NC); 260 } 261 262 int 263 octeon_pcibus_print(void *aux, const char *pnp) 264 { 265 struct pcibus_attach_args *pba = aux; 266 267 if (pnp) 268 printf("%s at %s", pba->pba_busname, pnp); 269 printf(" bus %d", pba->pba_bus); 270 271 return UNCONF; 272 } 273 274 /* 275 * various PCI helpers 276 */ 277 void 278 octeon_pcibus_attach_hook(struct device *parent, struct device *self, 279 struct pcibus_attach_args *pba) 280 { 281 } 282 283 /* 284 * PCI configuration space access routines 285 */ 286 int 287 octeon_pcibus_bus_maxdevs(void *v, int busno) 288 { 289 /* XXX */ 290 return 32; 291 } 292 293 pcitag_t 294 octeon_pcibus_make_tag(void *unused, int b, int d, int f) 295 { 296 return (b << 16) | (d << 11) | (f << 8); 297 } 298 299 void 300 octeon_pcibus_decompose_tag(void *unused, pcitag_t tag, int *bp, int *dp, int *fp) 301 { 302 if (bp != NULL) 303 *bp = (tag >> 16) & 0xff; 304 if (dp != NULL) 305 *dp = (tag >> 11) & 0x1f; 306 if (fp != NULL) 307 *fp = (tag >> 8) & 0x7; 308 } 309 310 int 311 octeon_pcibus_pci_conf_size(void *v, pcitag_t tag) 312 { 313 return PCI_CONFIG_SPACE_SIZE; 314 } 315 316 pcireg_t 317 octeon_pcibus_pci_conf_read(void *v, pcitag_t tag, int offset) 318 { 319 pcireg_t data; 320 uint64_t cfgoff; 321 322 if (tag == 0){ 323 if (offset & 0x4){ 324 cfgoff = OCTEON_PCI_CFG1 + (offset & 0xfff8); 325 } else { 326 cfgoff = OCTEON_PCI_CFG0 + (offset & 0xfff8); 327 } 328 } else { 329 cfgoff = tag + offset; 330 if (offset & 0x4) { 331 cfgoff = OCTEON_PCI_CONFIG_BASE1 + (cfgoff & 0xfffffff8); 332 } else { 333 cfgoff = OCTEON_PCI_CONFIG_BASE0 + (cfgoff & 0xfffffff8); 334 } 335 } 336 337 data = REG_READ32(cfgoff); 338 return data; 339 } 340 341 void 342 octeon_pcibus_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data) 343 { 344 uint64_t cfgoff; 345 346 if (tag == 0){ 347 if (offset & 0x4){ 348 cfgoff = OCTEON_PCI_CFG1 + (offset & 0xfff8); 349 } else { 350 cfgoff = OCTEON_PCI_CFG0 + (offset & 0xfff8); 351 } 352 } else { 353 cfgoff = tag + offset; 354 if (offset & 0x4){ 355 cfgoff = OCTEON_PCI_CONFIG_BASE1 + (cfgoff & 0xfffffff8); 356 } else { 357 cfgoff = OCTEON_PCI_CONFIG_BASE0 + (cfgoff & 0xfffffff8); 358 } 359 } 360 361 REG_WRITE32(cfgoff, data); 362 } 363 364 365 /* 366 * PCI Interrupt handling 367 */ 368 int 369 octeon_pcibus_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 370 { 371 #if 0 372 struct octeon_pcibus_softc *sc = pa->pa_pc->pc_intr_v; 373 #endif 374 int bus, dev, fn, pin; 375 376 *ihp = (pci_intr_handle_t)-1; 377 378 if (pa->pa_intrpin == 0) /* no interrupt needed */ 379 return 1; 380 381 #ifdef DIAGNOSTIC 382 if (pa->pa_intrpin > 4) { 383 printf("%s: bad interrupt pin %d\n", __func__, pa->pa_intrpin); 384 return 1; 385 } 386 #endif 387 388 pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &fn); 389 if (pa->pa_bridgetag) { 390 pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev); 391 *ihp = pa->pa_bridgeih[pin - 1]; 392 } else { 393 if (bus == 0) 394 *ihp = octeon_pcibus_intr_map(dev, fn, pa->pa_intrpin); 395 396 if (*ihp == (pci_intr_handle_t)-1) 397 return 1; 398 } 399 400 return 0; 401 } 402 403 const char * 404 octeon_pcibus_pci_intr_string(void *cookie, pci_intr_handle_t ih) 405 { 406 static char irqstr[sizeof("irq 0123456789")]; 407 408 snprintf(irqstr, sizeof irqstr, "irq %d", ih); 409 return irqstr; 410 } 411 412 void * 413 octeon_pcibus_pci_intr_establish(void *cookie, pci_intr_handle_t ih, int level, 414 int (*cb)(void *), void *cbarg, char *name) 415 { 416 return octeon_intr_establish(ih, level, cb, cbarg, name); 417 } 418 419 void 420 octeon_pcibus_pci_intr_disestablish(void *cookie, void *ihp) 421 { 422 struct octeon_pcibus_softc *sc; 423 struct iobus_attach_args *aa; 424 425 sc = (struct octeon_pcibus_softc *)cookie; 426 aa = sc->sc_aa; 427 428 // XXX: this cause panic... 429 // iobus_intr_disestablish(ihp); 430 } 431 432 /* 433 * bus_space mapping routines. 434 */ 435 int 436 octeon_pcibus_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, 437 bus_space_handle_t *bshp) 438 { 439 if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE)) { 440 offs += 441 PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC); 442 } 443 *bshp = t->bus_base + offs; 444 return 0; 445 } 446 447 int 448 octeon_pcibus_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, 449 bus_space_handle_t *bshp) 450 { 451 if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE)) { 452 offs += 453 PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC); 454 } 455 *bshp = t->bus_base + offs; 456 return 0; 457 } 458 459 /* 460 * PCI resource handling 461 */ 462 struct extent * 463 octeon_pcibus_get_resource_extent(pci_chipset_tag_t pc, int io) 464 { 465 struct octeon_pcibus_softc *sc = pc->pc_conf_v; 466 struct extent *ex; 467 char *exname; 468 int exnamesz; 469 int errors; 470 471 exnamesz = 1 + 16 + 4; 472 exname = (char *)malloc(exnamesz, M_DEVBUF, M_NOWAIT); 473 if (exname == NULL) 474 return NULL; 475 snprintf(exname, exnamesz, "%s%s", sc->sc_dev.dv_xname, 476 io ? "_io" : "_mem"); 477 478 ex = extent_create(exname, 0, 0xffffffffffffffff, M_DEVBUF, NULL, 0, 479 EX_NOWAIT | EX_FILLED); 480 if (ex == NULL) 481 goto out; 482 483 exname = NULL; 484 errors = 0; 485 if (io) { 486 if (extent_free(ex, _OCTEON_PCIBUS_PCIIO_BASE, _OCTEON_PCIBUS_PCIIO_SIZE, 487 EX_NOWAIT) != 0) 488 errors++; 489 } else { 490 if (extent_free(ex, _OCTEON_PCIBUS_PCIMEM_BASE, _OCTEON_PCIBUS_PCIMEM_SIZE, 491 EX_NOWAIT) != 0) 492 errors++; 493 } 494 495 if (errors != 0) { 496 extent_destroy(ex); 497 ex = NULL; 498 } 499 500 #ifdef OCTEON_PCIBUS_DEBUG 501 extent_print(ex); 502 #endif 503 504 out: 505 if (exname != NULL) 506 free(exname, M_DEVBUF); 507 508 return ex; 509 } 510 511 /* 512 * PCI model specific routines 513 */ 514 515 int 516 octeon_pcibus_intr_map(int dev, int fn, int pin) 517 { 518 return CIU_INT_PCI_INTA + ((pin - 1) & 3); 519 } 520