1 /* $OpenBSD: octeon_pcibus.c,v 1.23 2021/03/04 16:44:07 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 68 #include <uvm/uvm_extern.h> 69 70 #ifdef DEBUG 71 #define OCTEON_PCIDEBUG(p) printf p 72 #else 73 #define OCTEON_PCIDEBUG(p) 74 #endif 75 76 #define REG_READ32(addr) (*(volatile uint32_t *)(addr)) 77 #define REG_WRITE32(addr, data) (*(volatile uint32_t *)(addr) = (uint32_t)(data)) 78 79 struct octeon_pcibus_softc { 80 struct device sc_dev; 81 struct mips_pci_chipset sc_pc; 82 struct iobus_attach_args *sc_aa; 83 }; 84 85 int octeon_pcibus_match(struct device *, void *, void *); 86 void octeon_pcibus_attach(struct device *, struct device *, void *); 87 int octeon_pcibus_print(void *, const char *); 88 89 const struct cfattach pcibus_ca = { 90 sizeof(struct octeon_pcibus_softc), 91 octeon_pcibus_match, octeon_pcibus_attach 92 }; 93 94 struct cfdriver pcibus_cd = { 95 NULL, "pcibus", DV_DULL 96 }; 97 98 bus_addr_t octeon_pcibus_pa_to_device(paddr_t); 99 paddr_t octeon_pcibus_device_to_pa(bus_addr_t); 100 void octeon_pcibus_attach_hook(struct device *, struct device *, 101 struct pcibus_attach_args *); 102 int octeon_pcibus_bus_maxdevs(void *, int); 103 pcitag_t octeon_pcibus_make_tag(void *, int, int, int); 104 void octeon_pcibus_decompose_tag(void *, pcitag_t, int *, int *, int *); 105 int octeon_pcibus_pci_conf_size(void *, pcitag_t); 106 pcireg_t octeon_pcibus_pci_conf_read(void *, pcitag_t, int); 107 void octeon_pcibus_pci_conf_write(void *, pcitag_t, int, pcireg_t); 108 int octeon_pcibus_pci_intr_map(struct pci_attach_args *, 109 pci_intr_handle_t *); 110 const char *octeon_pcibus_pci_intr_string(void *, pci_intr_handle_t); 111 void *octeon_pcibus_pci_intr_establish(void *, pci_intr_handle_t, int, 112 int (*)(void *), void *, char *); 113 void octeon_pcibus_pci_intr_disestablish(void *, void *); 114 int octeon_pcibus_intr_map(int dev, int fn, int pin); 115 int octeon_pcibus_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 116 bus_space_handle_t *); 117 int octeon_pcibus_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 118 bus_space_handle_t *); 119 struct extent *octeon_pcibus_get_resource_extent(pci_chipset_tag_t, int); 120 121 struct machine_bus_dma_tag octeon_pcibus_bus_dma_tag = { 122 ._cookie = NULL, 123 ._dmamap_create = _dmamap_create, 124 ._dmamap_destroy = _dmamap_destroy, 125 ._dmamap_load = _dmamap_load, 126 ._dmamap_load_mbuf = _dmamap_load_mbuf, 127 ._dmamap_load_uio = _dmamap_load_uio, 128 ._dmamap_load_raw = _dmamap_load_raw, 129 ._dmamap_load_buffer = _dmamap_load_buffer, 130 ._dmamap_unload = _dmamap_unload, 131 ._dmamap_sync = _dmamap_sync, 132 ._dmamem_alloc = _dmamem_alloc, 133 ._dmamem_free = _dmamem_free, 134 ._dmamem_map = _dmamem_map, 135 ._dmamem_unmap = _dmamem_unmap, 136 ._dmamem_mmap = _dmamem_mmap, 137 ._pa_to_device = octeon_pcibus_pa_to_device, 138 ._device_to_pa = octeon_pcibus_device_to_pa 139 }; 140 141 #define _OCTEON_PCIBUS_PCIIO_BASE 0x00001000 142 #define _OCTEON_PCIBUS_PCIIO_SIZE 0x08000000 143 #define _OCTEON_PCIBUS_PCIMEM_BASE 0x80000000 144 #define _OCTEON_PCIBUS_PCIMEM_SIZE 0x40000000 145 146 struct mips_bus_space octeon_pcibus_pci_io_space_tag = { 147 .bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIIO_BASE, CCA_NC), 148 .bus_private = NULL, 149 ._space_read_1 = generic_space_read_1, 150 ._space_write_1 = generic_space_write_1, 151 ._space_read_2 = generic_space_read_2, 152 ._space_write_2 = generic_space_write_2, 153 ._space_read_4 = generic_space_read_4, 154 ._space_write_4 = generic_space_write_4, 155 ._space_read_8 = generic_space_read_8, 156 ._space_write_8 = generic_space_write_8, 157 ._space_read_raw_2 = generic_space_read_raw_2, 158 ._space_write_raw_2 = generic_space_write_raw_2, 159 ._space_read_raw_4 = generic_space_read_raw_4, 160 ._space_write_raw_4 = generic_space_write_raw_4, 161 ._space_read_raw_8 = generic_space_read_raw_8, 162 ._space_write_raw_8 = generic_space_write_raw_8, 163 ._space_map = octeon_pcibus_io_map, 164 ._space_unmap = generic_space_unmap, 165 ._space_subregion = generic_space_region, 166 ._space_vaddr = generic_space_vaddr 167 }; 168 169 struct mips_bus_space octeon_pcibus_pci_mem_space_tag = { 170 .bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIMEM_BASE, CCA_NC), 171 .bus_private = NULL, 172 ._space_read_1 = generic_space_read_1, 173 ._space_write_1 = generic_space_write_1, 174 ._space_read_2 = generic_space_read_2, 175 ._space_write_2 = generic_space_write_2, 176 ._space_read_4 = generic_space_read_4, 177 ._space_write_4 = generic_space_write_4, 178 ._space_read_8 = generic_space_read_8, 179 ._space_write_8 = generic_space_write_8, 180 ._space_read_raw_2 = generic_space_read_raw_2, 181 ._space_write_raw_2 = generic_space_write_raw_2, 182 ._space_read_raw_4 = generic_space_read_raw_4, 183 ._space_write_raw_4 = generic_space_write_raw_4, 184 ._space_read_raw_8 = generic_space_read_raw_8, 185 ._space_write_raw_8 = generic_space_write_raw_8, 186 ._space_map = octeon_pcibus_mem_map, 187 ._space_unmap = generic_space_unmap, 188 ._space_subregion = generic_space_region, 189 ._space_vaddr = generic_space_vaddr 190 }; 191 192 int 193 octeon_pcibus_match(struct device *parent, void *vcf, void *aux) 194 { 195 struct iobus_attach_args *aa = aux; 196 197 if ((octeon_boot_info->config_flags & BOOTINFO_CFG_FLAG_PCI_HOST) == 0) { 198 OCTEON_PCIDEBUG(("%s, no PCI host function detected.\n", __func__)); 199 return 0; 200 } 201 202 if (strcmp(aa->aa_name, pcibus_cd.cd_name) == 0) 203 return 1; 204 205 return 0; 206 } 207 208 void 209 octeon_pcibus_attach(struct device *parent, struct device *self, void *aux) 210 { 211 struct octeon_pcibus_softc *sc; 212 struct pcibus_attach_args pba; 213 214 sc = (struct octeon_pcibus_softc *)self; 215 sc->sc_aa = aux; 216 217 printf("\n"); 218 219 /* 220 * Attach PCI bus. 221 */ 222 sc->sc_pc.pc_attach_hook = octeon_pcibus_attach_hook; 223 sc->sc_pc.pc_bus_maxdevs = octeon_pcibus_bus_maxdevs; 224 sc->sc_pc.pc_make_tag = octeon_pcibus_make_tag; 225 sc->sc_pc.pc_decompose_tag = octeon_pcibus_decompose_tag; 226 227 sc->sc_pc.pc_conf_v = sc; 228 sc->sc_pc.pc_conf_size = octeon_pcibus_pci_conf_size; 229 sc->sc_pc.pc_conf_read = octeon_pcibus_pci_conf_read; 230 sc->sc_pc.pc_conf_write = octeon_pcibus_pci_conf_write; 231 232 sc->sc_pc.pc_intr_v = sc; 233 sc->sc_pc.pc_intr_map = octeon_pcibus_pci_intr_map; 234 sc->sc_pc.pc_intr_string = octeon_pcibus_pci_intr_string; 235 sc->sc_pc.pc_intr_establish = octeon_pcibus_pci_intr_establish; 236 sc->sc_pc.pc_intr_disestablish = octeon_pcibus_pci_intr_disestablish; 237 238 bzero(&pba, sizeof pba); 239 pba.pba_busname = "pci"; 240 pba.pba_iot = &octeon_pcibus_pci_io_space_tag; 241 pba.pba_memt = &octeon_pcibus_pci_mem_space_tag; 242 pba.pba_dmat = &octeon_pcibus_bus_dma_tag; 243 pba.pba_pc = &sc->sc_pc; 244 pba.pba_domain = pci_ndomains++; 245 pba.pba_bus = 0; 246 pba.pba_ioex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 1); 247 pba.pba_memex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 0); 248 249 config_found(&sc->sc_dev, &pba, octeon_pcibus_print); 250 } 251 252 bus_addr_t 253 octeon_pcibus_pa_to_device(paddr_t pa) 254 { 255 OCTEON_PCIDEBUG(("%s:%d: pa=%p\n", __func__, __LINE__, (void *)pa)); 256 257 return pa & 0x1ffffffffffffUL; 258 } 259 260 paddr_t 261 octeon_pcibus_device_to_pa(bus_addr_t addr) 262 { 263 OCTEON_PCIDEBUG(("%s:%d: addr=%lx\n", __func__, __LINE__, addr)); 264 265 return PHYS_TO_XKPHYS(addr, CCA_NC); 266 } 267 268 int 269 octeon_pcibus_print(void *aux, const char *pnp) 270 { 271 struct pcibus_attach_args *pba = aux; 272 273 if (pnp) 274 printf("%s at %s", pba->pba_busname, pnp); 275 printf(" bus %d", pba->pba_bus); 276 277 return UNCONF; 278 } 279 280 /* 281 * various PCI helpers 282 */ 283 void 284 octeon_pcibus_attach_hook(struct device *parent, struct device *self, 285 struct pcibus_attach_args *pba) 286 { 287 } 288 289 /* 290 * PCI configuration space access routines 291 */ 292 int 293 octeon_pcibus_bus_maxdevs(void *v, int busno) 294 { 295 return (32); 296 } 297 298 pcitag_t 299 octeon_pcibus_make_tag(void *unused, int b, int d, int f) 300 { 301 return (b << 16) | (d << 11) | (f << 8); 302 } 303 304 void 305 octeon_pcibus_decompose_tag(void *unused, pcitag_t tag, int *bp, int *dp, int *fp) 306 { 307 if (bp != NULL) 308 *bp = (tag >> 16) & 0xff; 309 if (dp != NULL) 310 *dp = (tag >> 11) & 0x1f; 311 if (fp != NULL) 312 *fp = (tag >> 8) & 0x7; 313 } 314 315 int 316 octeon_pcibus_pci_conf_size(void *v, pcitag_t tag) 317 { 318 return PCI_CONFIG_SPACE_SIZE; 319 } 320 321 pcireg_t 322 octeon_pcibus_pci_conf_read(void *v, pcitag_t tag, int offset) 323 { 324 pcireg_t data; 325 uint64_t cfgoff; 326 327 if (tag == 0){ 328 if (offset & 0x4){ 329 cfgoff = OCTEON_PCI_CFG1 + (offset & 0xfff8); 330 } else { 331 cfgoff = OCTEON_PCI_CFG0 + (offset & 0xfff8); 332 } 333 } else { 334 cfgoff = tag + offset; 335 if (offset & 0x4) { 336 cfgoff = OCTEON_PCI_CONFIG_BASE1 + (cfgoff & 0xfffffff8); 337 } else { 338 cfgoff = OCTEON_PCI_CONFIG_BASE0 + (cfgoff & 0xfffffff8); 339 } 340 } 341 342 data = REG_READ32(cfgoff); 343 return data; 344 } 345 346 void 347 octeon_pcibus_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data) 348 { 349 uint64_t cfgoff; 350 351 if (tag == 0){ 352 if (offset & 0x4){ 353 cfgoff = OCTEON_PCI_CFG1 + (offset & 0xfff8); 354 } else { 355 cfgoff = OCTEON_PCI_CFG0 + (offset & 0xfff8); 356 } 357 } else { 358 cfgoff = tag + offset; 359 if (offset & 0x4){ 360 cfgoff = OCTEON_PCI_CONFIG_BASE1 + (cfgoff & 0xfffffff8); 361 } else { 362 cfgoff = OCTEON_PCI_CONFIG_BASE0 + (cfgoff & 0xfffffff8); 363 } 364 } 365 366 REG_WRITE32(cfgoff, data); 367 } 368 369 370 /* 371 * PCI Interrupt handling 372 */ 373 int 374 octeon_pcibus_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 375 { 376 #if 0 377 struct octeon_pcibus_softc *sc = pa->pa_pc->pc_intr_v; 378 #endif 379 int bus, dev, fn, pin; 380 381 *ihp = (pci_intr_handle_t)-1; 382 383 if (pa->pa_intrpin == 0) /* no interrupt needed */ 384 return 1; 385 386 #ifdef DIAGNOSTIC 387 if (pa->pa_intrpin > 4) { 388 printf("%s: bad interrupt pin %d\n", __func__, pa->pa_intrpin); 389 return 1; 390 } 391 #endif 392 393 pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &fn); 394 if (pa->pa_bridgetag) { 395 pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev); 396 *ihp = pa->pa_bridgeih[pin - 1]; 397 } else { 398 if (bus == 0) 399 *ihp = octeon_pcibus_intr_map(dev, fn, pa->pa_intrpin); 400 401 if (*ihp == (pci_intr_handle_t)-1) 402 return 1; 403 } 404 405 return 0; 406 } 407 408 const char * 409 octeon_pcibus_pci_intr_string(void *cookie, pci_intr_handle_t ih) 410 { 411 static char irqstr[sizeof("irq 0123456789")]; 412 413 snprintf(irqstr, sizeof irqstr, "irq %ld", ih); 414 return irqstr; 415 } 416 417 void * 418 octeon_pcibus_pci_intr_establish(void *cookie, pci_intr_handle_t ih, int level, 419 int (*cb)(void *), void *cbarg, char *name) 420 { 421 return octeon_intr_establish(ih, level, cb, cbarg, name); 422 } 423 424 void 425 octeon_pcibus_pci_intr_disestablish(void *cookie, void *ihp) 426 { 427 octeon_intr_disestablish(ihp); 428 } 429 430 /* 431 * bus_space mapping routines. 432 */ 433 int 434 octeon_pcibus_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, 435 bus_space_handle_t *bshp) 436 { 437 if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE)) { 438 offs += 439 PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC); 440 } 441 *bshp = t->bus_base + offs; 442 return 0; 443 } 444 445 int 446 octeon_pcibus_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, 447 bus_space_handle_t *bshp) 448 { 449 if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE)) { 450 offs += 451 PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC); 452 } 453 *bshp = t->bus_base + offs; 454 return 0; 455 } 456 457 /* 458 * PCI resource handling 459 */ 460 struct extent * 461 octeon_pcibus_get_resource_extent(pci_chipset_tag_t pc, int io) 462 { 463 struct octeon_pcibus_softc *sc = pc->pc_conf_v; 464 struct extent *ex; 465 char *exname; 466 int exnamesz; 467 468 exnamesz = 1 + 16 + 4; 469 exname = malloc(exnamesz, M_DEVBUF, M_NOWAIT); 470 if (exname == NULL) 471 return NULL; 472 snprintf(exname, exnamesz, "%s%s", sc->sc_dev.dv_xname, 473 io ? "_io" : "_mem"); 474 475 ex = extent_create(exname, 0, 0xffffffffffffffff, M_DEVBUF, NULL, 0, 476 EX_NOWAIT | EX_FILLED); 477 if (ex == NULL) 478 goto error; 479 480 if (io) { 481 if (extent_free(ex, _OCTEON_PCIBUS_PCIIO_BASE, 482 _OCTEON_PCIBUS_PCIIO_SIZE, EX_NOWAIT) != 0) 483 goto error; 484 } else { 485 if (extent_free(ex, _OCTEON_PCIBUS_PCIMEM_BASE, 486 _OCTEON_PCIBUS_PCIMEM_SIZE, EX_NOWAIT) != 0) 487 goto error; 488 } 489 490 #if defined(DEBUG) && defined(DIAGNOSTIC) 491 extent_print(ex); 492 #endif 493 return ex; 494 495 error: 496 if (ex != NULL) 497 extent_destroy(ex); 498 free(exname, M_DEVBUF, exnamesz); 499 return NULL; 500 } 501 502 /* 503 * PCI model specific routines 504 */ 505 506 int 507 octeon_pcibus_intr_map(int dev, int fn, int pin) 508 { 509 return CIU_INT_PCI_INTA + ((pin - 1) & 3); 510 } 511