1183371Simp/*- 2183371Simp * Copyright (c) 2007 Bruce M. Simpson. 3183371Simp * All rights reserved. 4183371Simp * 5183371Simp * Redistribution and use in source and binary forms, with or without 6183371Simp * modification, are permitted provided that the following conditions 7183371Simp * are met: 8183371Simp * 1. Redistributions of source code must retain the above copyright 9183371Simp * notice, this list of conditions and the following disclaimer. 10183371Simp * 2. Redistributions in binary form must reproduce the above copyright 11183371Simp * notice, this list of conditions and the following disclaimer in the 12183371Simp * documentation and/or other materials provided with the distribution. 13183371Simp * 14183371Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15183371Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16183371Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17183371Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18183371Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19183371Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20183371Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21183371Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22183371Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23183371Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24183371Simp * SUCH DAMAGE. 25183371Simp */ 26183371Simp 27183371Simp/* 28183371Simp * Child driver for PCI host bridge core. 29183371Simp */ 30183371Simp 31183371Simp#include <sys/cdefs.h> 32183371Simp__FBSDID("$FreeBSD$"); 33183371Simp 34183371Simp#include <sys/param.h> 35183371Simp#include <sys/systm.h> 36183371Simp#include <sys/bus.h> 37183371Simp#include <sys/kernel.h> 38183371Simp#include <sys/module.h> 39183371Simp#include <sys/rman.h> 40183371Simp#include <sys/malloc.h> 41183371Simp#include <sys/endian.h> 42183371Simp 43183371Simp#include <vm/vm.h> 44183371Simp#include <vm/pmap.h> 45183371Simp#include <vm/vm_extern.h> 46183371Simp 47183371Simp#include <machine/bus.h> 48183371Simp#include <machine/cpu.h> 49183371Simp#include <machine/pcb.h> 50183371Simp#include <machine/pmap.h> 51183371Simp 52183371Simp#include <dev/pci/pcireg.h> 53183371Simp#include <dev/pci/pcivar.h> 54183371Simp#include <dev/pci/pcib_private.h> 55183371Simp 56183371Simp#include "pcib_if.h" 57183371Simp 58203319Sweongyo#include <dev/siba/siba_ids.h> 59203319Sweongyo#include <dev/siba/sibareg.h> 60183371Simp#include <dev/siba/sibavar.h> 61183371Simp#include <dev/siba/siba_pcibvar.h> 62183371Simp 63183371Simp#ifndef MIPS_MEM_RID 64183371Simp#define MIPS_MEM_RID 0x20 65183371Simp#endif 66183371Simp 67183371Simp#define SBPCI_SLOTMAX 15 68183371Simp 69183371Simp#define SBPCI_READ_4(sc, reg) \ 70183371Simp bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg)) 71183371Simp 72183371Simp#define SBPCI_WRITE_4(sc, reg, val) \ 73183371Simp bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg), (val)) 74183371Simp 75183371Simp/* 76183371Simp * PCI Configuration space window (64MB). 77183371Simp * contained in SBTOPCI1 window. 78183371Simp */ 79183371Simp#define SBPCI_CFGBASE 0x0C000000 80183371Simp#define SBPCI_CFGSIZE 0x01000000 81183371Simp 82183371Simp/* 83183371Simp * TODO: implement type 1 config space access (ie beyond bus 0) 84183371Simp * we may need to tweak the windows to do this 85183371Simp * TODO: interrupt routing. 86183371Simp * TODO: fully implement bus allocation. 87183371Simp * TODO: implement resource managers. 88183371Simp * TODO: code cleanup. 89183371Simp */ 90183371Simp 91183371Simpstatic int siba_pcib_activate_resource(device_t, device_t, int, 92183371Simp int, struct resource *); 93183371Simpstatic struct resource * 94183371Simp siba_pcib_alloc_resource(device_t, device_t, int, int *, 95183371Simp u_long , u_long, u_long, u_int); 96183371Simpstatic int siba_pcib_attach(device_t); 97183371Simpstatic int siba_pcib_deactivate_resource(device_t, device_t, int, 98183371Simp int, struct resource *); 99183371Simpstatic int siba_pcib_maxslots(device_t); 100183371Simpstatic int siba_pcib_probe(device_t); 101183371Simpstatic u_int32_t 102183371Simp siba_pcib_read_config(device_t, u_int, u_int, u_int, u_int, 103183371Simp int); 104183371Simpstatic int siba_pcib_read_ivar(device_t, device_t, int, uintptr_t *); 105183371Simpstatic int siba_pcib_release_resource(device_t, device_t, int, int, 106183371Simp struct resource *); 107183371Simpstatic int siba_pcib_route_interrupt(device_t, device_t, int); 108183371Simpstatic int siba_pcib_setup_intr(device_t, device_t, struct resource *, 109183371Simp int, driver_filter_t *, driver_intr_t *, void *, void **); 110183371Simpstatic int siba_pcib_teardown_intr(device_t, device_t, struct resource *, 111183371Simp void *); 112183371Simpstatic void siba_pcib_write_config(device_t, u_int, u_int, u_int, u_int, 113183371Simp u_int32_t, int); 114183371Simpstatic int siba_pcib_write_ivar(device_t, device_t, int, uintptr_t); 115183371Simp 116183371Simpstatic int 117183371Simpsiba_pcib_probe(device_t dev) 118183371Simp{ 119183371Simp 120183371Simp /* TODO: support earlier cores. */ 121183371Simp /* TODO: Check if PCI host mode is enabled in the SPROM. */ 122183371Simp if (siba_get_vendor(dev) == SIBA_VID_BROADCOM && 123183371Simp siba_get_device(dev) == SIBA_DEVID_PCI) { 124183371Simp device_set_desc(dev, "SiBa-to-PCI host bridge"); 125183371Simp return (BUS_PROBE_DEFAULT); 126183371Simp } 127183371Simp 128183371Simp return (ENXIO); 129183371Simp} 130183371Simp 131183371Simp//extern int rman_debug; 132183371Simp 133183371Simpstatic int 134183371Simpsiba_pcib_attach(device_t dev) 135183371Simp{ 136183371Simp struct siba_pcib_softc *sc = device_get_softc(dev); 137183371Simp int rid; 138183371Simp 139183371Simp /* 140183371Simp * Allocate the resources which the parent bus has already 141183371Simp * determined for us. 142183371Simp */ 143183371Simp rid = MIPS_MEM_RID; /* XXX */ 144183371Simp //rman_debug = 1; 145183371Simp sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 146183371Simp RF_ACTIVE); 147183371Simp if (sc->sc_mem == NULL) { 148183371Simp device_printf(dev, "unable to allocate memory\n"); 149183371Simp return (ENXIO); 150183371Simp } 151183371Simp 152183371Simp sc->sc_bt = rman_get_bustag(sc->sc_mem); 153183371Simp sc->sc_bh = rman_get_bushandle(sc->sc_mem); 154183371Simp 155183371Simp device_printf(dev, "bridge registers addr 0x%08x vaddr %p\n", 156183377Simp (uint32_t)sc->sc_bh, rman_get_virtual(sc->sc_mem)); 157183371Simp 158183371Simp SBPCI_WRITE_4(sc, 0x0000, 0x05); 159183371Simp SBPCI_WRITE_4(sc, 0x0000, 0x0D); 160183371Simp DELAY(150); 161183371Simp SBPCI_WRITE_4(sc, 0x0000, 0x0F); 162183371Simp SBPCI_WRITE_4(sc, 0x0010, 0x01); 163183371Simp DELAY(1); 164183371Simp 165183371Simp bus_space_handle_t sc_cfg_hand; 166183371Simp int error; 167183371Simp 168183371Simp /* 169183371Simp * XXX this doesn't actually do anything on mips; however... should 170183371Simp * we not be mapping to KSEG1? we need to wire down the range. 171183371Simp */ 172183371Simp error = bus_space_map(sc->sc_bt, SBPCI_CFGBASE, SBPCI_CFGSIZE, 173183371Simp 0, &sc_cfg_hand); 174183371Simp if (error) { 175183371Simp device_printf(dev, "cannot map PCI configuration space\n"); 176183371Simp return (ENXIO); 177183371Simp } 178183377Simp device_printf(dev, "mapped pci config space at 0x%08x\n", 179183377Simp (uint32_t)sc_cfg_hand); 180183371Simp 181183371Simp /* 182183371Simp * Setup configuration, io, and dma space windows. 183183371Simp * XXX we need to be able to do type 1 too. 184183371Simp * we probably don't need to be able to do i/o cycles. 185183371Simp */ 186203319Sweongyo 187203319Sweongyo /* I/O read/write window */ 188203319Sweongyo SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI0, 1); 189203319Sweongyo /* type 0 configuration only */ 190203319Sweongyo SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2); 191203319Sweongyo SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI2, 1 << 30); /* memory only */ 192183371Simp DELAY(500); 193183371Simp 194183371Simp /* XXX resource managers */ 195183371Simp 196183371Simp device_add_child(dev, "pci", -1); 197183371Simp return (bus_generic_attach(dev)); 198183371Simp} 199183371Simp 200183371Simp/* bus functions */ 201183371Simp 202183371Simpstatic int 203183371Simpsiba_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 204183371Simp{ 205183371Simp struct siba_pcib_softc *sc; 206183371Simp 207183371Simp sc = device_get_softc(dev); 208183371Simp switch (which) { 209183371Simp case PCIB_IVAR_BUS: 210183371Simp *result = sc->sc_bus; 211183371Simp return (0); 212183371Simp } 213183371Simp 214183371Simp return (ENOENT); 215183371Simp} 216183371Simp 217183371Simpstatic int 218183371Simpsiba_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 219183371Simp{ 220183371Simp struct siba_pcib_softc *sc; 221183371Simp 222183371Simp sc = device_get_softc(dev); 223183371Simp switch (which) { 224183371Simp case PCIB_IVAR_BUS: 225183371Simp sc->sc_bus = value; 226183371Simp return (0); 227183371Simp } 228183371Simp 229183371Simp return (ENOENT); 230183371Simp} 231183371Simp 232183371Simpstatic int 233183371Simpsiba_pcib_setup_intr(device_t dev, device_t child, struct resource *ires, 234183371Simp int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 235183371Simp void **cookiep) 236183371Simp{ 237183371Simp 238183371Simp return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 239183371Simp filt, intr, arg, cookiep)); 240183371Simp} 241183371Simp 242183371Simpstatic int 243183371Simpsiba_pcib_teardown_intr(device_t dev, device_t child, struct resource *vec, 244183371Simp void *cookie) 245183371Simp{ 246183371Simp 247183371Simp return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, cookie)); 248183371Simp} 249183371Simp 250183371Simpstatic struct resource * 251183371Simpsiba_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid, 252183371Simp u_long start, u_long end, u_long count, u_int flags) 253183371Simp{ 254183371Simp#if 1 255183371Simp 256183371Simp //device_printf(bus, "%s: not yet implemented\n", __func__); 257183371Simp return (NULL); 258183371Simp#else 259183371Simp bus_space_tag_t tag; 260183371Simp struct siba_pcib_softc *sc = device_get_softc(bus); 261183371Simp struct rman *rmanp; 262183371Simp struct resource *rv; 263183371Simp 264183371Simp tag = 0; 265183371Simp rv = NULL; 266183371Simp switch (type) { 267183371Simp case SYS_RES_IRQ: 268183371Simp rmanp = &sc->sc_irq_rman; 269183371Simp break; 270183371Simp 271183371Simp case SYS_RES_MEMORY: 272183371Simp rmanp = &sc->sc_mem_rman; 273183371Simp tag = &sc->sc_pci_memt; 274183371Simp break; 275183371Simp 276183371Simp default: 277183371Simp return (rv); 278183371Simp } 279183371Simp 280183371Simp rv = rman_reserve_resource(rmanp, start, end, count, flags, child); 281183371Simp if (rv != NULL) { 282183371Simp rman_set_rid(rv, *rid); 283183371Simp if (type == SYS_RES_MEMORY) { 284183371Simp#if 0 285183371Simp rman_set_bustag(rv, tag); 286183371Simp rman_set_bushandle(rv, rman_get_bushandle(sc->sc_mem) + 287183371Simp (rman_get_start(rv) - IXP425_PCI_MEM_HWBASE)); 288183371Simp#endif 289183371Simp } 290183371Simp } 291183371Simp 292183371Simp return (rv); 293183371Simp#endif 294183371Simp} 295183371Simp 296183371Simpstatic int 297183371Simpsiba_pcib_activate_resource(device_t bus, device_t child, int type, int rid, 298183371Simp struct resource *r) 299183371Simp{ 300183371Simp 301183371Simp device_printf(bus, "%s: not yet implemented\n", __func__); 302183371Simp device_printf(bus, "%s called activate_resource\n", 303183371Simp device_get_nameunit(child)); 304183371Simp return (ENXIO); 305183371Simp} 306183371Simp 307183371Simpstatic int 308183371Simpsiba_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid, 309183371Simp struct resource *r) 310183371Simp{ 311183371Simp 312183371Simp device_printf(bus, "%s: not yet implemented\n", __func__); 313183371Simp device_printf(bus, "%s called deactivate_resource\n", 314183371Simp device_get_nameunit(child)); 315183371Simp return (ENXIO); 316183371Simp} 317183371Simp 318183371Simpstatic int 319183371Simpsiba_pcib_release_resource(device_t bus, device_t child, int type, int rid, 320183371Simp struct resource *r) 321183371Simp{ 322183371Simp 323183371Simp device_printf(bus, "%s: not yet implemented\n", __func__); 324183371Simp device_printf(bus, "%s called release_resource\n", 325183371Simp device_get_nameunit(child)); 326183371Simp return (ENXIO); 327183371Simp} 328183371Simp 329183371Simp/* pcib interface functions */ 330183371Simp 331183371Simpstatic int 332183371Simpsiba_pcib_maxslots(device_t dev) 333183371Simp{ 334183371Simp 335183371Simp return (SBPCI_SLOTMAX); 336183371Simp} 337183371Simp 338183371Simp/* 339183371Simp * This needs hacking and fixery. It is currently broke and hangs. 340183371Simp * Debugging it will be tricky; there seems to be no way to enable 341183371Simp * a target abort which would cause a nice target abort. 342183371Simp * Look at linux again? 343183371Simp */ 344183371Simpstatic u_int32_t 345183371Simpsiba_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 346183371Simp u_int reg, int bytes) 347183371Simp{ 348183371Simp struct siba_pcib_softc *sc = device_get_softc(dev); 349183371Simp bus_addr_t cfgaddr; 350183371Simp uint32_t cfgtag; 351183371Simp uint32_t val; 352183371Simp 353183371Simp /* XXX anything higher than slot 2 currently seems to hang the bus. 354183371Simp * not sure why this is; look at linux again 355183371Simp */ 356183371Simp if (bus != 0 || slot > 2) { 357183371Simp printf("%s: bad b/s/f %d/%d/%d\n", __func__, bus, slot, func); 358183371Simp return 0xffffffff; // XXX 359183371Simp } 360183371Simp 361183371Simp device_printf(dev, "requested %d bytes from b/s/f %d/%d/%d reg %d\n", 362183371Simp bytes, bus, slot, func, reg); 363183371Simp 364183371Simp /* 365183371Simp * The configuration tag on the broadcom is weird. 366183371Simp */ 367203319Sweongyo SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2); /* XXX again??? */ 368183371Simp cfgtag = ((1 << slot) << 16) | (func << 8); 369183371Simp cfgaddr = SBPCI_CFGBASE | cfgtag | (reg & ~3); 370183371Simp 371183371Simp /* cfg space i/o is always 32 bits on this bridge */ 372183371Simp printf("reading 4 bytes from %08x\n", cfgaddr); 373183371Simp val = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(cfgaddr); /* XXX MIPS */ 374183371Simp 375183371Simp val = bswap32(val); /* XXX seems to be needed for now */ 376183371Simp 377183371Simp /* swizzle and return what was asked for */ 378183371Simp val &= 0xffffffff >> ((4 - bytes) * 8); 379183371Simp 380183371Simp return (val); 381183371Simp} 382183371Simp 383183371Simpstatic void 384183371Simpsiba_pcib_write_config(device_t dev, u_int bus, u_int slot, 385183371Simp u_int func, u_int reg, u_int32_t val, int bytes) 386183371Simp{ 387183371Simp 388183371Simp /* write to pci configuration space */ 389183371Simp //device_printf(dev, "%s: not yet implemented\n", __func__); 390183371Simp} 391183371Simp 392183371Simpstatic int 393183371Simpsiba_pcib_route_interrupt(device_t bridge, device_t device, int pin) 394183371Simp{ 395183371Simp 396183371Simp //device_printf(bridge, "%s: not yet implemented\n", __func__); 397183371Simp return (-1); 398183371Simp} 399183371Simp 400183371Simpstatic device_method_t siba_pcib_methods[] = { 401183371Simp /* Device interface */ 402183371Simp DEVMETHOD(device_attach, siba_pcib_attach), 403183371Simp DEVMETHOD(device_probe, siba_pcib_probe), 404183371Simp 405183371Simp /* Bus interface */ 406183371Simp DEVMETHOD(bus_read_ivar, siba_pcib_read_ivar), 407183371Simp DEVMETHOD(bus_write_ivar, siba_pcib_write_ivar), 408183371Simp DEVMETHOD(bus_setup_intr, siba_pcib_setup_intr), 409183371Simp DEVMETHOD(bus_teardown_intr, siba_pcib_teardown_intr), 410183371Simp DEVMETHOD(bus_alloc_resource, siba_pcib_alloc_resource), 411183371Simp DEVMETHOD(bus_activate_resource, siba_pcib_activate_resource), 412183371Simp DEVMETHOD(bus_deactivate_resource, siba_pcib_deactivate_resource), 413183371Simp DEVMETHOD(bus_release_resource, siba_pcib_release_resource), 414183371Simp 415183371Simp /* pcib interface */ 416183371Simp DEVMETHOD(pcib_maxslots, siba_pcib_maxslots), 417183371Simp DEVMETHOD(pcib_read_config, siba_pcib_read_config), 418183371Simp DEVMETHOD(pcib_write_config, siba_pcib_write_config), 419183371Simp DEVMETHOD(pcib_route_interrupt, siba_pcib_route_interrupt), 420183371Simp 421227843Smarius DEVMETHOD_END 422183371Simp}; 423183371Simp 424183371Simpstatic driver_t siba_pcib_driver = { 425183371Simp "pcib", 426183371Simp siba_pcib_methods, 427183371Simp sizeof(struct siba_softc), 428183371Simp}; 429183371Simpstatic devclass_t siba_pcib_devclass; 430183371Simp 431183371SimpDRIVER_MODULE(siba_pcib, siba, siba_pcib_driver, siba_pcib_devclass, 0, 0); 432