1 /* $OpenBSD: octeon_pcibus.c,v 1.20 2018/06/13 14:38:42 visa Exp $ */ 2 /* $NetBSD: bonito_mainbus.c,v 1.11 2008/04/28 20:23:10 martin Exp $ */ 3 /* $NetBSD: bonito_pci.c,v 1.5 2008/04/28 20:23:28 martin Exp $ */ 4 5 /* 6 * Copyright (c) 2009, 2010 Miodrag Vallat. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 /*- 21 * Copyright (c) 2001 The NetBSD Foundation, Inc. 22 * All rights reserved. 23 * 24 * This code is derived from software contributed to The NetBSD Foundation 25 * by Jason R. Thorpe. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 37 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 38 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 41 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 42 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 43 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 44 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 46 * POSSIBILITY OF SUCH DAMAGE. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/device.h> 52 #include <sys/extent.h> 53 #include <sys/malloc.h> 54 55 #include <machine/autoconf.h> 56 #include <machine/bus.h> 57 #include <machine/intr.h> 58 #include <machine/octeonvar.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 #ifdef DEBUG 72 #define OCTEON_PCIDEBUG(p) printf p 73 #else 74 #define OCTEON_PCIDEBUG(p) 75 #endif 76 77 #define REG_READ32(addr) (*(volatile uint32_t *)(addr)) 78 #define REG_WRITE32(addr, data) (*(volatile uint32_t *)(addr) = (uint32_t)(data)) 79 80 int octeon_pcibus_match(struct device *, void *, void *); 81 void octeon_pcibus_attach(struct device *, struct device *, void *); 82 int octeon_pcibus_intr_map(int dev, int fn, int pin); 83 84 const struct cfattach pcibus_ca = { 85 sizeof(struct octeon_pcibus_softc), 86 octeon_pcibus_match, octeon_pcibus_attach 87 }; 88 89 struct cfdriver pcibus_cd = { 90 NULL, "pcibus", DV_DULL 91 }; 92 93 bus_addr_t octeon_pcibus_pa_to_device(paddr_t); 94 paddr_t octeon_pcibus_device_to_pa(bus_addr_t); 95 void octeon_pcibus_attach_hook(struct device *, struct device *, 96 struct pcibus_attach_args *); 97 int octeon_pcibus_bus_maxdevs(void *, int); 98 pcitag_t octeon_pcibus_make_tag(void *, int, int, int); 99 void octeon_pcibus_decompose_tag(void *, pcitag_t, int *, int *, int *); 100 int octeon_pcibus_pci_conf_size(void *, pcitag_t); 101 pcireg_t octeon_pcibus_pci_conf_read(void *, pcitag_t, int); 102 void octeon_pcibus_pci_conf_write(void *, pcitag_t, int, pcireg_t); 103 int octeon_pcibus_pci_intr_map(struct pci_attach_args *, 104 pci_intr_handle_t *); 105 const char *octeon_pcibus_pci_intr_string(void *, pci_intr_handle_t); 106 void *octeon_pcibus_pci_intr_establish(void *, pci_intr_handle_t, int, 107 int (*)(void *), void *, char *); 108 void octeon_pcibus_pci_intr_disestablish(void *, void *); 109 110 111 struct machine_bus_dma_tag octeon_pcibus_bus_dma_tag = { 112 ._cookie = NULL, 113 ._dmamap_create = _dmamap_create, 114 ._dmamap_destroy = _dmamap_destroy, 115 ._dmamap_load = _dmamap_load, 116 ._dmamap_load_mbuf = _dmamap_load_mbuf, 117 ._dmamap_load_uio = _dmamap_load_uio, 118 ._dmamap_load_raw = _dmamap_load_raw, 119 ._dmamap_load_buffer = _dmamap_load_buffer, 120 ._dmamap_unload = _dmamap_unload, 121 ._dmamap_sync = _dmamap_sync, 122 ._dmamem_alloc = _dmamem_alloc, 123 ._dmamem_free = _dmamem_free, 124 ._dmamem_map = _dmamem_map, 125 ._dmamem_unmap = _dmamem_unmap, 126 ._dmamem_mmap = _dmamem_mmap, 127 ._pa_to_device = octeon_pcibus_pa_to_device, 128 ._device_to_pa = octeon_pcibus_device_to_pa 129 }; 130 131 int octeon_pcibus_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 132 bus_space_handle_t *); 133 int octeon_pcibus_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 134 bus_space_handle_t *); 135 136 #define _OCTEON_PCIBUS_PCIIO_BASE 0x00001000 137 #define _OCTEON_PCIBUS_PCIIO_SIZE 0x08000000 138 #define _OCTEON_PCIBUS_PCIMEM_BASE 0x80000000 139 #define _OCTEON_PCIBUS_PCIMEM_SIZE 0x40000000 140 141 struct mips_bus_space octeon_pcibus_pci_io_space_tag = { 142 .bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIIO_BASE, CCA_NC), 143 .bus_private = NULL, 144 ._space_read_1 = generic_space_read_1, 145 ._space_write_1 = generic_space_write_1, 146 ._space_read_2 = generic_space_read_2, 147 ._space_write_2 = generic_space_write_2, 148 ._space_read_4 = generic_space_read_4, 149 ._space_write_4 = generic_space_write_4, 150 ._space_read_8 = generic_space_read_8, 151 ._space_write_8 = generic_space_write_8, 152 ._space_read_raw_2 = generic_space_read_raw_2, 153 ._space_write_raw_2 = generic_space_write_raw_2, 154 ._space_read_raw_4 = generic_space_read_raw_4, 155 ._space_write_raw_4 = generic_space_write_raw_4, 156 ._space_read_raw_8 = generic_space_read_raw_8, 157 ._space_write_raw_8 = generic_space_write_raw_8, 158 ._space_map = octeon_pcibus_io_map, 159 ._space_unmap = generic_space_unmap, 160 ._space_subregion = generic_space_region, 161 ._space_vaddr = generic_space_vaddr 162 }; 163 164 struct mips_bus_space octeon_pcibus_pci_mem_space_tag = { 165 .bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIMEM_BASE, CCA_NC), 166 .bus_private = NULL, 167 ._space_read_1 = generic_space_read_1, 168 ._space_write_1 = generic_space_write_1, 169 ._space_read_2 = generic_space_read_2, 170 ._space_write_2 = generic_space_write_2, 171 ._space_read_4 = generic_space_read_4, 172 ._space_write_4 = generic_space_write_4, 173 ._space_read_8 = generic_space_read_8, 174 ._space_write_8 = generic_space_write_8, 175 ._space_read_raw_2 = generic_space_read_raw_2, 176 ._space_write_raw_2 = generic_space_write_raw_2, 177 ._space_read_raw_4 = generic_space_read_raw_4, 178 ._space_write_raw_4 = generic_space_write_raw_4, 179 ._space_read_raw_8 = generic_space_read_raw_8, 180 ._space_write_raw_8 = generic_space_write_raw_8, 181 ._space_map = octeon_pcibus_mem_map, 182 ._space_unmap = generic_space_unmap, 183 ._space_subregion = generic_space_region, 184 ._space_vaddr = generic_space_vaddr 185 }; 186 187 int 188 octeon_pcibus_match(struct device *parent, void *vcf, void *aux) 189 { 190 struct iobus_attach_args *aa = aux; 191 192 if ((octeon_boot_info->config_flags & BOOTINFO_CFG_FLAG_PCI_HOST) == 0) { 193 OCTEON_PCIDEBUG(("%s, no PCI host function detected.\n", __func__)); 194 return 0; 195 } 196 197 if (strcmp(aa->aa_name, pcibus_cd.cd_name) == 0) 198 return 1; 199 200 return 0; 201 } 202 203 void 204 octeon_pcibus_attach(struct device *parent, struct device *self, void *aux) 205 { 206 struct octeon_pcibus_softc *sc; 207 struct pcibus_attach_args pba; 208 209 sc = (struct octeon_pcibus_softc *)self; 210 sc->sc_aa = aux; 211 212 printf("\n"); 213 214 /* 215 * Attach PCI bus. 216 */ 217 sc->sc_pc.pc_attach_hook = octeon_pcibus_attach_hook; 218 sc->sc_pc.pc_bus_maxdevs = octeon_pcibus_bus_maxdevs; 219 sc->sc_pc.pc_make_tag = octeon_pcibus_make_tag; 220 sc->sc_pc.pc_decompose_tag = octeon_pcibus_decompose_tag; 221 222 sc->sc_pc.pc_conf_v = sc; 223 sc->sc_pc.pc_conf_size = octeon_pcibus_pci_conf_size; 224 sc->sc_pc.pc_conf_read = octeon_pcibus_pci_conf_read; 225 sc->sc_pc.pc_conf_write = octeon_pcibus_pci_conf_write; 226 227 sc->sc_pc.pc_intr_v = sc; 228 sc->sc_pc.pc_intr_map = octeon_pcibus_pci_intr_map; 229 sc->sc_pc.pc_intr_string = octeon_pcibus_pci_intr_string; 230 sc->sc_pc.pc_intr_establish = octeon_pcibus_pci_intr_establish; 231 sc->sc_pc.pc_intr_disestablish = octeon_pcibus_pci_intr_disestablish; 232 233 bzero(&pba, sizeof pba); 234 pba.pba_busname = "pci"; 235 pba.pba_iot = &octeon_pcibus_pci_io_space_tag; 236 pba.pba_memt = &octeon_pcibus_pci_mem_space_tag; 237 pba.pba_dmat = &octeon_pcibus_bus_dma_tag; 238 pba.pba_pc = &sc->sc_pc; 239 pba.pba_domain = pci_ndomains++; 240 pba.pba_bus = 0; 241 pba.pba_ioex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 1); 242 pba.pba_memex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 0); 243 244 config_found(&sc->sc_dev, &pba, octeon_pcibus_print); 245 } 246 247 bus_addr_t 248 octeon_pcibus_pa_to_device(paddr_t pa) 249 { 250 OCTEON_PCIDEBUG(("%s:%d: pa=%p\n", __func__, __LINE__, (void *)pa)); 251 252 return pa & 0x1ffffffffffffUL; 253 } 254 255 paddr_t 256 octeon_pcibus_device_to_pa(bus_addr_t addr) 257 { 258 OCTEON_PCIDEBUG(("%s:%d: addr=%lx\n", __func__, __LINE__, addr)); 259 260 return PHYS_TO_XKPHYS(addr, CCA_NC); 261 } 262 263 int 264 octeon_pcibus_print(void *aux, const char *pnp) 265 { 266 struct pcibus_attach_args *pba = aux; 267 268 if (pnp) 269 printf("%s at %s", pba->pba_busname, pnp); 270 printf(" bus %d", pba->pba_bus); 271 272 return UNCONF; 273 } 274 275 /* 276 * various PCI helpers 277 */ 278 void 279 octeon_pcibus_attach_hook(struct device *parent, struct device *self, 280 struct pcibus_attach_args *pba) 281 { 282 } 283 284 /* 285 * PCI configuration space access routines 286 */ 287 int 288 octeon_pcibus_bus_maxdevs(void *v, int busno) 289 { 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 %ld", 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 470 exnamesz = 1 + 16 + 4; 471 exname = malloc(exnamesz, M_DEVBUF, M_NOWAIT); 472 if (exname == NULL) 473 return NULL; 474 snprintf(exname, exnamesz, "%s%s", sc->sc_dev.dv_xname, 475 io ? "_io" : "_mem"); 476 477 ex = extent_create(exname, 0, 0xffffffffffffffff, M_DEVBUF, NULL, 0, 478 EX_NOWAIT | EX_FILLED); 479 if (ex == NULL) 480 goto error; 481 482 if (io) { 483 if (extent_free(ex, _OCTEON_PCIBUS_PCIIO_BASE, 484 _OCTEON_PCIBUS_PCIIO_SIZE, EX_NOWAIT) != 0) 485 goto error; 486 } else { 487 if (extent_free(ex, _OCTEON_PCIBUS_PCIMEM_BASE, 488 _OCTEON_PCIBUS_PCIMEM_SIZE, EX_NOWAIT) != 0) 489 goto error; 490 } 491 492 #if defined(DEBUG) && defined(DIAGNOSTIC) 493 extent_print(ex); 494 #endif 495 return ex; 496 497 error: 498 if (ex != NULL) 499 extent_destroy(ex); 500 free(exname, M_DEVBUF, exnamesz); 501 return NULL; 502 } 503 504 /* 505 * PCI model specific routines 506 */ 507 508 int 509 octeon_pcibus_intr_map(int dev, int fn, int pin) 510 { 511 return CIU_INT_PCI_INTA + ((pin - 1) & 3); 512 } 513