1209908Sraj/*- 2209908Sraj * Copyright 2006-2007 by Juniper Networks. 3209908Sraj * Copyright 2008 Semihalf. 4209908Sraj * Copyright 2010 The FreeBSD Foundation 5209908Sraj * All rights reserved. 6209908Sraj * 7209908Sraj * Portions of this software were developed by Semihalf 8209908Sraj * under sponsorship from the FreeBSD Foundation. 9209908Sraj * 10209908Sraj * Redistribution and use in source and binary forms, with or without 11209908Sraj * modification, are permitted provided that the following conditions 12209908Sraj * are met: 13209908Sraj * 1. Redistributions of source code must retain the above copyright 14209908Sraj * notice, this list of conditions and the following disclaimer. 15209908Sraj * 2. Redistributions in binary form must reproduce the above copyright 16209908Sraj * notice, this list of conditions and the following disclaimer in the 17209908Sraj * documentation and/or other materials provided with the distribution. 18209908Sraj * 3. The name of the author may not be used to endorse or promote products 19209908Sraj * derived from this software without specific prior written permission. 20209908Sraj * 21209908Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22209908Sraj * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23209908Sraj * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24209908Sraj * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25209908Sraj * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26209908Sraj * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27209908Sraj * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28209908Sraj * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29209908Sraj * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30209908Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31209908Sraj * SUCH DAMAGE. 32209908Sraj * 33209908Sraj * From: FreeBSD: src/sys/powerpc/mpc85xx/pci_ocp.c,v 1.9 2010/03/23 23:46:28 marcel 34209908Sraj */ 35209908Sraj 36209908Sraj#include <sys/cdefs.h> 37209908Sraj__FBSDID("$FreeBSD$"); 38209908Sraj 39209908Sraj#include <sys/param.h> 40209908Sraj#include <sys/systm.h> 41209908Sraj#include <sys/ktr.h> 42209908Sraj#include <sys/sockio.h> 43209908Sraj#include <sys/mbuf.h> 44209908Sraj#include <sys/malloc.h> 45209908Sraj#include <sys/kernel.h> 46209908Sraj#include <sys/module.h> 47209908Sraj#include <sys/socket.h> 48209908Sraj#include <sys/queue.h> 49209908Sraj#include <sys/bus.h> 50209908Sraj#include <sys/lock.h> 51209908Sraj#include <sys/mutex.h> 52209908Sraj#include <sys/rman.h> 53209908Sraj#include <sys/endian.h> 54209908Sraj 55209908Sraj#include <vm/vm.h> 56209908Sraj#include <vm/pmap.h> 57209908Sraj 58209908Sraj#include <dev/fdt/fdt_common.h> 59209908Sraj#include <dev/ofw/ofw_bus.h> 60209908Sraj#include <dev/ofw/ofw_bus_subr.h> 61209908Sraj#include <dev/pci/pcivar.h> 62209908Sraj#include <dev/pci/pcireg.h> 63209908Sraj#include <dev/pci/pcib_private.h> 64209908Sraj 65209908Sraj#include "ofw_bus_if.h" 66209908Sraj#include "pcib_if.h" 67209908Sraj 68209908Sraj#include <machine/resource.h> 69209908Sraj#include <machine/bus.h> 70209908Sraj#include <machine/intr_machdep.h> 71209908Sraj 72209908Sraj#include <powerpc/mpc85xx/mpc85xx.h> 73209908Sraj 74209908Sraj#define REG_CFG_ADDR 0x0000 75209908Sraj#define CONFIG_ACCESS_ENABLE 0x80000000 76209908Sraj 77209908Sraj#define REG_CFG_DATA 0x0004 78209908Sraj#define REG_INT_ACK 0x0008 79209908Sraj 80209908Sraj#define REG_POTAR(n) (0x0c00 + 0x20 * (n)) 81209908Sraj#define REG_POTEAR(n) (0x0c04 + 0x20 * (n)) 82209908Sraj#define REG_POWBAR(n) (0x0c08 + 0x20 * (n)) 83209908Sraj#define REG_POWAR(n) (0x0c10 + 0x20 * (n)) 84209908Sraj 85209908Sraj#define REG_PITAR(n) (0x0e00 - 0x20 * (n)) 86209908Sraj#define REG_PIWBAR(n) (0x0e08 - 0x20 * (n)) 87209908Sraj#define REG_PIWBEAR(n) (0x0e0c - 0x20 * (n)) 88209908Sraj#define REG_PIWAR(n) (0x0e10 - 0x20 * (n)) 89209908Sraj 90209908Sraj#define REG_PEX_MES_DR 0x0020 91209908Sraj#define REG_PEX_MES_IER 0x0028 92209908Sraj#define REG_PEX_ERR_DR 0x0e00 93209908Sraj#define REG_PEX_ERR_EN 0x0e08 94209908Sraj 95209908Sraj#define PCIR_LTSSM 0x404 96209908Sraj#define LTSSM_STAT_L0 0x16 97209908Sraj 98209908Sraj#define DEVFN(b, s, f) ((b << 16) | (s << 8) | f) 99209908Sraj 100209908Srajstruct fsl_pcib_softc { 101209908Sraj device_t sc_dev; 102209908Sraj 103209908Sraj struct rman sc_iomem; 104209908Sraj bus_addr_t sc_iomem_va; /* Virtual mapping. */ 105209908Sraj bus_addr_t sc_iomem_size; 106209908Sraj bus_addr_t sc_iomem_alloc; /* Next allocation. */ 107209908Sraj int sc_iomem_target; 108209908Sraj struct rman sc_ioport; 109209908Sraj bus_addr_t sc_ioport_va; /* Virtual mapping. */ 110209908Sraj bus_addr_t sc_ioport_size; 111209908Sraj bus_addr_t sc_ioport_alloc; /* Next allocation. */ 112209908Sraj int sc_ioport_target; 113209908Sraj 114209908Sraj struct resource *sc_res; 115209908Sraj bus_space_handle_t sc_bsh; 116209908Sraj bus_space_tag_t sc_bst; 117209908Sraj int sc_rid; 118209908Sraj 119209908Sraj int sc_busnr; 120209908Sraj int sc_pcie; 121209908Sraj uint8_t sc_pcie_capreg; /* PCI-E Capability Reg Set */ 122209908Sraj 123209908Sraj /* Devices that need special attention. */ 124209908Sraj int sc_devfn_tundra; 125209908Sraj int sc_devfn_via_ide; 126209908Sraj 127209908Sraj struct fdt_pci_intr sc_intr_info; 128209908Sraj}; 129209908Sraj 130209908Sraj/* Local forward declerations. */ 131209908Srajstatic uint32_t fsl_pcib_cfgread(struct fsl_pcib_softc *, u_int, u_int, u_int, 132209908Sraj u_int, int); 133209908Srajstatic void fsl_pcib_cfgwrite(struct fsl_pcib_softc *, u_int, u_int, u_int, 134209908Sraj u_int, uint32_t, int); 135209908Srajstatic int fsl_pcib_decode_win(phandle_t, struct fsl_pcib_softc *); 136209908Srajstatic void fsl_pcib_err_init(device_t); 137209908Srajstatic void fsl_pcib_inbound(struct fsl_pcib_softc *, int, int, u_long, 138209908Sraj u_long, u_long); 139218075Smarcelstatic int fsl_pcib_init(struct fsl_pcib_softc *, int, int); 140209908Srajstatic int fsl_pcib_intr_info(phandle_t, struct fsl_pcib_softc *); 141209908Srajstatic int fsl_pcib_set_range(struct fsl_pcib_softc *, int, int, u_long, 142209908Sraj u_long); 143209908Srajstatic void fsl_pcib_outbound(struct fsl_pcib_softc *, int, int, u_long, 144209908Sraj u_long, u_long); 145209908Sraj 146209908Sraj/* Forward declerations. */ 147209908Srajstatic int fsl_pcib_attach(device_t); 148209908Srajstatic int fsl_pcib_detach(device_t); 149209908Srajstatic int fsl_pcib_probe(device_t); 150209908Sraj 151209908Srajstatic struct resource *fsl_pcib_alloc_resource(device_t, device_t, int, int *, 152209908Sraj u_long, u_long, u_long, u_int); 153209908Srajstatic int fsl_pcib_read_ivar(device_t, device_t, int, uintptr_t *); 154209908Srajstatic int fsl_pcib_release_resource(device_t, device_t, int, int, 155209908Sraj struct resource *); 156209908Srajstatic int fsl_pcib_write_ivar(device_t, device_t, int, uintptr_t); 157209908Sraj 158209908Srajstatic int fsl_pcib_maxslots(device_t); 159209908Srajstatic uint32_t fsl_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int); 160209908Srajstatic void fsl_pcib_write_config(device_t, u_int, u_int, u_int, u_int, 161209908Sraj uint32_t, int); 162209908Sraj 163209908Sraj/* Configuration r/w mutex. */ 164209908Srajstruct mtx pcicfg_mtx; 165209908Srajstatic int mtx_initialized = 0; 166209908Sraj 167209908Sraj/* 168209908Sraj * Bus interface definitions. 169209908Sraj */ 170209908Srajstatic device_method_t fsl_pcib_methods[] = { 171209908Sraj /* Device interface */ 172209908Sraj DEVMETHOD(device_probe, fsl_pcib_probe), 173209908Sraj DEVMETHOD(device_attach, fsl_pcib_attach), 174209908Sraj DEVMETHOD(device_detach, fsl_pcib_detach), 175209908Sraj 176209908Sraj /* Bus interface */ 177209908Sraj DEVMETHOD(bus_read_ivar, fsl_pcib_read_ivar), 178209908Sraj DEVMETHOD(bus_write_ivar, fsl_pcib_write_ivar), 179209908Sraj DEVMETHOD(bus_alloc_resource, fsl_pcib_alloc_resource), 180209908Sraj DEVMETHOD(bus_release_resource, fsl_pcib_release_resource), 181209908Sraj DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 182209908Sraj DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 183209908Sraj DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 184209908Sraj DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 185209908Sraj 186209908Sraj /* pcib interface */ 187209908Sraj DEVMETHOD(pcib_maxslots, fsl_pcib_maxslots), 188209908Sraj DEVMETHOD(pcib_read_config, fsl_pcib_read_config), 189209908Sraj DEVMETHOD(pcib_write_config, fsl_pcib_write_config), 190209908Sraj DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 191209908Sraj 192209908Sraj /* OFW bus interface */ 193209908Sraj DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 194209908Sraj DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 195209908Sraj DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 196209908Sraj DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 197209908Sraj DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 198209908Sraj 199227843Smarius DEVMETHOD_END 200209908Sraj}; 201209908Sraj 202209908Srajstatic driver_t fsl_pcib_driver = { 203209908Sraj "pcib", 204209908Sraj fsl_pcib_methods, 205209908Sraj sizeof(struct fsl_pcib_softc), 206209908Sraj}; 207209908Sraj 208209908Srajdevclass_t pcib_devclass; 209209908Sraj 210209908SrajDRIVER_MODULE(pcib, fdtbus, fsl_pcib_driver, pcib_devclass, 0, 0); 211209908Sraj 212209908Srajstatic int 213209908Srajfsl_pcib_probe(device_t dev) 214209908Sraj{ 215218075Smarcel phandle_t node; 216209908Sraj 217218075Smarcel node = ofw_bus_get_node(dev); 218218075Smarcel if (!fdt_is_type(node, "pci")) 219209908Sraj return (ENXIO); 220218075Smarcel 221218075Smarcel if (!(fdt_is_compatible(node, "fsl,mpc8540-pci") || 222218075Smarcel fdt_is_compatible(node, "fsl,mpc8548-pcie"))) 223209908Sraj return (ENXIO); 224209908Sraj 225209908Sraj device_set_desc(dev, "Freescale Integrated PCI/PCI-E Controller"); 226209908Sraj return (BUS_PROBE_DEFAULT); 227209908Sraj} 228209908Sraj 229209908Srajstatic int 230209908Srajfsl_pcib_attach(device_t dev) 231209908Sraj{ 232209908Sraj struct fsl_pcib_softc *sc; 233209908Sraj phandle_t node; 234209908Sraj uint32_t cfgreg; 235218075Smarcel int maxslot; 236209908Sraj uint8_t ltssm, capptr; 237209908Sraj 238209908Sraj sc = device_get_softc(dev); 239209908Sraj sc->sc_dev = dev; 240209908Sraj 241209908Sraj sc->sc_rid = 0; 242209908Sraj sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 243209908Sraj RF_ACTIVE); 244209908Sraj if (sc->sc_res == NULL) { 245209908Sraj device_printf(dev, "could not map I/O memory\n"); 246209908Sraj return (ENXIO); 247209908Sraj } 248209908Sraj sc->sc_bst = rman_get_bustag(sc->sc_res); 249209908Sraj sc->sc_bsh = rman_get_bushandle(sc->sc_res); 250209908Sraj sc->sc_busnr = 0; 251209908Sraj 252209908Sraj if (!mtx_initialized) { 253209908Sraj mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 254209908Sraj mtx_initialized = 1; 255209908Sraj } 256209908Sraj 257209908Sraj cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_VENDOR, 2); 258209908Sraj if (cfgreg != 0x1057 && cfgreg != 0x1957) 259209908Sraj goto err; 260209908Sraj 261209908Sraj capptr = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_CAP_PTR, 1); 262209908Sraj while (capptr != 0) { 263209908Sraj cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, capptr, 2); 264209908Sraj switch (cfgreg & 0xff) { 265209908Sraj case PCIY_PCIX: 266209908Sraj break; 267209908Sraj case PCIY_EXPRESS: 268209908Sraj sc->sc_pcie = 1; 269209908Sraj sc->sc_pcie_capreg = capptr; 270209908Sraj break; 271209908Sraj } 272209908Sraj capptr = (cfgreg >> 8) & 0xff; 273209908Sraj } 274209908Sraj 275209908Sraj node = ofw_bus_get_node(dev); 276209908Sraj /* 277209908Sraj * Get PCI interrupt info. 278209908Sraj */ 279209908Sraj if (fsl_pcib_intr_info(node, sc) != 0) { 280209908Sraj device_printf(dev, "could not retrieve interrupt info\n"); 281209908Sraj goto err; 282209908Sraj } 283209908Sraj 284209908Sraj /* 285209908Sraj * Configure decode windows for PCI(E) access. 286209908Sraj */ 287209908Sraj if (fsl_pcib_decode_win(node, sc) != 0) 288209908Sraj goto err; 289209908Sraj 290209908Sraj cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_COMMAND, 2); 291209908Sraj cfgreg |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | 292209908Sraj PCIM_CMD_PORTEN; 293209908Sraj fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_COMMAND, cfgreg, 2); 294209908Sraj 295209908Sraj sc->sc_devfn_tundra = -1; 296209908Sraj sc->sc_devfn_via_ide = -1; 297209908Sraj 298209908Sraj 299209908Sraj /* 300218075Smarcel * Scan bus using firmware configured, 0 based bus numbering. 301209908Sraj */ 302218075Smarcel sc->sc_busnr = 0; 303218075Smarcel maxslot = (sc->sc_pcie) ? 0 : PCI_SLOTMAX; 304218075Smarcel fsl_pcib_init(sc, sc->sc_busnr, maxslot); 305209908Sraj 306209908Sraj if (sc->sc_pcie) { 307209908Sraj ltssm = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_LTSSM, 1); 308209908Sraj if (ltssm < LTSSM_STAT_L0) { 309209908Sraj if (bootverbose) 310209908Sraj printf("PCI %d: no PCIE link, skipping\n", 311209908Sraj device_get_unit(dev)); 312209908Sraj return (0); 313209908Sraj } 314209908Sraj } 315209908Sraj 316209908Sraj fsl_pcib_err_init(dev); 317209908Sraj 318209908Sraj device_add_child(dev, "pci", -1); 319209908Sraj return (bus_generic_attach(dev)); 320209908Sraj 321209908Srajerr: 322209908Sraj bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 323209908Sraj return (ENXIO); 324209908Sraj} 325209908Sraj 326209908Srajstatic uint32_t 327209908Srajfsl_pcib_cfgread(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func, 328209908Sraj u_int reg, int bytes) 329209908Sraj{ 330209908Sraj uint32_t addr, data; 331209908Sraj 332209908Sraj if (bus == sc->sc_busnr - 1) 333209908Sraj bus = 0; 334209908Sraj 335209908Sraj addr = CONFIG_ACCESS_ENABLE; 336209908Sraj addr |= (bus & 0xff) << 16; 337209908Sraj addr |= (slot & 0x1f) << 11; 338209908Sraj addr |= (func & 0x7) << 8; 339209908Sraj addr |= reg & 0xfc; 340209908Sraj if (sc->sc_pcie) 341209908Sraj addr |= (reg & 0xf00) << 16; 342209908Sraj 343209908Sraj mtx_lock_spin(&pcicfg_mtx); 344209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr); 345209908Sraj 346209908Sraj switch (bytes) { 347209908Sraj case 1: 348209908Sraj data = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 349209908Sraj REG_CFG_DATA + (reg & 3)); 350209908Sraj break; 351209908Sraj case 2: 352209908Sraj data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh, 353209908Sraj REG_CFG_DATA + (reg & 2))); 354209908Sraj break; 355209908Sraj case 4: 356209908Sraj data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, 357209908Sraj REG_CFG_DATA)); 358209908Sraj break; 359209908Sraj default: 360209908Sraj data = ~0; 361209908Sraj break; 362209908Sraj } 363209908Sraj mtx_unlock_spin(&pcicfg_mtx); 364209908Sraj return (data); 365209908Sraj} 366209908Sraj 367209908Srajstatic void 368209908Srajfsl_pcib_cfgwrite(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func, 369209908Sraj u_int reg, uint32_t data, int bytes) 370209908Sraj{ 371209908Sraj uint32_t addr; 372209908Sraj 373209908Sraj if (bus == sc->sc_busnr - 1) 374209908Sraj bus = 0; 375209908Sraj 376209908Sraj addr = CONFIG_ACCESS_ENABLE; 377209908Sraj addr |= (bus & 0xff) << 16; 378209908Sraj addr |= (slot & 0x1f) << 11; 379209908Sraj addr |= (func & 0x7) << 8; 380209908Sraj addr |= reg & 0xfc; 381209908Sraj if (sc->sc_pcie) 382209908Sraj addr |= (reg & 0xf00) << 16; 383209908Sraj 384209908Sraj mtx_lock_spin(&pcicfg_mtx); 385209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr); 386209908Sraj 387209908Sraj switch (bytes) { 388209908Sraj case 1: 389209908Sraj bus_space_write_1(sc->sc_bst, sc->sc_bsh, 390209908Sraj REG_CFG_DATA + (reg & 3), data); 391209908Sraj break; 392209908Sraj case 2: 393209908Sraj bus_space_write_2(sc->sc_bst, sc->sc_bsh, 394209908Sraj REG_CFG_DATA + (reg & 2), htole16(data)); 395209908Sraj break; 396209908Sraj case 4: 397209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, 398209908Sraj REG_CFG_DATA, htole32(data)); 399209908Sraj break; 400209908Sraj } 401209908Sraj mtx_unlock_spin(&pcicfg_mtx); 402209908Sraj} 403209908Sraj 404209908Sraj#if 0 405209908Srajstatic void 406209908Srajdump(struct fsl_pcib_softc *sc) 407209908Sraj{ 408209908Sraj unsigned int i; 409209908Sraj 410209908Sraj#define RD(o) bus_space_read_4(sc->sc_bst, sc->sc_bsh, o) 411209908Sraj for (i = 0; i < 5; i++) { 412209908Sraj printf("POTAR%u =0x%08x\n", i, RD(REG_POTAR(i))); 413209908Sraj printf("POTEAR%u =0x%08x\n", i, RD(REG_POTEAR(i))); 414209908Sraj printf("POWBAR%u =0x%08x\n", i, RD(REG_POWBAR(i))); 415209908Sraj printf("POWAR%u =0x%08x\n", i, RD(REG_POWAR(i))); 416209908Sraj } 417209908Sraj printf("\n"); 418209908Sraj for (i = 1; i < 4; i++) { 419209908Sraj printf("PITAR%u =0x%08x\n", i, RD(REG_PITAR(i))); 420209908Sraj printf("PIWBAR%u =0x%08x\n", i, RD(REG_PIWBAR(i))); 421209908Sraj printf("PIWBEAR%u=0x%08x\n", i, RD(REG_PIWBEAR(i))); 422209908Sraj printf("PIWAR%u =0x%08x\n", i, RD(REG_PIWAR(i))); 423209908Sraj } 424209908Sraj printf("\n"); 425209908Sraj#undef RD 426209908Sraj 427209908Sraj for (i = 0; i < 0x48; i += 4) { 428209908Sraj printf("cfg%02x=0x%08x\n", i, fsl_pcib_cfgread(sc, 0, 0, 0, 429209908Sraj i, 4)); 430209908Sraj } 431209908Sraj} 432209908Sraj#endif 433209908Sraj 434209908Srajstatic int 435209908Srajfsl_pcib_maxslots(device_t dev) 436209908Sraj{ 437209908Sraj struct fsl_pcib_softc *sc = device_get_softc(dev); 438209908Sraj 439218075Smarcel return ((sc->sc_pcie) ? 0 : PCI_SLOTMAX); 440209908Sraj} 441209908Sraj 442209908Srajstatic uint32_t 443209908Srajfsl_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 444209908Sraj u_int reg, int bytes) 445209908Sraj{ 446209908Sraj struct fsl_pcib_softc *sc = device_get_softc(dev); 447209908Sraj u_int devfn; 448209908Sraj 449209908Sraj if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10) 450209908Sraj return (~0); 451209908Sraj devfn = DEVFN(bus, slot, func); 452209908Sraj if (devfn == sc->sc_devfn_tundra) 453209908Sraj return (~0); 454209908Sraj if (devfn == sc->sc_devfn_via_ide && reg == PCIR_INTPIN) 455209908Sraj return (1); 456209908Sraj return (fsl_pcib_cfgread(sc, bus, slot, func, reg, bytes)); 457209908Sraj} 458209908Sraj 459209908Srajstatic void 460209908Srajfsl_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 461209908Sraj u_int reg, uint32_t val, int bytes) 462209908Sraj{ 463209908Sraj struct fsl_pcib_softc *sc = device_get_softc(dev); 464209908Sraj 465209908Sraj if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10) 466209908Sraj return; 467209908Sraj fsl_pcib_cfgwrite(sc, bus, slot, func, reg, val, bytes); 468209908Sraj} 469209908Sraj 470209908Srajstatic void 471209908Srajfsl_pcib_init_via(struct fsl_pcib_softc *sc, uint16_t device, int bus, 472209908Sraj int slot, int fn) 473209908Sraj{ 474209908Sraj 475209908Sraj if (device == 0x0686) { 476209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x52, 0x34, 1); 477209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x77, 0x00, 1); 478209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x83, 0x98, 1); 479209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x85, 0x03, 1); 480209908Sraj } else if (device == 0x0571) { 481209908Sraj sc->sc_devfn_via_ide = DEVFN(bus, slot, fn); 482209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, fn, 0x40, 0x0b, 1); 483209908Sraj } 484209908Sraj} 485209908Sraj 486209908Srajstatic int 487209908Srajfsl_pcib_init_bar(struct fsl_pcib_softc *sc, int bus, int slot, int func, 488209908Sraj int barno) 489209908Sraj{ 490209908Sraj bus_addr_t *allocp; 491209908Sraj uint32_t addr, mask, size; 492209908Sraj int reg, width; 493209908Sraj 494209908Sraj reg = PCIR_BAR(barno); 495209908Sraj 496209908Sraj if (DEVFN(bus, slot, func) == sc->sc_devfn_via_ide) { 497209908Sraj switch (barno) { 498209908Sraj case 0: addr = 0x1f0; break; 499209908Sraj case 1: addr = 0x3f4; break; 500209908Sraj case 2: addr = 0x170; break; 501209908Sraj case 3: addr = 0x374; break; 502209908Sraj case 4: addr = 0xcc0; break; 503209908Sraj default: return (1); 504209908Sraj } 505209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4); 506209908Sraj return (1); 507209908Sraj } 508209908Sraj 509209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4); 510209908Sraj size = fsl_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4); 511209908Sraj if (size == 0) 512209908Sraj return (1); 513209908Sraj width = ((size & 7) == 4) ? 2 : 1; 514209908Sraj 515209908Sraj if (size & 1) { /* I/O port */ 516209908Sraj allocp = &sc->sc_ioport_alloc; 517209908Sraj size &= ~3; 518209908Sraj if ((size & 0xffff0000) == 0) 519209908Sraj size |= 0xffff0000; 520209908Sraj } else { /* memory */ 521209908Sraj allocp = &sc->sc_iomem_alloc; 522209908Sraj size &= ~15; 523209908Sraj } 524209908Sraj mask = ~size; 525209908Sraj size = mask + 1; 526209908Sraj /* Sanity check (must be a power of 2). */ 527209908Sraj if (size & mask) 528209908Sraj return (width); 529209908Sraj 530209908Sraj addr = (*allocp + mask) & ~mask; 531209908Sraj *allocp = addr + size; 532209908Sraj 533209908Sraj if (bootverbose) 534209908Sraj printf("PCI %u:%u:%u:%u: reg %x: size=%08x: addr=%08x\n", 535209908Sraj device_get_unit(sc->sc_dev), bus, slot, func, reg, 536209908Sraj size, addr); 537209908Sraj 538209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4); 539209908Sraj if (width == 2) 540209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4, 541209908Sraj 0, 4); 542209908Sraj return (width); 543209908Sraj} 544209908Sraj 545209908Srajstatic u_int 546209908Srajfsl_pcib_route_int(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func, 547209908Sraj u_int intpin) 548209908Sraj{ 549209908Sraj int err, unit; 550209908Sraj u_int devfn, intline; 551209908Sraj 552209908Sraj unit = device_get_unit(sc->sc_dev); 553209908Sraj 554209908Sraj devfn = DEVFN(bus, slot, func); 555209908Sraj if (devfn == sc->sc_devfn_via_ide) 556218184Smarcel intline = MAP_IRQ(0, 14); 557209908Sraj else if (devfn == sc->sc_devfn_via_ide + 1) 558218184Smarcel intline = MAP_IRQ(0, 10); 559209908Sraj else if (devfn == sc->sc_devfn_via_ide + 2) 560218184Smarcel intline = MAP_IRQ(0, 10); 561209908Sraj else { 562209908Sraj if (intpin != 0) 563209908Sraj err = fdt_pci_route_intr(bus, slot, func, intpin, 564209908Sraj &sc->sc_intr_info, &intline); 565209908Sraj else 566209908Sraj intline = 0xff; 567209908Sraj } 568209908Sraj 569209908Sraj if (bootverbose) 570209908Sraj printf("PCI %u:%u:%u:%u: intpin %u: intline=%u\n", 571209908Sraj unit, bus, slot, func, intpin, intline); 572209908Sraj 573209908Sraj return (intline); 574209908Sraj} 575209908Sraj 576209908Srajstatic int 577218075Smarcelfsl_pcib_init(struct fsl_pcib_softc *sc, int bus, int maxslot) 578209908Sraj{ 579218075Smarcel int secbus; 580209908Sraj int old_pribus, old_secbus, old_subbus; 581209908Sraj int new_pribus, new_secbus, new_subbus; 582209908Sraj int slot, func, maxfunc; 583209908Sraj int bar, maxbar; 584209908Sraj uint16_t vendor, device; 585209908Sraj uint8_t command, hdrtype, class, subclass; 586209908Sraj uint8_t intline, intpin; 587209908Sraj 588218075Smarcel secbus = bus; 589209908Sraj for (slot = 0; slot <= maxslot; slot++) { 590209908Sraj maxfunc = 0; 591209908Sraj for (func = 0; func <= maxfunc; func++) { 592209908Sraj hdrtype = fsl_pcib_read_config(sc->sc_dev, bus, slot, 593209908Sraj func, PCIR_HDRTYPE, 1); 594209908Sraj 595209908Sraj if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 596209908Sraj continue; 597209908Sraj 598209908Sraj if (func == 0 && (hdrtype & PCIM_MFDEV)) 599209908Sraj maxfunc = PCI_FUNCMAX; 600209908Sraj 601209908Sraj vendor = fsl_pcib_read_config(sc->sc_dev, bus, slot, 602209908Sraj func, PCIR_VENDOR, 2); 603209908Sraj device = fsl_pcib_read_config(sc->sc_dev, bus, slot, 604209908Sraj func, PCIR_DEVICE, 2); 605209908Sraj 606209908Sraj if (vendor == 0x1957 && device == 0x3fff) { 607209908Sraj sc->sc_devfn_tundra = DEVFN(bus, slot, func); 608209908Sraj continue; 609209908Sraj } 610209908Sraj 611209908Sraj command = fsl_pcib_read_config(sc->sc_dev, bus, slot, 612209908Sraj func, PCIR_COMMAND, 1); 613209908Sraj command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); 614209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 615209908Sraj PCIR_COMMAND, command, 1); 616209908Sraj 617209908Sraj if (vendor == 0x1106) 618209908Sraj fsl_pcib_init_via(sc, device, bus, slot, func); 619209908Sraj 620209908Sraj /* Program the base address registers. */ 621209908Sraj maxbar = (hdrtype & PCIM_HDRTYPE) ? 1 : 6; 622209908Sraj bar = 0; 623209908Sraj while (bar < maxbar) 624209908Sraj bar += fsl_pcib_init_bar(sc, bus, slot, func, 625209908Sraj bar); 626209908Sraj 627209908Sraj /* Perform interrupt routing. */ 628209908Sraj intpin = fsl_pcib_read_config(sc->sc_dev, bus, slot, 629209908Sraj func, PCIR_INTPIN, 1); 630209908Sraj intline = fsl_pcib_route_int(sc, bus, slot, func, 631209908Sraj intpin); 632209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 633209908Sraj PCIR_INTLINE, intline, 1); 634209908Sraj 635209908Sraj command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; 636209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 637209908Sraj PCIR_COMMAND, command, 1); 638209908Sraj 639209908Sraj /* 640209908Sraj * Handle PCI-PCI bridges 641209908Sraj */ 642209908Sraj class = fsl_pcib_read_config(sc->sc_dev, bus, slot, 643209908Sraj func, PCIR_CLASS, 1); 644209908Sraj subclass = fsl_pcib_read_config(sc->sc_dev, bus, slot, 645209908Sraj func, PCIR_SUBCLASS, 1); 646218075Smarcel 647209908Sraj /* Allow only proper PCI-PCI briges */ 648209908Sraj if (class != PCIC_BRIDGE) 649209908Sraj continue; 650209908Sraj if (subclass != PCIS_BRIDGE_PCI) 651209908Sraj continue; 652209908Sraj 653218075Smarcel secbus++; 654209908Sraj 655209908Sraj /* Program I/O decoder. */ 656209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 657209908Sraj PCIR_IOBASEL_1, sc->sc_ioport.rm_start >> 8, 1); 658209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 659209908Sraj PCIR_IOLIMITL_1, sc->sc_ioport.rm_end >> 8, 1); 660209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 661209908Sraj PCIR_IOBASEH_1, sc->sc_ioport.rm_start >> 16, 2); 662209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 663209908Sraj PCIR_IOLIMITH_1, sc->sc_ioport.rm_end >> 16, 2); 664209908Sraj 665209908Sraj /* Program (non-prefetchable) memory decoder. */ 666209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 667209908Sraj PCIR_MEMBASE_1, sc->sc_iomem.rm_start >> 16, 2); 668209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 669209908Sraj PCIR_MEMLIMIT_1, sc->sc_iomem.rm_end >> 16, 2); 670209908Sraj 671209908Sraj /* Program prefetchable memory decoder. */ 672209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 673209908Sraj PCIR_PMBASEL_1, 0x0010, 2); 674209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 675209908Sraj PCIR_PMLIMITL_1, 0x000f, 2); 676209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 677209908Sraj PCIR_PMBASEH_1, 0x00000000, 4); 678209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 679209908Sraj PCIR_PMLIMITH_1, 0x00000000, 4); 680209908Sraj 681209908Sraj /* Read currect bus register configuration */ 682209908Sraj old_pribus = fsl_pcib_read_config(sc->sc_dev, bus, 683209908Sraj slot, func, PCIR_PRIBUS_1, 1); 684209908Sraj old_secbus = fsl_pcib_read_config(sc->sc_dev, bus, 685209908Sraj slot, func, PCIR_SECBUS_1, 1); 686209908Sraj old_subbus = fsl_pcib_read_config(sc->sc_dev, bus, 687209908Sraj slot, func, PCIR_SUBBUS_1, 1); 688209908Sraj 689209908Sraj if (bootverbose) 690209908Sraj printf("PCI: reading firmware bus numbers for " 691209908Sraj "secbus = %d (bus/sec/sub) = (%d/%d/%d)\n", 692218075Smarcel secbus, old_pribus, old_secbus, old_subbus); 693209908Sraj 694218075Smarcel new_pribus = bus; 695218075Smarcel new_secbus = secbus; 696209908Sraj 697218075Smarcel secbus = fsl_pcib_init(sc, secbus, 698218075Smarcel (subclass == PCIS_BRIDGE_PCI) ? PCI_SLOTMAX : 0); 699209908Sraj 700218075Smarcel new_subbus = secbus; 701209908Sraj 702209908Sraj if (bootverbose) 703218075Smarcel printf("PCI: translate firmware bus numbers " 704218075Smarcel "for secbus %d (%d/%d/%d) -> (%d/%d/%d)\n", 705218075Smarcel secbus, old_pribus, old_secbus, old_subbus, 706209908Sraj new_pribus, new_secbus, new_subbus); 707209908Sraj 708209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 709209908Sraj PCIR_PRIBUS_1, new_pribus, 1); 710209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 711209908Sraj PCIR_SECBUS_1, new_secbus, 1); 712209908Sraj fsl_pcib_write_config(sc->sc_dev, bus, slot, func, 713209908Sraj PCIR_SUBBUS_1, new_subbus, 1); 714209908Sraj } 715209908Sraj } 716209908Sraj 717218075Smarcel return (secbus); 718209908Sraj} 719209908Sraj 720209908Srajstatic void 721209908Srajfsl_pcib_inbound(struct fsl_pcib_softc *sc, int wnd, int tgt, u_long start, 722209908Sraj u_long size, u_long pci_start) 723209908Sraj{ 724209908Sraj uint32_t attr, bar, tar; 725209908Sraj 726209908Sraj KASSERT(wnd > 0, ("%s: inbound window 0 is invalid", __func__)); 727209908Sraj 728209908Sraj switch (tgt) { 729209908Sraj /* XXX OCP85XX_TGTIF_RAM2, OCP85XX_TGTIF_RAM_INTL should be handled */ 730209908Sraj case OCP85XX_TGTIF_RAM1: 731209908Sraj attr = 0xa0f55000 | (ffsl(size) - 2); 732209908Sraj break; 733209908Sraj default: 734209908Sraj attr = 0; 735209908Sraj break; 736209908Sraj } 737209908Sraj tar = start >> 12; 738209908Sraj bar = pci_start >> 12; 739209908Sraj 740209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PITAR(wnd), tar); 741209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBEAR(wnd), 0); 742209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBAR(wnd), bar); 743209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWAR(wnd), attr); 744209908Sraj} 745209908Sraj 746209908Srajstatic void 747209908Srajfsl_pcib_outbound(struct fsl_pcib_softc *sc, int wnd, int res, u_long start, 748209908Sraj u_long size, u_long pci_start) 749209908Sraj{ 750209908Sraj uint32_t attr, bar, tar; 751209908Sraj 752209908Sraj switch (res) { 753209908Sraj case SYS_RES_MEMORY: 754209908Sraj attr = 0x80044000 | (ffsl(size) - 2); 755209908Sraj break; 756209908Sraj case SYS_RES_IOPORT: 757209908Sraj attr = 0x80088000 | (ffsl(size) - 2); 758209908Sraj break; 759209908Sraj default: 760209908Sraj attr = 0x0004401f; 761209908Sraj break; 762209908Sraj } 763209908Sraj bar = start >> 12; 764209908Sraj tar = pci_start >> 12; 765209908Sraj 766209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTAR(wnd), tar); 767209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTEAR(wnd), 0); 768209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWBAR(wnd), bar); 769209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWAR(wnd), attr); 770209908Sraj} 771209908Sraj 772209908Srajstatic int 773209908Srajfsl_pcib_set_range(struct fsl_pcib_softc *sc, int type, int wnd, u_long start, 774209908Sraj u_long size) 775209908Sraj{ 776209908Sraj struct rman *rm; 777209908Sraj u_long end, alloc; 778209908Sraj bus_addr_t pci_start, pci_end; 779209908Sraj bus_addr_t *vap, *allocp; 780209908Sraj int error; 781209908Sraj 782209908Sraj end = start + size - 1; 783209908Sraj 784209908Sraj switch (type) { 785209908Sraj case SYS_RES_IOPORT: 786209908Sraj rm = &sc->sc_ioport; 787209908Sraj pci_start = 0x0000; 788209908Sraj pci_end = 0xffff; 789209908Sraj alloc = 0x1000; 790209908Sraj vap = &sc->sc_ioport_va; 791209908Sraj allocp = &sc->sc_ioport_alloc; 792209908Sraj break; 793209908Sraj case SYS_RES_MEMORY: 794209908Sraj rm = &sc->sc_iomem; 795209908Sraj pci_start = start; 796209908Sraj pci_end = end; 797209908Sraj alloc = 0; 798209908Sraj vap = &sc->sc_iomem_va; 799209908Sraj allocp = &sc->sc_iomem_alloc; 800209908Sraj break; 801209908Sraj default: 802209908Sraj return (EINVAL); 803209908Sraj } 804209908Sraj 805209908Sraj rm->rm_type = RMAN_ARRAY; 806209908Sraj rm->rm_start = pci_start; 807209908Sraj rm->rm_end = pci_end; 808209908Sraj error = rman_init(rm); 809209908Sraj if (error) 810209908Sraj return (error); 811209908Sraj 812209908Sraj error = rman_manage_region(rm, pci_start, pci_end); 813209908Sraj if (error) { 814209908Sraj rman_fini(rm); 815209908Sraj return (error); 816209908Sraj } 817209908Sraj 818209908Sraj *allocp = pci_start + alloc; 819235933Smarcel if (size > 0) { 820235933Smarcel *vap = (uintptr_t)pmap_mapdev(start, size); 821235933Smarcel fsl_pcib_outbound(sc, wnd, type, start, size, pci_start); 822235933Smarcel } else { 823235933Smarcel *vap = 0; 824235933Smarcel fsl_pcib_outbound(sc, wnd, -1, 0, 0, 0); 825235933Smarcel } 826209908Sraj return (0); 827209908Sraj} 828209908Sraj 829209908Srajstatic void 830209908Srajfsl_pcib_err_init(device_t dev) 831209908Sraj{ 832209908Sraj struct fsl_pcib_softc *sc; 833209908Sraj uint16_t sec_stat, dsr; 834209908Sraj uint32_t dcr, err_en; 835209908Sraj 836209908Sraj sc = device_get_softc(dev); 837209908Sraj 838209908Sraj sec_stat = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_SECSTAT_1, 2); 839209908Sraj if (sec_stat) 840209908Sraj fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_SECSTAT_1, 0xffff, 2); 841209908Sraj if (sc->sc_pcie) { 842209908Sraj /* Clear error bits */ 843209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_IER, 844209908Sraj 0xffffffff); 845209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_DR, 846209908Sraj 0xffffffff); 847209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR, 848209908Sraj 0xffffffff); 849209908Sraj 850209908Sraj dsr = fsl_pcib_cfgread(sc, 0, 0, 0, 851240680Sgavin sc->sc_pcie_capreg + PCIER_DEVICE_STA, 2); 852209908Sraj if (dsr) 853209908Sraj fsl_pcib_cfgwrite(sc, 0, 0, 0, 854240680Sgavin sc->sc_pcie_capreg + PCIER_DEVICE_STA, 855209908Sraj 0xffff, 2); 856209908Sraj 857209908Sraj /* Enable all errors reporting */ 858209908Sraj err_en = 0x00bfff00; 859209908Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_EN, 860209908Sraj err_en); 861209908Sraj 862209908Sraj /* Enable error reporting: URR, FER, NFER */ 863209908Sraj dcr = fsl_pcib_cfgread(sc, 0, 0, 0, 864240680Sgavin sc->sc_pcie_capreg + PCIER_DEVICE_CTL, 4); 865240680Sgavin dcr |= PCIEM_CTL_URR_ENABLE | PCIEM_CTL_FER_ENABLE | 866240680Sgavin PCIEM_CTL_NFER_ENABLE; 867209908Sraj fsl_pcib_cfgwrite(sc, 0, 0, 0, 868240680Sgavin sc->sc_pcie_capreg + PCIER_DEVICE_CTL, dcr, 4); 869209908Sraj } 870209908Sraj} 871209908Sraj 872209908Srajstatic int 873209908Srajfsl_pcib_detach(device_t dev) 874209908Sraj{ 875209908Sraj 876209908Sraj if (mtx_initialized) { 877209908Sraj mtx_destroy(&pcicfg_mtx); 878209908Sraj mtx_initialized = 0; 879209908Sraj } 880209908Sraj return (bus_generic_detach(dev)); 881209908Sraj} 882209908Sraj 883209908Srajstatic struct resource * 884209908Srajfsl_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 885209908Sraj u_long start, u_long end, u_long count, u_int flags) 886209908Sraj{ 887209908Sraj struct fsl_pcib_softc *sc = device_get_softc(dev); 888209908Sraj struct rman *rm; 889209908Sraj struct resource *res; 890209908Sraj bus_addr_t va; 891209908Sraj 892209908Sraj switch (type) { 893209908Sraj case SYS_RES_IOPORT: 894209908Sraj rm = &sc->sc_ioport; 895209908Sraj va = sc->sc_ioport_va; 896209908Sraj break; 897209908Sraj case SYS_RES_MEMORY: 898209908Sraj rm = &sc->sc_iomem; 899209908Sraj va = sc->sc_iomem_va; 900209908Sraj break; 901209908Sraj case SYS_RES_IRQ: 902218075Smarcel if (start < 16) { 903209908Sraj device_printf(dev, "%s requested ISA interrupt %lu\n", 904209908Sraj device_get_nameunit(child), start); 905209908Sraj } 906209908Sraj flags |= RF_SHAREABLE; 907209908Sraj return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 908209908Sraj type, rid, start, end, count, flags)); 909209908Sraj default: 910209908Sraj return (NULL); 911209908Sraj } 912209908Sraj 913209908Sraj res = rman_reserve_resource(rm, start, end, count, flags, child); 914209908Sraj if (res == NULL) 915209908Sraj return (NULL); 916209908Sraj 917209908Sraj rman_set_bustag(res, &bs_le_tag); 918209908Sraj rman_set_bushandle(res, va + rman_get_start(res) - rm->rm_start); 919209908Sraj return (res); 920209908Sraj} 921209908Sraj 922209908Srajstatic int 923209908Srajfsl_pcib_release_resource(device_t dev, device_t child, int type, int rid, 924209908Sraj struct resource *res) 925209908Sraj{ 926209908Sraj 927209908Sraj return (rman_release_resource(res)); 928209908Sraj} 929209908Sraj 930209908Srajstatic int 931209908Srajfsl_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 932209908Sraj{ 933209908Sraj struct fsl_pcib_softc *sc = device_get_softc(dev); 934209908Sraj 935209908Sraj switch (which) { 936209908Sraj case PCIB_IVAR_BUS: 937209908Sraj *result = sc->sc_busnr; 938209908Sraj return (0); 939209908Sraj case PCIB_IVAR_DOMAIN: 940209908Sraj *result = device_get_unit(dev); 941209908Sraj return (0); 942209908Sraj } 943209908Sraj return (ENOENT); 944209908Sraj} 945209908Sraj 946209908Srajstatic int 947209908Srajfsl_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 948209908Sraj{ 949209908Sraj struct fsl_pcib_softc *sc = device_get_softc(dev); 950209908Sraj 951209908Sraj switch (which) { 952209908Sraj case PCIB_IVAR_BUS: 953209908Sraj sc->sc_busnr = value; 954209908Sraj return (0); 955209908Sraj } 956209908Sraj return (ENOENT); 957209908Sraj} 958209908Sraj 959209908Srajstatic int 960209908Srajfsl_pcib_intr_info(phandle_t node, struct fsl_pcib_softc *sc) 961209908Sraj{ 962209908Sraj int error; 963209908Sraj 964209908Sraj if ((error = fdt_pci_intr_info(node, &sc->sc_intr_info)) != 0) 965209908Sraj return (error); 966209908Sraj 967209908Sraj return (0); 968209908Sraj} 969209908Sraj 970209908Srajstatic int 971209908Srajfsl_pcib_decode_win(phandle_t node, struct fsl_pcib_softc *sc) 972209908Sraj{ 973209908Sraj struct fdt_pci_range io_space, mem_space; 974209908Sraj device_t dev; 975209908Sraj int error; 976209908Sraj 977209908Sraj dev = sc->sc_dev; 978209908Sraj 979209908Sraj if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) { 980209908Sraj device_printf(dev, "could not retrieve 'ranges' data\n"); 981209908Sraj return (error); 982209908Sraj } 983209908Sraj 984209908Sraj /* 985209908Sraj * Configure LAW decode windows. 986209908Sraj */ 987209908Sraj error = law_pci_target(sc->sc_res, &sc->sc_iomem_target, 988209908Sraj &sc->sc_ioport_target); 989209908Sraj if (error != 0) { 990209908Sraj device_printf(dev, "could not retrieve PCI LAW target info\n"); 991209908Sraj return (error); 992209908Sraj } 993209908Sraj error = law_enable(sc->sc_iomem_target, mem_space.base_parent, 994209908Sraj mem_space.len); 995209908Sraj if (error != 0) { 996209908Sraj device_printf(dev, "could not program LAW for PCI MEM range\n"); 997209908Sraj return (error); 998209908Sraj } 999209908Sraj error = law_enable(sc->sc_ioport_target, io_space.base_parent, 1000209908Sraj io_space.len); 1001209908Sraj if (error != 0) { 1002209908Sraj device_printf(dev, "could not program LAW for PCI IO range\n"); 1003209908Sraj return (error); 1004209908Sraj } 1005209908Sraj 1006209908Sraj /* 1007209908Sraj * Set outbout and inbound windows. 1008209908Sraj */ 1009209908Sraj fsl_pcib_outbound(sc, 0, -1, 0, 0, 0); 1010209908Sraj if ((error = fsl_pcib_set_range(sc, SYS_RES_MEMORY, 1, 1011209908Sraj mem_space.base_parent, mem_space.len)) != 0) 1012209908Sraj return (error); 1013209908Sraj if ((error = fsl_pcib_set_range(sc, SYS_RES_IOPORT, 2, 1014209908Sraj io_space.base_parent, io_space.len)) != 0) 1015209908Sraj return (error); 1016209908Sraj 1017209908Sraj fsl_pcib_outbound(sc, 3, -1, 0, 0, 0); 1018209908Sraj fsl_pcib_outbound(sc, 4, -1, 0, 0, 0); 1019209908Sraj 1020209908Sraj fsl_pcib_inbound(sc, 1, -1, 0, 0, 0); 1021209908Sraj fsl_pcib_inbound(sc, 2, -1, 0, 0, 0); 1022209908Sraj fsl_pcib_inbound(sc, 3, OCP85XX_TGTIF_RAM1, 0, 1023209908Sraj 2U * 1024U * 1024U * 1024U, 0); 1024209908Sraj 1025209908Sraj return (0); 1026209908Sraj} 1027