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