1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012-2017 Oleksandr Tymoshenko <gonzo@freebsd.org> 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 118struct 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 135static 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 142static int 143versatile_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 157static int 158versatile_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 275static int 276versatile_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 293static int 294versatile_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 308static struct resource * 309versatile_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 352static int 353versatile_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 380static int 381versatile_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 390static int 391versatile_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 398static int 399versatile_pci_maxslots(device_t dev) 400{ 401 402 return (PCI_SLOTMAX); 403} 404 405static int 406versatile_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 435static uint32_t 436versatile_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 486static void 487versatile_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 516static 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 540static driver_t versatile_pci_driver = { 541 "pcib", 542 versatile_pci_methods, 543 sizeof(struct versatile_pci_softc), 544}; 545 546static devclass_t versatile_pci_devclass; 547 548DRIVER_MODULE(versatile_pci, simplebus, versatile_pci_driver, versatile_pci_devclass, 0, 0); 549