1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012-2017 Oleksandr Tymoshenko <[email protected]> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/module.h> 39 #include <sys/mutex.h> 40 #include <sys/rman.h> 41 #include <sys/watchdog.h> 42 43 #include <vm/vm.h> 44 #include <vm/pmap.h> 45 46 #include <machine/bus.h> 47 #include <machine/cpu.h> 48 #include <machine/intr.h> 49 50 #include <dev/pci/pcivar.h> 51 #include <dev/pci/pcireg.h> 52 53 #include <dev/pci/pcib_private.h> 54 #include "pcib_if.h" 55 56 #include <dev/ofw/openfirm.h> 57 #include <dev/ofw/ofw_bus.h> 58 #include <dev/ofw/ofw_bus_subr.h> 59 #include <dev/ofw/ofw_pci.h> 60 61 #include <arm/versatile/versatile_scm.h> 62 63 #include <machine/bus.h> 64 #include <machine/fdt.h> 65 66 #define MEM_CORE 0 67 #define MEM_BASE 1 68 #define MEM_CONF_BASE 2 69 #define MEM_REGIONS 3 70 71 #define PCI_CORE_IMAP0 0x00 72 #define PCI_CORE_IMAP1 0x04 73 #define PCI_CORE_IMAP2 0x08 74 #define PCI_CORE_SELFID 0x0C 75 #define PCI_CORE_SMAP0 0x10 76 #define PCI_CORE_SMAP1 0x14 77 #define PCI_CORE_SMAP2 0x18 78 79 #define VERSATILE_PCI_DEV 0x030010ee 80 #define VERSATILE_PCI_CLASS 0x0b400000 81 82 #define PCI_IO_WINDOW 0x44000000 83 #define PCI_IO_SIZE 0x0c000000 84 #define PCI_NPREFETCH_WINDOW 0x50000000 85 #define PCI_NPREFETCH_SIZE 0x10000000 86 #define PCI_PREFETCH_WINDOW 0x60000000 87 #define PCI_PREFETCH_SIZE 0x10000000 88 89 #define VERSATILE_PCI_IRQ_START 27 90 #define VERSATILE_PCI_IRQ_END 30 91 92 #ifdef DEBUG 93 #define dprintf(fmt, args...) do { printf("%s(): ", __func__); \ 94 printf(fmt,##args); } while (0) 95 #else 96 #define dprintf(fmt, args...) 97 #endif 98 99 #define versatile_pci_core_read_4(reg) \ 100 bus_read_4(sc->mem_res[MEM_CORE], (reg)) 101 #define versatile_pci_core_write_4(reg, val) \ 102 bus_write_4(sc->mem_res[MEM_CORE], (reg), (val)) 103 104 #define versatile_pci_read_4(reg) \ 105 bus_read_4(sc->mem_res[MEM_BASE], (reg)) 106 #define versatile_pci_write_4(reg, val) \ 107 bus_write_4(sc->mem_res[MEM_BASE], (reg), (val)) 108 109 #define versatile_pci_conf_read_4(reg) \ 110 bus_read_4(sc->mem_res[MEM_CONF_BASE], (reg)) 111 #define versatile_pci_conf_write_4(reg, val) \ 112 bus_write_4(sc->mem_res[MEM_CONF_BASE], (reg), (val)) 113 #define versatile_pci_conf_write_2(reg, val) \ 114 bus_write_2(sc->mem_res[MEM_CONF_BASE], (reg), (val)) 115 #define versatile_pci_conf_write_1(reg, val) \ 116 bus_write_1(sc->mem_res[MEM_CONF_BASE], (reg), (val)) 117 118 struct versatile_pci_softc { 119 struct resource* mem_res[MEM_REGIONS]; 120 struct resource* irq_res; 121 void* intr_hl; 122 123 int pcib_slot; 124 125 /* Bus part */ 126 int busno; 127 struct rman io_rman; 128 struct rman irq_rman; 129 struct rman mem_rman; 130 131 struct mtx mtx; 132 struct ofw_bus_iinfo pci_iinfo; 133 }; 134 135 static struct resource_spec versatile_pci_mem_spec[] = { 136 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 137 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 138 { SYS_RES_MEMORY, 2, RF_ACTIVE }, 139 { -1, 0, 0 } 140 }; 141 142 static int 143 versatile_pci_probe(device_t dev) 144 { 145 146 if (!ofw_bus_status_okay(dev)) 147 return (ENXIO); 148 149 if (ofw_bus_is_compatible(dev, "arm,versatile-pci")) { 150 device_set_desc(dev, "Versatile PCI controller"); 151 return (BUS_PROBE_DEFAULT); 152 } 153 154 return (ENXIO); 155 } 156 157 static int 158 versatile_pci_attach(device_t dev) 159 { 160 struct versatile_pci_softc *sc = device_get_softc(dev); 161 int err; 162 int slot; 163 uint32_t vendordev_id, class_id; 164 uint32_t val; 165 phandle_t node; 166 167 node = ofw_bus_get_node(dev); 168 169 /* Request memory resources */ 170 err = bus_alloc_resources(dev, versatile_pci_mem_spec, 171 sc->mem_res); 172 if (err) { 173 device_printf(dev, "Error: could not allocate memory resources\n"); 174 return (ENXIO); 175 } 176 177 /* 178 * Setup memory windows 179 */ 180 versatile_pci_core_write_4(PCI_CORE_IMAP0, (PCI_IO_WINDOW >> 28)); 181 versatile_pci_core_write_4(PCI_CORE_IMAP1, (PCI_NPREFETCH_WINDOW >> 28)); 182 versatile_pci_core_write_4(PCI_CORE_IMAP2, (PCI_PREFETCH_WINDOW >> 28)); 183 184 /* 185 * XXX: this is SDRAM offset >> 28 186 * Unused as of QEMU 1.5 187 */ 188 versatile_pci_core_write_4(PCI_CORE_SMAP0, (PCI_IO_WINDOW >> 28)); 189 versatile_pci_core_write_4(PCI_CORE_SMAP1, (PCI_NPREFETCH_WINDOW >> 28)); 190 versatile_pci_core_write_4(PCI_CORE_SMAP2, (PCI_NPREFETCH_WINDOW >> 28)); 191 192 versatile_scm_reg_write_4(SCM_PCICTL, 1); 193 194 for (slot = 0; slot <= PCI_SLOTMAX; slot++) { 195 vendordev_id = versatile_pci_read_4((slot << 11) + PCIR_DEVVENDOR); 196 class_id = versatile_pci_read_4((slot << 11) + PCIR_REVID); 197 if ((vendordev_id == VERSATILE_PCI_DEV) && 198 (class_id == VERSATILE_PCI_CLASS)) 199 break; 200 } 201 202 if (slot == (PCI_SLOTMAX + 1)) { 203 bus_release_resources(dev, versatile_pci_mem_spec, 204 sc->mem_res); 205 device_printf(dev, "Versatile PCI core not found\n"); 206 return (ENXIO); 207 } 208 209 sc->pcib_slot = slot; 210 device_printf(dev, "PCI core at slot #%d\n", slot); 211 212 versatile_pci_core_write_4(PCI_CORE_SELFID, slot); 213 val = versatile_pci_conf_read_4((slot << 11) + PCIR_COMMAND); 214 val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_MWRICEN); 215 versatile_pci_conf_write_4((slot << 11) + PCIR_COMMAND, val); 216 217 /* Again SDRAM start >> 28 */ 218 versatile_pci_write_4((slot << 11) + PCIR_BAR(0), 0); 219 versatile_pci_write_4((slot << 11) + PCIR_BAR(1), 0); 220 versatile_pci_write_4((slot << 11) + PCIR_BAR(2), 0); 221 222 /* Prepare resource managers */ 223 sc->mem_rman.rm_type = RMAN_ARRAY; 224 sc->mem_rman.rm_descr = "versatile PCI memory window"; 225 if (rman_init(&sc->mem_rman) != 0 || 226 rman_manage_region(&sc->mem_rman, PCI_NPREFETCH_WINDOW, 227 PCI_NPREFETCH_WINDOW + PCI_NPREFETCH_SIZE - 1) != 0) { 228 panic("versatile_pci_attach: failed to set up memory rman"); 229 } 230 231 bootverbose = 1; 232 sc->io_rman.rm_type = RMAN_ARRAY; 233 sc->io_rman.rm_descr = "versatile PCI IO window"; 234 if (rman_init(&sc->io_rman) != 0 || 235 rman_manage_region(&sc->io_rman, PCI_IO_WINDOW, 236 PCI_IO_WINDOW + PCI_IO_SIZE - 1) != 0) { 237 panic("versatile_pci_attach: failed to set up I/O rman"); 238 } 239 240 sc->irq_rman.rm_type = RMAN_ARRAY; 241 sc->irq_rman.rm_descr = "versatile PCI IRQs"; 242 if (rman_init(&sc->irq_rman) != 0 || 243 rman_manage_region(&sc->irq_rman, VERSATILE_PCI_IRQ_START, 244 VERSATILE_PCI_IRQ_END) != 0) { 245 panic("versatile_pci_attach: failed to set up IRQ rman"); 246 } 247 248 mtx_init(&sc->mtx, device_get_nameunit(dev), "versatilepci", 249 MTX_SPIN); 250 251 val = versatile_pci_conf_read_4((12 << 11) + PCIR_COMMAND); 252 253 for (slot = 0; slot <= PCI_SLOTMAX; slot++) { 254 vendordev_id = versatile_pci_read_4((slot << 11) + PCIR_DEVVENDOR); 255 class_id = versatile_pci_read_4((slot << 11) + PCIR_REVID); 256 257 if (slot == sc->pcib_slot) 258 continue; 259 260 if ((vendordev_id == 0xffffffff) && 261 (class_id == 0xffffffff)) 262 continue; 263 264 val = versatile_pci_conf_read_4((slot << 11) + PCIR_COMMAND); 265 val |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; 266 versatile_pci_conf_write_4((slot << 11) + PCIR_COMMAND, val); 267 } 268 269 ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(cell_t)); 270 271 device_add_child(dev, "pci", -1); 272 return (bus_generic_attach(dev)); 273 } 274 275 static int 276 versatile_pci_read_ivar(device_t dev, device_t child, int which, 277 uintptr_t *result) 278 { 279 struct versatile_pci_softc *sc = device_get_softc(dev); 280 281 switch (which) { 282 case PCIB_IVAR_DOMAIN: 283 *result = 0; 284 return (0); 285 case PCIB_IVAR_BUS: 286 *result = sc->busno; 287 return (0); 288 } 289 290 return (ENOENT); 291 } 292 293 static int 294 versatile_pci_write_ivar(device_t dev, device_t child, int which, 295 uintptr_t result) 296 { 297 struct versatile_pci_softc * sc = device_get_softc(dev); 298 299 switch (which) { 300 case PCIB_IVAR_BUS: 301 sc->busno = result; 302 return (0); 303 } 304 305 return (ENOENT); 306 } 307 308 static struct resource * 309 versatile_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 310 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 311 { 312 313 struct versatile_pci_softc *sc = device_get_softc(bus); 314 struct resource *rv; 315 struct rman *rm; 316 317 dprintf("Alloc resources %d, %08lx..%08lx, %ld\n", type, start, end, count); 318 319 switch (type) { 320 case SYS_RES_IOPORT: 321 rm = &sc->io_rman; 322 break; 323 case SYS_RES_IRQ: 324 rm = NULL; 325 break; 326 case SYS_RES_MEMORY: 327 rm = &sc->mem_rman; 328 break; 329 default: 330 return (NULL); 331 } 332 333 if (rm == NULL) 334 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), 335 child, type, rid, start, end, count, flags)); 336 337 rv = rman_reserve_resource(rm, start, end, count, flags, child); 338 if (rv == NULL) 339 return (NULL); 340 341 rman_set_rid(rv, *rid); 342 343 if (flags & RF_ACTIVE) { 344 if (bus_activate_resource(child, type, *rid, rv)) { 345 rman_release_resource(rv); 346 return (NULL); 347 } 348 } 349 return (rv); 350 } 351 352 static int 353 versatile_pci_activate_resource(device_t bus, device_t child, int type, int rid, 354 struct resource *r) 355 { 356 vm_offset_t vaddr; 357 int res; 358 359 switch(type) { 360 case SYS_RES_MEMORY: 361 case SYS_RES_IOPORT: 362 vaddr = (vm_offset_t)pmap_mapdev(rman_get_start(r), 363 rman_get_size(r)); 364 rman_set_bushandle(r, vaddr); 365 rman_set_bustag(r, fdtbus_bs_tag); 366 res = rman_activate_resource(r); 367 break; 368 case SYS_RES_IRQ: 369 res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 370 child, type, rid, r)); 371 break; 372 default: 373 res = ENXIO; 374 break; 375 } 376 377 return (res); 378 } 379 380 static int 381 versatile_pci_setup_intr(device_t bus, device_t child, struct resource *ires, 382 int flags, driver_filter_t *filt, driver_intr_t *handler, 383 void *arg, void **cookiep) 384 { 385 386 return BUS_SETUP_INTR(device_get_parent(bus), bus, ires, flags, 387 filt, handler, arg, cookiep); 388 } 389 390 static int 391 versatile_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, 392 void *cookie) 393 { 394 395 return BUS_TEARDOWN_INTR(device_get_parent(dev), dev, ires, cookie); 396 } 397 398 static int 399 versatile_pci_maxslots(device_t dev) 400 { 401 402 return (PCI_SLOTMAX); 403 } 404 405 static int 406 versatile_pci_route_interrupt(device_t bus, device_t dev, int pin) 407 { 408 struct versatile_pci_softc *sc; 409 struct ofw_pci_register reg; 410 uint32_t pintr, mintr[4]; 411 phandle_t iparent; 412 int intrcells; 413 414 sc = device_get_softc(bus); 415 pintr = pin; 416 417 bzero(®, sizeof(reg)); 418 reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | 419 (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | 420 (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); 421 422 intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), 423 &sc->pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), 424 mintr, sizeof(mintr), &iparent); 425 if (intrcells) { 426 pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr); 427 return (pintr); 428 } 429 430 device_printf(bus, "could not route pin %d for device %d.%d\n", 431 pin, pci_get_slot(dev), pci_get_function(dev)); 432 return (PCI_INVALID_IRQ); 433 } 434 435 static uint32_t 436 versatile_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, 437 u_int reg, int bytes) 438 { 439 struct versatile_pci_softc *sc = device_get_softc(dev); 440 uint32_t data; 441 uint32_t shift, mask; 442 uint32_t addr; 443 444 if (sc->pcib_slot == slot) { 445 switch (bytes) { 446 case 4: 447 return (0xffffffff); 448 break; 449 case 2: 450 return (0xffff); 451 break; 452 case 1: 453 return (0xff); 454 break; 455 } 456 } 457 458 addr = (bus << 16) | (slot << 11) | (func << 8) | (reg & ~3); 459 460 /* register access is 32-bit aligned */ 461 shift = (reg & 3) * 8; 462 463 /* Create a mask based on the width, post-shift */ 464 if (bytes == 2) 465 mask = 0xffff; 466 else if (bytes == 1) 467 mask = 0xff; 468 else 469 mask = 0xffffffff; 470 471 dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 472 func, reg, bytes); 473 474 mtx_lock_spin(&sc->mtx); 475 data = versatile_pci_conf_read_4(addr); 476 mtx_unlock_spin(&sc->mtx); 477 478 /* get request bytes from 32-bit word */ 479 data = (data >> shift) & mask; 480 481 dprintf("%s: read 0x%x\n", __func__, data); 482 483 return (data); 484 } 485 486 static void 487 versatile_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 488 u_int reg, uint32_t data, int bytes) 489 { 490 491 struct versatile_pci_softc *sc = device_get_softc(dev); 492 uint32_t addr; 493 494 dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 495 func, reg, bytes); 496 497 if (sc->pcib_slot == slot) 498 return; 499 500 addr = (bus << 16) | (slot << 11) | (func << 8) | reg; 501 mtx_lock_spin(&sc->mtx); 502 switch (bytes) { 503 case 4: 504 versatile_pci_conf_write_4(addr, data); 505 break; 506 case 2: 507 versatile_pci_conf_write_2(addr, data); 508 break; 509 case 1: 510 versatile_pci_conf_write_1(addr, data); 511 break; 512 } 513 mtx_unlock_spin(&sc->mtx); 514 } 515 516 static device_method_t versatile_pci_methods[] = { 517 DEVMETHOD(device_probe, versatile_pci_probe), 518 DEVMETHOD(device_attach, versatile_pci_attach), 519 520 /* Bus interface */ 521 DEVMETHOD(bus_read_ivar, versatile_pci_read_ivar), 522 DEVMETHOD(bus_write_ivar, versatile_pci_write_ivar), 523 DEVMETHOD(bus_alloc_resource, versatile_pci_alloc_resource), 524 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 525 DEVMETHOD(bus_activate_resource, versatile_pci_activate_resource), 526 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 527 DEVMETHOD(bus_setup_intr, versatile_pci_setup_intr), 528 DEVMETHOD(bus_teardown_intr, versatile_pci_teardown_intr), 529 530 /* pcib interface */ 531 DEVMETHOD(pcib_maxslots, versatile_pci_maxslots), 532 DEVMETHOD(pcib_read_config, versatile_pci_read_config), 533 DEVMETHOD(pcib_write_config, versatile_pci_write_config), 534 DEVMETHOD(pcib_route_interrupt, versatile_pci_route_interrupt), 535 DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), 536 537 DEVMETHOD_END 538 }; 539 540 static driver_t versatile_pci_driver = { 541 "pcib", 542 versatile_pci_methods, 543 sizeof(struct versatile_pci_softc), 544 }; 545 546 static devclass_t versatile_pci_devclass; 547 548 DRIVER_MODULE(versatile_pci, simplebus, versatile_pci_driver, versatile_pci_devclass, 0, 0); 549