1/*- 2 * Copyright (c) 2007 Bruce M. Simpson. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * Child driver for PCI host bridge core. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/bus.h> 37#include <sys/kernel.h> 38#include <sys/module.h> 39#include <sys/rman.h> 40#include <sys/malloc.h> 41#include <sys/endian.h> 42 43#include <vm/vm.h> 44#include <vm/pmap.h> 45#include <vm/vm_extern.h> 46 47#include <machine/bus.h> 48#include <machine/cpu.h> 49#include <machine/pcb.h> 50#include <machine/pmap.h> 51 52#include <dev/pci/pcireg.h> 53#include <dev/pci/pcivar.h> 54#include <dev/pci/pcib_private.h> 55 56#include "pcib_if.h" 57 58#include <dev/siba/siba_ids.h> 59#include <dev/siba/sibareg.h> 60#include <dev/siba/sibavar.h> 61#include <dev/siba/siba_pcibvar.h> 62 63#ifndef MIPS_MEM_RID 64#define MIPS_MEM_RID 0x20 65#endif 66 67#define SBPCI_SLOTMAX 15 68 69#define SBPCI_READ_4(sc, reg) \ 70 bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg)) 71 72#define SBPCI_WRITE_4(sc, reg, val) \ 73 bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg), (val)) 74 75/* 76 * PCI Configuration space window (64MB). 77 * contained in SBTOPCI1 window. 78 */ 79#define SBPCI_CFGBASE 0x0C000000 80#define SBPCI_CFGSIZE 0x01000000 81 82/* 83 * TODO: implement type 1 config space access (ie beyond bus 0) 84 * we may need to tweak the windows to do this 85 * TODO: interrupt routing. 86 * TODO: fully implement bus allocation. 87 * TODO: implement resource managers. 88 * TODO: code cleanup. 89 */ 90 91static int siba_pcib_activate_resource(device_t, device_t, int, 92 int, struct resource *); 93static struct resource * 94 siba_pcib_alloc_resource(device_t, device_t, int, int *, 95 u_long , u_long, u_long, u_int); 96static int siba_pcib_attach(device_t); 97static int siba_pcib_deactivate_resource(device_t, device_t, int, 98 int, struct resource *); 99static int siba_pcib_maxslots(device_t); 100static int siba_pcib_probe(device_t); 101static u_int32_t 102 siba_pcib_read_config(device_t, u_int, u_int, u_int, u_int, 103 int); 104static int siba_pcib_read_ivar(device_t, device_t, int, uintptr_t *); 105static int siba_pcib_release_resource(device_t, device_t, int, int, 106 struct resource *); 107static int siba_pcib_route_interrupt(device_t, device_t, int); 108static int siba_pcib_setup_intr(device_t, device_t, struct resource *, 109 int, driver_filter_t *, driver_intr_t *, void *, void **); 110static int siba_pcib_teardown_intr(device_t, device_t, struct resource *, 111 void *); 112static void siba_pcib_write_config(device_t, u_int, u_int, u_int, u_int, 113 u_int32_t, int); 114static int siba_pcib_write_ivar(device_t, device_t, int, uintptr_t); 115 116static int 117siba_pcib_probe(device_t dev) 118{ 119 120 /* TODO: support earlier cores. */ 121 /* TODO: Check if PCI host mode is enabled in the SPROM. */ 122 if (siba_get_vendor(dev) == SIBA_VID_BROADCOM && 123 siba_get_device(dev) == SIBA_DEVID_PCI) { 124 device_set_desc(dev, "SiBa-to-PCI host bridge"); 125 return (BUS_PROBE_DEFAULT); 126 } 127 128 return (ENXIO); 129} 130 131//extern int rman_debug; 132 133static int 134siba_pcib_attach(device_t dev) 135{ 136 struct siba_pcib_softc *sc = device_get_softc(dev); 137 int rid; 138 139 /* 140 * Allocate the resources which the parent bus has already 141 * determined for us. 142 */ 143 rid = MIPS_MEM_RID; /* XXX */ 144 //rman_debug = 1; 145 sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 146 RF_ACTIVE); 147 if (sc->sc_mem == NULL) { 148 device_printf(dev, "unable to allocate memory\n"); 149 return (ENXIO); 150 } 151 152 sc->sc_bt = rman_get_bustag(sc->sc_mem); 153 sc->sc_bh = rman_get_bushandle(sc->sc_mem); 154 155 device_printf(dev, "bridge registers addr 0x%08x vaddr %p\n", 156 (uint32_t)sc->sc_bh, rman_get_virtual(sc->sc_mem)); 157 158 SBPCI_WRITE_4(sc, 0x0000, 0x05); 159 SBPCI_WRITE_4(sc, 0x0000, 0x0D); 160 DELAY(150); 161 SBPCI_WRITE_4(sc, 0x0000, 0x0F); 162 SBPCI_WRITE_4(sc, 0x0010, 0x01); 163 DELAY(1); 164 165 bus_space_handle_t sc_cfg_hand; 166 int error; 167 168 /* 169 * XXX this doesn't actually do anything on mips; however... should 170 * we not be mapping to KSEG1? we need to wire down the range. 171 */ 172 error = bus_space_map(sc->sc_bt, SBPCI_CFGBASE, SBPCI_CFGSIZE, 173 0, &sc_cfg_hand); 174 if (error) { 175 device_printf(dev, "cannot map PCI configuration space\n"); 176 return (ENXIO); 177 } 178 device_printf(dev, "mapped pci config space at 0x%08x\n", 179 (uint32_t)sc_cfg_hand); 180 181 /* 182 * Setup configuration, io, and dma space windows. 183 * XXX we need to be able to do type 1 too. 184 * we probably don't need to be able to do i/o cycles. 185 */ 186 187 /* I/O read/write window */ 188 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI0, 1); 189 /* type 0 configuration only */ 190 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2); 191 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI2, 1 << 30); /* memory only */ 192 DELAY(500); 193 194 /* XXX resource managers */ 195 196 device_add_child(dev, "pci", -1); 197 return (bus_generic_attach(dev)); 198} 199 200/* bus functions */ 201 202static int 203siba_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 204{ 205 struct siba_pcib_softc *sc; 206 207 sc = device_get_softc(dev); 208 switch (which) { 209 case PCIB_IVAR_BUS: 210 *result = sc->sc_bus; 211 return (0); 212 } 213 214 return (ENOENT); 215} 216 217static int 218siba_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 219{ 220 struct siba_pcib_softc *sc; 221 222 sc = device_get_softc(dev); 223 switch (which) { 224 case PCIB_IVAR_BUS: 225 sc->sc_bus = value; 226 return (0); 227 } 228 229 return (ENOENT); 230} 231 232static int 233siba_pcib_setup_intr(device_t dev, device_t child, struct resource *ires, 234 int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 235 void **cookiep) 236{ 237 238 return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 239 filt, intr, arg, cookiep)); 240} 241 242static int 243siba_pcib_teardown_intr(device_t dev, device_t child, struct resource *vec, 244 void *cookie) 245{ 246 247 return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, cookie)); 248} 249 250static struct resource * 251siba_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid, 252 u_long start, u_long end, u_long count, u_int flags) 253{ 254#if 1 255 256 //device_printf(bus, "%s: not yet implemented\n", __func__); 257 return (NULL); 258#else 259 bus_space_tag_t tag; 260 struct siba_pcib_softc *sc = device_get_softc(bus); 261 struct rman *rmanp; 262 struct resource *rv; 263 264 tag = 0; 265 rv = NULL; 266 switch (type) { 267 case SYS_RES_IRQ: 268 rmanp = &sc->sc_irq_rman; 269 break; 270 271 case SYS_RES_MEMORY: 272 rmanp = &sc->sc_mem_rman; 273 tag = &sc->sc_pci_memt; 274 break; 275 276 default: 277 return (rv); 278 } 279 280 rv = rman_reserve_resource(rmanp, start, end, count, flags, child); 281 if (rv != NULL) { 282 rman_set_rid(rv, *rid); 283 if (type == SYS_RES_MEMORY) { 284#if 0 285 rman_set_bustag(rv, tag); 286 rman_set_bushandle(rv, rman_get_bushandle(sc->sc_mem) + 287 (rman_get_start(rv) - IXP425_PCI_MEM_HWBASE)); 288#endif 289 } 290 } 291 292 return (rv); 293#endif 294} 295 296static int 297siba_pcib_activate_resource(device_t bus, device_t child, int type, int rid, 298 struct resource *r) 299{ 300 301 device_printf(bus, "%s: not yet implemented\n", __func__); 302 device_printf(bus, "%s called activate_resource\n", 303 device_get_nameunit(child)); 304 return (ENXIO); 305} 306 307static int 308siba_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid, 309 struct resource *r) 310{ 311 312 device_printf(bus, "%s: not yet implemented\n", __func__); 313 device_printf(bus, "%s called deactivate_resource\n", 314 device_get_nameunit(child)); 315 return (ENXIO); 316} 317 318static int 319siba_pcib_release_resource(device_t bus, device_t child, int type, int rid, 320 struct resource *r) 321{ 322 323 device_printf(bus, "%s: not yet implemented\n", __func__); 324 device_printf(bus, "%s called release_resource\n", 325 device_get_nameunit(child)); 326 return (ENXIO); 327} 328 329/* pcib interface functions */ 330 331static int 332siba_pcib_maxslots(device_t dev) 333{ 334 335 return (SBPCI_SLOTMAX); 336} 337 338/* 339 * This needs hacking and fixery. It is currently broke and hangs. 340 * Debugging it will be tricky; there seems to be no way to enable 341 * a target abort which would cause a nice target abort. 342 * Look at linux again? 343 */ 344static u_int32_t 345siba_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 346 u_int reg, int bytes) 347{ 348 struct siba_pcib_softc *sc = device_get_softc(dev); 349 bus_addr_t cfgaddr; 350 uint32_t cfgtag; 351 uint32_t val; 352 353 /* XXX anything higher than slot 2 currently seems to hang the bus. 354 * not sure why this is; look at linux again 355 */ 356 if (bus != 0 || slot > 2) { 357 printf("%s: bad b/s/f %d/%d/%d\n", __func__, bus, slot, func); 358 return 0xffffffff; // XXX 359 } 360 361 device_printf(dev, "requested %d bytes from b/s/f %d/%d/%d reg %d\n", 362 bytes, bus, slot, func, reg); 363 364 /* 365 * The configuration tag on the broadcom is weird. 366 */ 367 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2); /* XXX again??? */ 368 cfgtag = ((1 << slot) << 16) | (func << 8); 369 cfgaddr = SBPCI_CFGBASE | cfgtag | (reg & ~3); 370 371 /* cfg space i/o is always 32 bits on this bridge */ 372 printf("reading 4 bytes from %08x\n", cfgaddr); 373 val = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(cfgaddr); /* XXX MIPS */ 374 375 val = bswap32(val); /* XXX seems to be needed for now */ 376 377 /* swizzle and return what was asked for */ 378 val &= 0xffffffff >> ((4 - bytes) * 8); 379 380 return (val); 381} 382 383static void 384siba_pcib_write_config(device_t dev, u_int bus, u_int slot, 385 u_int func, u_int reg, u_int32_t val, int bytes) 386{ 387 388 /* write to pci configuration space */ 389 //device_printf(dev, "%s: not yet implemented\n", __func__); 390} 391 392static int 393siba_pcib_route_interrupt(device_t bridge, device_t device, int pin) 394{ 395 396 //device_printf(bridge, "%s: not yet implemented\n", __func__); 397 return (-1); 398} 399 400static device_method_t siba_pcib_methods[] = { 401 /* Device interface */ 402 DEVMETHOD(device_attach, siba_pcib_attach), 403 DEVMETHOD(device_probe, siba_pcib_probe), 404 405 /* Bus interface */ 406 DEVMETHOD(bus_read_ivar, siba_pcib_read_ivar), 407 DEVMETHOD(bus_write_ivar, siba_pcib_write_ivar), 408 DEVMETHOD(bus_setup_intr, siba_pcib_setup_intr), 409 DEVMETHOD(bus_teardown_intr, siba_pcib_teardown_intr), 410 DEVMETHOD(bus_alloc_resource, siba_pcib_alloc_resource), 411 DEVMETHOD(bus_activate_resource, siba_pcib_activate_resource), 412 DEVMETHOD(bus_deactivate_resource, siba_pcib_deactivate_resource), 413 DEVMETHOD(bus_release_resource, siba_pcib_release_resource), 414 415 /* pcib interface */ 416 DEVMETHOD(pcib_maxslots, siba_pcib_maxslots), 417 DEVMETHOD(pcib_read_config, siba_pcib_read_config), 418 DEVMETHOD(pcib_write_config, siba_pcib_write_config), 419 DEVMETHOD(pcib_route_interrupt, siba_pcib_route_interrupt), 420 421 DEVMETHOD_END 422}; 423 424static driver_t siba_pcib_driver = { 425 "pcib", 426 siba_pcib_methods, 427 sizeof(struct siba_softc), 428}; 429static devclass_t siba_pcib_devclass; 430 431DRIVER_MODULE(siba_pcib, siba, siba_pcib_driver, siba_pcib_devclass, 0, 0); 432