2 * Copyright (c) 2007 Bruce M. Simpson.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 * Child driver for PCI host bridge core.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
40 #include <sys/malloc.h>
41 #include <sys/endian.h>
45 #include <vm/vm_extern.h>
47 #include <machine/bus.h>
48 #include <machine/cpu.h>
49 #include <machine/pcb.h>
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
53 #include <dev/pci/pcib_private.h>
57 #include <dev/siba/siba_ids.h>
58 #include <dev/siba/sibareg.h>
59 #include <dev/siba/sibavar.h>
60 #include <dev/siba/siba_pcibvar.h>
63 #define MIPS_MEM_RID 0x20
66 #define SBPCI_SLOTMAX 15
68 #define SBPCI_READ_4(sc, reg) \
69 bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg))
71 #define SBPCI_WRITE_4(sc, reg, val) \
72 bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg), (val))
75 * PCI Configuration space window (64MB).
76 * contained in SBTOPCI1 window.
78 #define SBPCI_CFGBASE 0x0C000000
79 #define SBPCI_CFGSIZE 0x01000000
82 * TODO: implement type 1 config space access (ie beyond bus 0)
83 * we may need to tweak the windows to do this
84 * TODO: interrupt routing.
85 * TODO: fully implement bus allocation.
86 * TODO: implement resource managers.
90 static int siba_pcib_activate_resource(device_t, device_t, int,
91 int, struct resource *);
92 static struct resource *
93 siba_pcib_alloc_resource(device_t, device_t, int, int *,
94 rman_res_t , rman_res_t, rman_res_t, u_int);
95 static int siba_pcib_attach(device_t);
96 static int siba_pcib_deactivate_resource(device_t, device_t, int,
97 int, struct resource *);
98 static int siba_pcib_maxslots(device_t);
99 static int siba_pcib_probe(device_t);
101 siba_pcib_read_config(device_t, u_int, u_int, u_int, u_int,
103 static int siba_pcib_read_ivar(device_t, device_t, int, uintptr_t *);
104 static int siba_pcib_release_resource(device_t, device_t, int, int,
106 static int siba_pcib_route_interrupt(device_t, device_t, int);
107 static int siba_pcib_setup_intr(device_t, device_t, struct resource *,
108 int, driver_filter_t *, driver_intr_t *, void *, void **);
109 static int siba_pcib_teardown_intr(device_t, device_t, struct resource *,
111 static void siba_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
113 static int siba_pcib_write_ivar(device_t, device_t, int, uintptr_t);
116 siba_pcib_probe(device_t dev)
119 /* TODO: support earlier cores. */
120 /* TODO: Check if PCI host mode is enabled in the SPROM. */
121 if (siba_get_vendor(dev) == SIBA_VID_BROADCOM &&
122 siba_get_device(dev) == SIBA_DEVID_PCI) {
123 device_set_desc(dev, "SiBa-to-PCI host bridge");
124 return (BUS_PROBE_DEFAULT);
130 //extern int rman_debug;
133 siba_pcib_attach(device_t dev)
135 struct siba_pcib_softc *sc = device_get_softc(dev);
139 * Allocate the resources which the parent bus has already
142 rid = MIPS_MEM_RID; /* XXX */
144 sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
146 if (sc->sc_mem == NULL) {
147 device_printf(dev, "unable to allocate memory\n");
151 sc->sc_bt = rman_get_bustag(sc->sc_mem);
152 sc->sc_bh = rman_get_bushandle(sc->sc_mem);
154 device_printf(dev, "bridge registers addr 0x%08x vaddr %p\n",
155 (uint32_t)sc->sc_bh, rman_get_virtual(sc->sc_mem));
157 SBPCI_WRITE_4(sc, 0x0000, 0x05);
158 SBPCI_WRITE_4(sc, 0x0000, 0x0D);
160 SBPCI_WRITE_4(sc, 0x0000, 0x0F);
161 SBPCI_WRITE_4(sc, 0x0010, 0x01);
164 bus_space_handle_t sc_cfg_hand;
168 * XXX this doesn't actually do anything on mips; however... should
169 * we not be mapping to KSEG1? we need to wire down the range.
171 error = bus_space_map(sc->sc_bt, SBPCI_CFGBASE, SBPCI_CFGSIZE,
174 device_printf(dev, "cannot map PCI configuration space\n");
177 device_printf(dev, "mapped pci config space at 0x%08x\n",
178 (uint32_t)sc_cfg_hand);
181 * Setup configuration, io, and dma space windows.
182 * XXX we need to be able to do type 1 too.
183 * we probably don't need to be able to do i/o cycles.
186 /* I/O read/write window */
187 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI0, 1);
188 /* type 0 configuration only */
189 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2);
190 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI2, 1 << 30); /* memory only */
193 /* XXX resource managers */
195 device_add_child(dev, "pci", -1);
196 return (bus_generic_attach(dev));
202 siba_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
204 struct siba_pcib_softc *sc;
206 sc = device_get_softc(dev);
209 *result = sc->sc_bus;
217 siba_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
219 struct siba_pcib_softc *sc;
221 sc = device_get_softc(dev);
232 siba_pcib_setup_intr(device_t dev, device_t child, struct resource *ires,
233 int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
237 return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
238 filt, intr, arg, cookiep));
242 siba_pcib_teardown_intr(device_t dev, device_t child, struct resource *vec,
246 return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, cookie));
249 static struct resource *
250 siba_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid,
251 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
255 //device_printf(bus, "%s: not yet implemented\n", __func__);
259 struct siba_pcib_softc *sc = device_get_softc(bus);
267 rmanp = &sc->sc_irq_rman;
271 rmanp = &sc->sc_mem_rman;
272 tag = &sc->sc_pci_memt;
279 rv = rman_reserve_resource(rmanp, start, end, count, flags, child);
281 rman_set_rid(rv, *rid);
282 if (type == SYS_RES_MEMORY) {
284 rman_set_bustag(rv, tag);
285 rman_set_bushandle(rv, rman_get_bushandle(sc->sc_mem) +
286 (rman_get_start(rv) - IXP425_PCI_MEM_HWBASE));
296 siba_pcib_activate_resource(device_t bus, device_t child, int type, int rid,
300 device_printf(bus, "%s: not yet implemented\n", __func__);
301 device_printf(bus, "%s called activate_resource\n",
302 device_get_nameunit(child));
307 siba_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid,
311 device_printf(bus, "%s: not yet implemented\n", __func__);
312 device_printf(bus, "%s called deactivate_resource\n",
313 device_get_nameunit(child));
318 siba_pcib_release_resource(device_t bus, device_t child, int type, int rid,
322 device_printf(bus, "%s: not yet implemented\n", __func__);
323 device_printf(bus, "%s called release_resource\n",
324 device_get_nameunit(child));
328 /* pcib interface functions */
331 siba_pcib_maxslots(device_t dev)
334 return (SBPCI_SLOTMAX);
338 * This needs hacking and fixery. It is currently broke and hangs.
339 * Debugging it will be tricky; there seems to be no way to enable
340 * a target abort which would cause a nice target abort.
341 * Look at linux again?
344 siba_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
345 u_int reg, int bytes)
347 struct siba_pcib_softc *sc = device_get_softc(dev);
352 /* XXX anything higher than slot 2 currently seems to hang the bus.
353 * not sure why this is; look at linux again
355 if (bus != 0 || slot > 2) {
356 printf("%s: bad b/s/f %d/%d/%d\n", __func__, bus, slot, func);
357 return 0xffffffff; // XXX
360 device_printf(dev, "requested %d bytes from b/s/f %d/%d/%d reg %d\n",
361 bytes, bus, slot, func, reg);
364 * The configuration tag on the broadcom is weird.
366 SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2); /* XXX again??? */
367 cfgtag = ((1 << slot) << 16) | (func << 8);
368 cfgaddr = SBPCI_CFGBASE | cfgtag | (reg & ~3);
370 /* cfg space i/o is always 32 bits on this bridge */
371 printf("reading 4 bytes from %08x\n", cfgaddr);
372 val = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(cfgaddr); /* XXX MIPS */
374 val = bswap32(val); /* XXX seems to be needed for now */
376 /* swizzle and return what was asked for */
377 val &= 0xffffffff >> ((4 - bytes) * 8);
383 siba_pcib_write_config(device_t dev, u_int bus, u_int slot,
384 u_int func, u_int reg, u_int32_t val, int bytes)
387 /* write to pci configuration space */
388 //device_printf(dev, "%s: not yet implemented\n", __func__);
392 siba_pcib_route_interrupt(device_t bridge, device_t device, int pin)
395 //device_printf(bridge, "%s: not yet implemented\n", __func__);
399 static device_method_t siba_pcib_methods[] = {
400 /* Device interface */
401 DEVMETHOD(device_attach, siba_pcib_attach),
402 DEVMETHOD(device_probe, siba_pcib_probe),
405 DEVMETHOD(bus_read_ivar, siba_pcib_read_ivar),
406 DEVMETHOD(bus_write_ivar, siba_pcib_write_ivar),
407 DEVMETHOD(bus_setup_intr, siba_pcib_setup_intr),
408 DEVMETHOD(bus_teardown_intr, siba_pcib_teardown_intr),
409 DEVMETHOD(bus_alloc_resource, siba_pcib_alloc_resource),
410 DEVMETHOD(bus_activate_resource, siba_pcib_activate_resource),
411 DEVMETHOD(bus_deactivate_resource, siba_pcib_deactivate_resource),
412 DEVMETHOD(bus_release_resource, siba_pcib_release_resource),
415 DEVMETHOD(pcib_maxslots, siba_pcib_maxslots),
416 DEVMETHOD(pcib_read_config, siba_pcib_read_config),
417 DEVMETHOD(pcib_write_config, siba_pcib_write_config),
418 DEVMETHOD(pcib_route_interrupt, siba_pcib_route_interrupt),
423 static driver_t siba_pcib_driver = {
426 sizeof(struct siba_softc),
428 static devclass_t siba_pcib_devclass;
430 DRIVER_MODULE(siba_pcib, siba, siba_pcib_driver, siba_pcib_devclass, 0, 0);