mv_pci.c revision 186932
1185089Sraj/*- 2185089Sraj * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. 3185089Sraj * All rights reserved. 4185089Sraj * 5185089Sraj * Developed by Semihalf. 6185089Sraj * 7185089Sraj * Redistribution and use in source and binary forms, with or without 8185089Sraj * modification, are permitted provided that the following conditions 9185089Sraj * are met: 10185089Sraj * 1. Redistributions of source code must retain the above copyright 11185089Sraj * notice, this list of conditions and the following disclaimer. 12185089Sraj * 2. Redistributions in binary form must reproduce the above copyright 13185089Sraj * notice, this list of conditions and the following disclaimer in the 14185089Sraj * documentation and/or other materials provided with the distribution. 15185089Sraj * 3. Neither the name of MARVELL nor the names of contributors 16185089Sraj * may be used to endorse or promote products derived from this software 17185089Sraj * without specific prior written permission. 18185089Sraj * 19185089Sraj * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20185089Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21185089Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22185089Sraj * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 23185089Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24185089Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25185089Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26185089Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27185089Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28185089Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29185089Sraj * SUCH DAMAGE. 30185089Sraj */ 31185089Sraj 32185089Sraj/* 33185089Sraj * Marvell integrated PCI/PCI-Express controller driver. 34185089Sraj */ 35185089Sraj 36185089Sraj#include <sys/cdefs.h> 37185089Sraj__FBSDID("$FreeBSD: head/sys/arm/mv/mv_pci.c 186932 2009-01-09 10:20:51Z raj $"); 38185089Sraj 39185089Sraj#include <sys/param.h> 40185089Sraj#include <sys/systm.h> 41185089Sraj#include <sys/kernel.h> 42185089Sraj#include <sys/lock.h> 43185089Sraj#include <sys/malloc.h> 44185089Sraj#include <sys/module.h> 45185089Sraj#include <sys/mutex.h> 46185089Sraj#include <sys/queue.h> 47185089Sraj#include <sys/bus.h> 48185089Sraj#include <sys/rman.h> 49185089Sraj#include <sys/endian.h> 50185089Sraj 51185089Sraj#include <vm/vm.h> 52185089Sraj#include <vm/pmap.h> 53185089Sraj 54185089Sraj#include <dev/pci/pcivar.h> 55185089Sraj#include <dev/pci/pcireg.h> 56185089Sraj#include <dev/pci/pcib_private.h> 57185089Sraj 58185089Sraj#include "pcib_if.h" 59185089Sraj 60185089Sraj#include <machine/resource.h> 61185089Sraj#include <machine/bus.h> 62185089Sraj 63185089Sraj#include <arm/mv/mvreg.h> 64185089Sraj#include <arm/mv/mvvar.h> 65185089Sraj 66185089Sraj#define PCI_CFG_ENA (1 << 31) 67185089Sraj#define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16) 68185089Sraj#define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11) 69185089Sraj#define PCI_CFG_FUN(fun) (((fun) & 0x7) << 8) 70185089Sraj#define PCI_CFG_PCIE_REG(reg) ((reg) & 0xfc) 71185089Sraj 72185089Sraj#define PCI_REG_CFG_ADDR 0x0C78 73185089Sraj#define PCI_REG_CFG_DATA 0x0C7C 74185089Sraj#define PCI_REG_P2P_CONF 0x1D14 75185089Sraj 76185089Sraj#define PCIE_REG_CFG_ADDR 0x18F8 77185089Sraj#define PCIE_REG_CFG_DATA 0x18FC 78185089Sraj#define PCIE_REG_CONTROL 0x1A00 79185089Sraj#define PCIE_CTRL_LINK1X 0x00000001 80185089Sraj#define PCIE_REG_STATUS 0x1A04 81185089Sraj#define PCIE_REG_IRQ_MASK 0x1910 82185089Sraj 83185089Sraj#define STATUS_BUS_OFFS 8 84185089Sraj#define STATUS_BUS_MASK (0xFF << STATUS_BUS_OFFS) 85185089Sraj#define STATUS_DEV_OFFS 16 86185089Sraj#define STATUS_DEV_MASK (0x1F << STATUS_DEV_OFFS) 87185089Sraj 88185089Sraj#define P2P_CONF_BUS_OFFS 16 89185089Sraj#define P2P_CONF_BUS_MASK (0xFF << P2P_CONF_BUS_OFFS) 90185089Sraj#define P2P_CONF_DEV_OFFS 24 91185089Sraj#define P2P_CONF_DEV_MASK (0x1F << P2P_CONF_DEV_OFFS) 92185089Sraj 93185089Sraj#define PCI_VENDORID_MRVL 0x11AB 94185089Sraj 95185089Srajstruct pcib_mbus_softc { 96185089Sraj device_t sc_dev; 97185089Sraj 98186932Sraj struct rman sc_iomem_rman; 99185089Sraj bus_addr_t sc_iomem_base; 100185089Sraj bus_addr_t sc_iomem_size; 101185089Sraj bus_addr_t sc_iomem_alloc; /* Next allocation. */ 102185089Sraj 103186932Sraj struct rman sc_ioport_rman; 104185089Sraj bus_addr_t sc_ioport_base; 105185089Sraj bus_addr_t sc_ioport_size; 106185089Sraj bus_addr_t sc_ioport_alloc; /* Next allocation. */ 107185089Sraj 108185089Sraj struct resource *sc_res; 109185089Sraj bus_space_handle_t sc_bsh; 110185089Sraj bus_space_tag_t sc_bst; 111185089Sraj int sc_rid; 112185089Sraj 113185089Sraj int sc_busnr; /* Host bridge bus number */ 114185089Sraj int sc_devnr; /* Host bridge device number */ 115185089Sraj 116185089Sraj const struct obio_pci *sc_info; 117185089Sraj}; 118185089Sraj 119185089Srajstatic void pcib_mbus_identify(driver_t *driver, device_t parent); 120185089Srajstatic int pcib_mbus_probe(device_t); 121185089Srajstatic int pcib_mbus_attach(device_t); 122185089Sraj 123185089Srajstatic struct resource *pcib_mbus_alloc_resource(device_t, device_t, int, int *, 124185089Sraj u_long, u_long, u_long, u_int); 125185089Srajstatic int pcib_mbus_release_resource(device_t, device_t, int, int, 126185089Sraj struct resource *); 127185089Srajstatic int pcib_mbus_read_ivar(device_t, device_t, int, uintptr_t *); 128185089Srajstatic int pcib_mbus_write_ivar(device_t, device_t, int, uintptr_t); 129185089Sraj 130185089Srajstatic int pcib_mbus_maxslots(device_t); 131185089Srajstatic uint32_t pcib_mbus_read_config(device_t, u_int, u_int, u_int, u_int, 132185089Sraj int); 133185089Srajstatic void pcib_mbus_write_config(device_t, u_int, u_int, u_int, u_int, 134185089Sraj uint32_t, int); 135185089Srajstatic int pcib_mbus_init(struct pcib_mbus_softc *sc, int bus, int maxslot); 136185089Srajstatic int pcib_mbus_init_bar(struct pcib_mbus_softc *sc, int bus, int slot, 137185089Sraj int func, int barno); 138185089Srajstatic void pcib_mbus_init_bridge(struct pcib_mbus_softc *sc, int bus, int slot, 139185089Sraj int func); 140185089Srajstatic int pcib_mbus_init_resources(struct pcib_mbus_softc *sc, int bus, 141185089Sraj int slot, int func, int hdrtype); 142185089Sraj 143185089Sraj/* 144185089Sraj * Bus interface definitions. 145185089Sraj */ 146185089Srajstatic device_method_t pcib_mbus_methods[] = { 147185089Sraj /* Device interface */ 148185089Sraj DEVMETHOD(device_identify, pcib_mbus_identify), 149185089Sraj DEVMETHOD(device_probe, pcib_mbus_probe), 150185089Sraj DEVMETHOD(device_attach, pcib_mbus_attach), 151185089Sraj 152185089Sraj /* Bus interface */ 153185089Sraj DEVMETHOD(bus_print_child, bus_generic_print_child), 154185089Sraj DEVMETHOD(bus_read_ivar, pcib_mbus_read_ivar), 155185089Sraj DEVMETHOD(bus_write_ivar, pcib_mbus_write_ivar), 156185089Sraj DEVMETHOD(bus_alloc_resource, pcib_mbus_alloc_resource), 157185089Sraj DEVMETHOD(bus_release_resource, pcib_mbus_release_resource), 158185089Sraj DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 159185089Sraj DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 160185089Sraj DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 161185089Sraj DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 162185089Sraj 163185089Sraj /* pcib interface */ 164185089Sraj DEVMETHOD(pcib_maxslots, pcib_mbus_maxslots), 165185089Sraj DEVMETHOD(pcib_read_config, pcib_mbus_read_config), 166185089Sraj DEVMETHOD(pcib_write_config, pcib_mbus_write_config), 167185089Sraj DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 168185089Sraj 169185089Sraj { 0, 0 } 170185089Sraj}; 171185089Sraj 172185089Srajstatic driver_t pcib_mbus_driver = { 173185089Sraj "pcib", 174185089Sraj pcib_mbus_methods, 175185089Sraj sizeof(struct pcib_mbus_softc), 176185089Sraj}; 177185089Sraj 178185089Srajdevclass_t pcib_devclass; 179185089Sraj 180185089SrajDRIVER_MODULE(pcib, mbus, pcib_mbus_driver, pcib_devclass, 0, 0); 181185089Sraj 182185089Srajstatic struct mtx pcicfg_mtx; 183185089Sraj 184185089Srajstatic inline void 185185089Srajpcib_write_irq_mask(struct pcib_mbus_softc *sc, uint32_t mask) 186185089Sraj{ 187185089Sraj 188185089Sraj if (!sc->sc_info->op_type != MV_TYPE_PCI) 189185089Sraj return; 190185089Sraj 191185089Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, 192185089Sraj PCIE_REG_IRQ_MASK, mask); 193185089Sraj} 194185089Sraj 195185089Srajstatic void 196185089Srajpcib_mbus_hw_cfginit(void) 197185089Sraj{ 198185089Sraj static int opened = 0; 199185089Sraj 200185089Sraj if (opened) 201185089Sraj return; 202185089Sraj 203185089Sraj mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 204185089Sraj opened = 1; 205185089Sraj} 206185089Sraj 207185089Srajstatic uint32_t 208185089Srajpcib_mbus_hw_cfgread(struct pcib_mbus_softc *sc, u_int bus, u_int slot, 209185089Sraj u_int func, u_int reg, int bytes) 210185089Sraj{ 211185089Sraj uint32_t addr, data, ca, cd; 212185089Sraj 213185089Sraj ca = (sc->sc_info->op_type != MV_TYPE_PCI) ? 214185089Sraj PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; 215185089Sraj cd = (sc->sc_info->op_type != MV_TYPE_PCI) ? 216185089Sraj PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; 217185089Sraj addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | 218185089Sraj PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); 219185089Sraj 220185089Sraj mtx_lock_spin(&pcicfg_mtx); 221185089Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); 222185089Sraj 223185089Sraj data = ~0; 224185089Sraj switch (bytes) { 225185089Sraj case 1: 226185089Sraj data = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 227185089Sraj cd + (reg & 3)); 228185089Sraj break; 229185089Sraj case 2: 230185089Sraj data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh, 231185089Sraj cd + (reg & 2))); 232185089Sraj break; 233185089Sraj case 4: 234185089Sraj data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, 235185089Sraj cd)); 236185089Sraj break; 237185089Sraj } 238185089Sraj mtx_unlock_spin(&pcicfg_mtx); 239185089Sraj return (data); 240185089Sraj} 241185089Sraj 242185089Srajstatic void 243185089Srajpcib_mbus_hw_cfgwrite(struct pcib_mbus_softc *sc, u_int bus, u_int slot, 244185089Sraj u_int func, u_int reg, uint32_t data, int bytes) 245185089Sraj{ 246185089Sraj uint32_t addr, ca, cd; 247185089Sraj 248185089Sraj ca = (sc->sc_info->op_type != MV_TYPE_PCI) ? 249185089Sraj PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; 250185089Sraj cd = (sc->sc_info->op_type != MV_TYPE_PCI) ? 251185089Sraj PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; 252185089Sraj addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | 253185089Sraj PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); 254185089Sraj 255185089Sraj mtx_lock_spin(&pcicfg_mtx); 256185089Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); 257185089Sraj 258185089Sraj switch (bytes) { 259185089Sraj case 1: 260185089Sraj bus_space_write_1(sc->sc_bst, sc->sc_bsh, 261185089Sraj cd + (reg & 3), data); 262185089Sraj break; 263185089Sraj case 2: 264185089Sraj bus_space_write_2(sc->sc_bst, sc->sc_bsh, 265185089Sraj cd + (reg & 2), htole16(data)); 266185089Sraj break; 267185089Sraj case 4: 268185089Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, 269185089Sraj cd, htole32(data)); 270185089Sraj break; 271185089Sraj } 272185089Sraj mtx_unlock_spin(&pcicfg_mtx); 273185089Sraj} 274185089Sraj 275185089Srajstatic int 276185089Srajpcib_mbus_maxslots(device_t dev) 277185089Sraj{ 278185089Sraj struct pcib_mbus_softc *sc = device_get_softc(dev); 279185089Sraj 280185089Sraj return ((sc->sc_info->op_type != MV_TYPE_PCI) ? 1 : PCI_SLOTMAX); 281185089Sraj} 282185089Sraj 283185089Srajstatic uint32_t 284185089Srajpcib_mbus_read_config(device_t dev, u_int bus, u_int slot, u_int func, 285185089Sraj u_int reg, int bytes) 286185089Sraj{ 287185089Sraj struct pcib_mbus_softc *sc = device_get_softc(dev); 288185089Sraj 289185089Sraj /* Skip self */ 290185089Sraj if (bus == sc->sc_busnr && slot == sc->sc_devnr) 291185089Sraj return (~0U); 292185089Sraj 293185089Sraj return (pcib_mbus_hw_cfgread(sc, bus, slot, func, reg, bytes)); 294185089Sraj} 295185089Sraj 296185089Srajstatic void 297185089Srajpcib_mbus_write_config(device_t dev, u_int bus, u_int slot, u_int func, 298185089Sraj u_int reg, uint32_t val, int bytes) 299185089Sraj{ 300185089Sraj struct pcib_mbus_softc *sc = device_get_softc(dev); 301185089Sraj 302185089Sraj /* Skip self */ 303185089Sraj if (bus == sc->sc_busnr && slot == sc->sc_devnr) 304185089Sraj return; 305185089Sraj 306185089Sraj pcib_mbus_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes); 307185089Sraj} 308185089Sraj 309185089Srajstatic void 310185089Srajpcib_mbus_add_child(driver_t *driver, device_t parent, struct pcib_mbus_softc *sc) 311185089Sraj{ 312185089Sraj device_t child; 313185089Sraj int error; 314185089Sraj 315185089Sraj /* Configure CPU decoding windows */ 316185089Sraj error = decode_win_cpu_set(sc->sc_info->op_io_win_target, 317185089Sraj sc->sc_info->op_io_win_attr, sc->sc_info->op_io_base, 318185089Sraj sc->sc_info->op_io_size, -1); 319185089Sraj if (error < 0) { 320185089Sraj device_printf(parent, "Could not set up CPU decode " 321185089Sraj "window for PCI IO\n"); 322185089Sraj return; 323185089Sraj } 324185089Sraj error = decode_win_cpu_set(sc->sc_info->op_mem_win_target, 325185089Sraj sc->sc_info->op_mem_win_attr, sc->sc_info->op_mem_base, 326185089Sraj sc->sc_info->op_mem_size, -1); 327185089Sraj if (error < 0) { 328185089Sraj device_printf(parent, "Could not set up CPU decode " 329185089Sraj "windows for PCI MEM\n"); 330185089Sraj return; 331185089Sraj } 332185089Sraj 333185089Sraj /* Create driver instance */ 334185089Sraj child = BUS_ADD_CHILD(parent, 0, driver->name, -1); 335185089Sraj bus_set_resource(child, SYS_RES_MEMORY, 0, 336185089Sraj sc->sc_info->op_base, sc->sc_info->op_size); 337185089Sraj device_set_softc(child, sc); 338185089Sraj} 339185089Sraj 340185089Srajstatic void 341185089Srajpcib_mbus_identify(driver_t *driver, device_t parent) 342185089Sraj{ 343185089Sraj const struct obio_pci *info = mv_pci_info; 344185089Sraj struct pcib_mbus_softc *sc; 345185089Sraj uint32_t control; 346185089Sraj 347185089Sraj while (info->op_base) { 348185089Sraj sc = malloc(driver->size, M_DEVBUF, M_NOWAIT | M_ZERO); 349185089Sraj if (sc == NULL) { 350185089Sraj device_printf(parent, "Could not allocate pcib " 351185089Sraj "memory\n"); 352185089Sraj break; 353185089Sraj } 354185089Sraj sc->sc_info = info++; 355185089Sraj 356185089Sraj /* 357185089Sraj * PCI bridge objects are instantiated immediately. PCI-Express 358185089Sraj * bridges require more complicated handling depending on 359185089Sraj * platform configuration. 360185089Sraj */ 361185089Sraj if (sc->sc_info->op_type == MV_TYPE_PCI) { 362185089Sraj pcib_mbus_add_child(driver, parent, sc); 363185089Sraj continue; 364185089Sraj } 365185089Sraj 366185089Sraj /* 367185089Sraj * Read link configuration 368185089Sraj */ 369185089Sraj sc->sc_rid = 0; 370185089Sraj sc->sc_res = BUS_ALLOC_RESOURCE(parent, parent, SYS_RES_MEMORY, 371185089Sraj &sc->sc_rid, sc->sc_info->op_base, sc->sc_info->op_base + 372185089Sraj sc->sc_info->op_size - 1, sc->sc_info->op_size, 373185089Sraj RF_ACTIVE); 374185098Sraj if (sc->sc_res == NULL) { 375185089Sraj device_printf(parent, "Could not map pcib memory\n"); 376185098Sraj break; 377185098Sraj } 378185089Sraj 379185089Sraj sc->sc_bst = rman_get_bustag(sc->sc_res); 380185089Sraj sc->sc_bsh = rman_get_bushandle(sc->sc_res); 381185089Sraj 382185089Sraj control = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 383185089Sraj PCIE_REG_CONTROL); 384185089Sraj 385185089Sraj BUS_RELEASE_RESOURCE(parent, parent, SYS_RES_MEMORY, sc->sc_rid, 386185089Sraj sc->sc_res); 387185089Sraj 388185089Sraj /* 389185089Sraj * If this PCI-E port (controller) is configured (by the 390185089Sraj * underlying firmware) with lane width other than 1x, there 391185089Sraj * are auxiliary resources defined for aggregating more width 392185089Sraj * on our lane. Skip all such entries as they are not 393185089Sraj * standalone ports and must not have a device object 394185089Sraj * instantiated. 395185089Sraj */ 396185089Sraj if ((control & PCIE_CTRL_LINK1X) == 0) 397185089Sraj while (info->op_base && 398185089Sraj info->op_type == MV_TYPE_PCIE_AGGR_LANE) 399185089Sraj info++; 400185089Sraj 401185089Sraj pcib_mbus_add_child(driver, parent, sc); 402185089Sraj } 403185089Sraj} 404185089Sraj 405185089Srajstatic int 406185089Srajpcib_mbus_probe(device_t self) 407185089Sraj{ 408185089Sraj char buf[128]; 409185089Sraj struct pcib_mbus_softc *sc; 410185089Sraj const char *id, *type; 411185089Sraj uint32_t val; 412185089Sraj int rv = ENOENT, bus, dev; 413185089Sraj 414185089Sraj sc = device_get_softc(self); 415185089Sraj 416185089Sraj sc->sc_rid = 0; 417185089Sraj sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid, 418185089Sraj RF_ACTIVE); 419185089Sraj if (sc->sc_res == NULL) { 420185089Sraj device_printf(self, "Could not map memory\n"); 421185089Sraj return (ENXIO); 422185089Sraj } 423185089Sraj 424185089Sraj sc->sc_bst = rman_get_bustag(sc->sc_res); 425185089Sraj sc->sc_bsh = rman_get_bushandle(sc->sc_res); 426185089Sraj 427185089Sraj pcib_mbus_hw_cfginit(); 428185089Sraj 429185089Sraj /* Retrieve configuration of the bridge */ 430185089Sraj if (sc->sc_info->op_type == MV_TYPE_PCI) { 431185089Sraj val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 432185089Sraj PCI_REG_P2P_CONF); 433185089Sraj bus = sc->sc_busnr = (val & P2P_CONF_BUS_MASK) >> 434185089Sraj P2P_CONF_BUS_OFFS; 435185089Sraj dev = sc->sc_devnr = (val & P2P_CONF_DEV_MASK) >> 436185089Sraj P2P_CONF_DEV_OFFS; 437185089Sraj } else { 438185089Sraj val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS); 439185089Sraj bus = sc->sc_busnr = (val & STATUS_BUS_MASK) >> STATUS_BUS_OFFS; 440185089Sraj dev = sc->sc_devnr = (val & STATUS_DEV_MASK) >> STATUS_DEV_OFFS; 441185089Sraj } 442185089Sraj 443185089Sraj val = pcib_mbus_hw_cfgread(sc, bus, dev, 0, PCIR_VENDOR, 2); 444185089Sraj if (val != PCI_VENDORID_MRVL) 445185089Sraj goto out; 446185089Sraj 447185089Sraj val = pcib_mbus_hw_cfgread(sc, bus, dev, 0, PCIR_DEVICE, 2); 448185089Sraj switch (val) { 449185089Sraj case 0x5281: 450185089Sraj id = "88F5281"; 451185089Sraj break; 452185089Sraj case 0x5182: 453185089Sraj id = "88F5182"; 454185089Sraj break; 455185089Sraj case 0x6281: 456185089Sraj id = "88F6281"; 457185089Sraj break; 458185089Sraj case 0x6381: 459185089Sraj id = "MV78100"; 460185089Sraj break; 461185089Sraj default: 462185089Sraj device_printf(self, "unknown Marvell PCI bridge: %x\n", val); 463185089Sraj goto out; 464185089Sraj } 465185089Sraj 466185089Sraj type = "PCI"; 467185089Sraj val = pcib_mbus_hw_cfgread(sc, bus, dev, 0, PCIR_CAP_PTR, 1); 468185089Sraj while (val != 0) { 469185089Sraj val = pcib_mbus_hw_cfgread(sc, bus, dev, 0, val, 2); 470185089Sraj switch (val & 0xff) { 471185089Sraj case PCIY_PCIX: 472185089Sraj type = "PCI-X"; 473185089Sraj break; 474185089Sraj case PCIY_EXPRESS: 475185089Sraj type = "PCI-Express"; 476185089Sraj break; 477185089Sraj } 478185089Sraj val = (val >> 8) & 0xff; 479185089Sraj } 480185089Sraj 481185089Sraj snprintf(buf, sizeof(buf), "Marvell %s %s host controller", id, 482185089Sraj type); 483185089Sraj device_set_desc_copy(self, buf); 484185089Sraj rv = BUS_PROBE_DEFAULT; 485185089Srajout: 486185089Sraj bus_release_resource(self, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 487185089Sraj return (rv); 488185089Sraj} 489185089Sraj 490185089Srajstatic int 491185089Srajpcib_mbus_attach(device_t self) 492185089Sraj{ 493185089Sraj struct pcib_mbus_softc *sc; 494185089Sraj uint32_t val; 495185089Sraj int err; 496185089Sraj 497185089Sraj sc = device_get_softc(self); 498185089Sraj sc->sc_dev = self; 499185089Sraj 500185089Sraj sc->sc_rid = 0; 501185089Sraj sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid, 502185089Sraj RF_ACTIVE); 503185089Sraj if (sc->sc_res == NULL) { 504185089Sraj device_printf(self, "Could not map memory\n"); 505185089Sraj return (ENXIO); 506185089Sraj } 507185089Sraj sc->sc_bst = rman_get_bustag(sc->sc_res); 508185089Sraj sc->sc_bsh = rman_get_bushandle(sc->sc_res); 509185089Sraj 510185089Sraj /* Enable PCI bridge */ 511185089Sraj val = pcib_mbus_hw_cfgread(sc, sc->sc_busnr, sc->sc_devnr, 0, 512185089Sraj PCIR_COMMAND, 2); 513185089Sraj val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | 514185089Sraj PCIM_CMD_PORTEN; 515185089Sraj pcib_mbus_hw_cfgwrite(sc, sc->sc_busnr, sc->sc_devnr, 0, 516185089Sraj PCIR_COMMAND, val, 2); 517185089Sraj 518185089Sraj sc->sc_iomem_base = sc->sc_info->op_mem_base; 519185089Sraj sc->sc_iomem_size = sc->sc_info->op_mem_size; 520185089Sraj sc->sc_iomem_alloc = sc->sc_info->op_mem_base; 521185089Sraj 522185089Sraj sc->sc_ioport_base = sc->sc_info->op_io_base; 523185089Sraj sc->sc_ioport_size = sc->sc_info->op_io_size; 524185089Sraj sc->sc_ioport_alloc = sc->sc_info->op_io_base; 525185089Sraj 526186932Sraj sc->sc_iomem_rman.rm_type = RMAN_ARRAY; 527186932Sraj err = rman_init(&sc->sc_iomem_rman); 528186932Sraj if (err) 529186932Sraj return (err); 530186932Sraj 531186932Sraj sc->sc_ioport_rman.rm_type = RMAN_ARRAY; 532186932Sraj err = rman_init(&sc->sc_ioport_rman); 533186932Sraj if (err) { 534186932Sraj rman_fini(&sc->sc_iomem_rman); 535186932Sraj return (err); 536186932Sraj } 537186932Sraj 538186932Sraj err = rman_manage_region(&sc->sc_iomem_rman, sc->sc_iomem_base, 539186932Sraj sc->sc_iomem_base + sc->sc_iomem_size - 1); 540186932Sraj if (err) 541186932Sraj goto error; 542186932Sraj 543186932Sraj err = rman_manage_region(&sc->sc_ioport_rman, sc->sc_ioport_base, 544186932Sraj sc->sc_ioport_base + sc->sc_ioport_size - 1); 545186932Sraj if (err) 546186932Sraj goto error; 547186932Sraj 548185089Sraj err = pcib_mbus_init(sc, sc->sc_busnr, pcib_mbus_maxslots(sc->sc_dev)); 549185089Sraj if (err) 550186932Sraj goto error; 551185089Sraj 552185089Sraj device_add_child(self, "pci", -1); 553185089Sraj return (bus_generic_attach(self)); 554186932Sraj 555186932Srajerror: 556186932Sraj rman_fini(&sc->sc_iomem_rman); 557186932Sraj rman_fini(&sc->sc_ioport_rman); 558186932Sraj return (err); 559185089Sraj} 560185089Sraj 561185089Srajstatic int 562185089Srajpcib_mbus_init_bar(struct pcib_mbus_softc *sc, int bus, int slot, int func, 563185089Sraj int barno) 564185089Sraj{ 565185089Sraj bus_addr_t *allocp, limit; 566185089Sraj uint32_t addr, bar, mask, size; 567185089Sraj int reg, width; 568185089Sraj 569185089Sraj reg = PCIR_BAR(barno); 570185089Sraj bar = pcib_mbus_read_config(sc->sc_dev, bus, slot, func, reg, 4); 571185089Sraj if (bar == 0) 572185089Sraj return (1); 573185089Sraj 574185089Sraj /* Calculate BAR size: 64 or 32 bit (in 32-bit units) */ 575185089Sraj width = ((bar & 7) == 4) ? 2 : 1; 576185089Sraj 577185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4); 578185089Sraj size = pcib_mbus_read_config(sc->sc_dev, bus, slot, func, reg, 4); 579185089Sraj 580185089Sraj /* Get BAR type and size */ 581185089Sraj if (bar & 1) { 582185089Sraj /* I/O port */ 583185089Sraj allocp = &sc->sc_ioport_alloc; 584185089Sraj limit = sc->sc_ioport_base + sc->sc_ioport_size; 585185089Sraj size &= ~0x3; 586185089Sraj if ((size & 0xffff0000) == 0) 587185089Sraj size |= 0xffff0000; 588185089Sraj } else { 589185089Sraj /* Memory */ 590185089Sraj allocp = &sc->sc_iomem_alloc; 591185089Sraj limit = sc->sc_iomem_base + sc->sc_iomem_size; 592185089Sraj size &= ~0xF; 593185089Sraj } 594185089Sraj mask = ~size; 595185089Sraj size = mask + 1; 596185089Sraj 597185089Sraj /* Sanity check (must be a power of 2) */ 598185089Sraj if (size & mask) 599185089Sraj return (width); 600185089Sraj 601185089Sraj addr = (*allocp + mask) & ~mask; 602186932Sraj if ((*allocp = addr + size) > limit) 603185089Sraj return (-1); 604185089Sraj 605185089Sraj if (bootverbose) 606185089Sraj printf("PCI %u:%u:%u: reg %x: size=%08x: addr=%08x\n", 607185089Sraj bus, slot, func, reg, size, addr); 608185089Sraj 609185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4); 610185089Sraj if (width == 2) 611185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, reg + 4, 612185089Sraj 0, 4); 613185089Sraj 614185089Sraj return (width); 615185089Sraj} 616185089Sraj 617185089Srajstatic void 618185089Srajpcib_mbus_init_bridge(struct pcib_mbus_softc *sc, int bus, int slot, int func) 619185089Sraj{ 620185089Sraj bus_addr_t io_base, mem_base; 621185089Sraj uint32_t io_limit, mem_limit; 622185089Sraj int secbus; 623185089Sraj 624185089Sraj io_base = sc->sc_info->op_io_base; 625185089Sraj io_limit = io_base + sc->sc_info->op_io_size - 1; 626185089Sraj mem_base = sc->sc_info->op_mem_base; 627185089Sraj mem_limit = mem_base + sc->sc_info->op_mem_size - 1; 628185089Sraj 629185089Sraj /* Configure I/O decode registers */ 630185639Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEL_1, 631185639Sraj io_base >> 8, 1); 632185639Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEH_1, 633185639Sraj io_base >> 16, 2); 634185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITL_1, 635185089Sraj io_limit >> 8, 1); 636185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITH_1, 637185089Sraj io_limit >> 16, 2); 638185089Sraj 639185089Sraj /* Configure memory decode registers */ 640185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMBASE_1, 641185089Sraj mem_base >> 16, 2); 642185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMLIMIT_1, 643185089Sraj mem_limit >> 16, 2); 644185089Sraj 645185089Sraj /* Disable memory prefetch decode */ 646185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEL_1, 647185089Sraj 0x10, 2); 648185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEH_1, 649185089Sraj 0x0, 4); 650185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITL_1, 651185089Sraj 0xF, 2); 652185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITH_1, 653185089Sraj 0x0, 4); 654185089Sraj 655185089Sraj secbus = pcib_mbus_read_config(sc->sc_dev, bus, slot, func, 656185089Sraj PCIR_SECBUS_1, 1); 657185089Sraj 658185089Sraj /* Configure buses behind the bridge */ 659185089Sraj pcib_mbus_init(sc, secbus, PCI_SLOTMAX); 660185089Sraj} 661185089Sraj 662185089Srajstatic int 663185089Srajpcib_mbus_init_resources(struct pcib_mbus_softc *sc, int bus, int slot, 664185089Sraj int func, int hdrtype) 665185089Sraj{ 666186932Sraj const struct obio_pci_irq_map *map = sc->sc_info->op_pci_irq_map; 667185089Sraj int maxbar = (hdrtype & PCIM_HDRTYPE) ? 0 : 6; 668186932Sraj int bar = 0, irq = -1; 669186932Sraj int pin, i; 670185089Sraj 671185089Sraj /* Program the base address registers */ 672185089Sraj while (bar < maxbar) { 673185089Sraj i = pcib_mbus_init_bar(sc, bus, slot, func, bar); 674185089Sraj bar += i; 675185089Sraj if (i < 0) { 676185089Sraj device_printf(sc->sc_dev, 677185089Sraj "PCI IO/Memory space exhausted\n"); 678185089Sraj return (ENOMEM); 679185089Sraj } 680185089Sraj } 681185089Sraj 682185089Sraj /* Perform interrupt routing */ 683185089Sraj pin = pcib_mbus_read_config(sc->sc_dev, bus, slot, func, 684185089Sraj PCIR_INTPIN, 1); 685185089Sraj 686186932Sraj if (map != NULL) 687186932Sraj while (map->opim_irq >= 0) { 688186932Sraj if ((map->opim_slot == slot || map->opim_slot < 0) && 689186932Sraj (map->opim_pin == pin || map->opim_pin < 0)) 690186932Sraj irq = map->opim_irq; 691186932Sraj 692186932Sraj map++; 693186932Sraj } 694185089Sraj else 695185089Sraj irq = sc->sc_info->op_irq; 696185089Sraj 697185089Sraj if (irq >= 0) 698185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, 699185089Sraj PCIR_INTLINE, irq, 1); 700185089Sraj else { 701185089Sraj device_printf(sc->sc_dev, "Missing IRQ routing information " 702185089Sraj "for PCI device %u:%u:%u\n", bus, slot, func); 703185089Sraj return (ENXIO); 704185089Sraj } 705185089Sraj 706185089Sraj return (0); 707185089Sraj} 708185089Sraj 709185089Srajstatic int 710185089Srajpcib_mbus_init(struct pcib_mbus_softc *sc, int bus, int maxslot) 711185089Sraj{ 712185089Sraj int slot, func, maxfunc, error; 713185089Sraj uint8_t hdrtype, command, class, subclass; 714185089Sraj 715185089Sraj for (slot = 0; slot <= maxslot; slot++) { 716185089Sraj maxfunc = 0; 717185089Sraj for (func = 0; func <= maxfunc; func++) { 718185089Sraj hdrtype = pcib_mbus_read_config(sc->sc_dev, bus, slot, 719185089Sraj func, PCIR_HDRTYPE, 1); 720185089Sraj 721185089Sraj if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 722185089Sraj continue; 723185089Sraj 724185089Sraj if (func == 0 && (hdrtype & PCIM_MFDEV)) 725185089Sraj maxfunc = PCI_FUNCMAX; 726185089Sraj 727185089Sraj command = pcib_mbus_read_config(sc->sc_dev, bus, slot, 728185089Sraj func, PCIR_COMMAND, 1); 729185089Sraj command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); 730185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, 731185089Sraj PCIR_COMMAND, command, 1); 732185089Sraj 733185089Sraj error = pcib_mbus_init_resources(sc, bus, slot, func, 734185089Sraj hdrtype); 735185089Sraj 736185089Sraj if (error) 737185089Sraj return (error); 738185089Sraj 739185089Sraj command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | 740185089Sraj PCIM_CMD_PORTEN; 741185089Sraj pcib_mbus_write_config(sc->sc_dev, bus, slot, func, 742185089Sraj PCIR_COMMAND, command, 1); 743185089Sraj 744185089Sraj /* Handle PCI-PCI bridges */ 745185089Sraj class = pcib_mbus_read_config(sc->sc_dev, bus, slot, 746185089Sraj func, PCIR_CLASS, 1); 747185089Sraj subclass = pcib_mbus_read_config(sc->sc_dev, bus, slot, 748185089Sraj func, PCIR_SUBCLASS, 1); 749185089Sraj 750185089Sraj if (class != PCIC_BRIDGE || 751185089Sraj subclass != PCIS_BRIDGE_PCI) 752185089Sraj continue; 753185089Sraj 754185089Sraj pcib_mbus_init_bridge(sc, bus, slot, func); 755185089Sraj } 756185089Sraj } 757185089Sraj 758185089Sraj /* Enable all ABCD interrupts */ 759185089Sraj pcib_write_irq_mask(sc, (0xF << 24)); 760185089Sraj 761185089Sraj return (0); 762185089Sraj} 763185089Sraj 764185089Srajstatic struct resource * 765185089Srajpcib_mbus_alloc_resource(device_t dev, device_t child, int type, int *rid, 766185089Sraj u_long start, u_long end, u_long count, u_int flags) 767185089Sraj{ 768186932Sraj struct pcib_mbus_softc *sc = device_get_softc(dev); 769186932Sraj struct rman *rm = NULL; 770186932Sraj struct resource *res; 771185089Sraj 772186932Sraj switch (type) { 773186932Sraj case SYS_RES_IOPORT: 774186932Sraj rm = &sc->sc_ioport_rman; 775186932Sraj break; 776186932Sraj case SYS_RES_MEMORY: 777186932Sraj rm = &sc->sc_iomem_rman; 778186932Sraj break; 779186932Sraj default: 780186932Sraj return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 781186932Sraj type, rid, start, end, count, flags)); 782186932Sraj }; 783186932Sraj 784186932Sraj res = rman_reserve_resource(rm, start, end, count, flags, child); 785186932Sraj if (res == NULL) 786186932Sraj return (NULL); 787186932Sraj 788186932Sraj rman_set_rid(res, *rid); 789186932Sraj rman_set_bustag(res, obio_tag); 790186932Sraj rman_set_bushandle(res, start); 791186932Sraj 792186932Sraj if (flags & RF_ACTIVE) 793186932Sraj if (bus_activate_resource(child, type, *rid, res)) { 794186932Sraj rman_release_resource(res); 795186932Sraj return (NULL); 796186932Sraj } 797186932Sraj 798186932Sraj return (res); 799185089Sraj} 800185089Sraj 801185089Srajstatic int 802185089Srajpcib_mbus_release_resource(device_t dev, device_t child, int type, int rid, 803185089Sraj struct resource *res) 804185089Sraj{ 805185089Sraj 806186932Sraj if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) 807186932Sraj return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 808186932Sraj type, rid, res)); 809186932Sraj 810186932Sraj return (rman_release_resource(res)); 811185089Sraj} 812185089Sraj 813185089Srajstatic int 814185089Srajpcib_mbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 815185089Sraj{ 816185089Sraj struct pcib_mbus_softc *sc = device_get_softc(dev); 817185089Sraj 818185089Sraj switch (which) { 819185089Sraj case PCIB_IVAR_BUS: 820185089Sraj *result = sc->sc_busnr; 821185089Sraj return (0); 822185089Sraj case PCIB_IVAR_DOMAIN: 823185089Sraj *result = device_get_unit(dev); 824185089Sraj return (0); 825185089Sraj } 826185089Sraj 827185089Sraj return (ENOENT); 828185089Sraj} 829185089Sraj 830185089Srajstatic int 831185089Srajpcib_mbus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 832185089Sraj{ 833185089Sraj struct pcib_mbus_softc *sc = device_get_softc(dev); 834185089Sraj 835185089Sraj switch (which) { 836185089Sraj case PCIB_IVAR_BUS: 837185089Sraj sc->sc_busnr = value; 838185089Sraj return (0); 839185089Sraj } 840185089Sraj 841185089Sraj return (ENOENT); 842185089Sraj} 843