]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - sys/dev/siba/siba_pcib.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / sys / dev / siba / siba_pcib.c
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/sibavar.h>
59 #include <dev/siba/sibareg.h>
60 #include <dev/siba/siba_ids.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 #define SBPCI_SBTOPCI0 0x100
83 #define SBPCI_SBTOPCI1 0x104
84 #define SBPCI_SBTOPCI2 0x108
85
86 /*
87  * TODO: implement type 1 config space access (ie beyond bus 0)
88  * we may need to tweak the windows to do this
89  * TODO: interrupt routing.
90  * TODO: fully implement bus allocation.
91  * TODO: implement resource managers.
92  * TODO: code cleanup.
93  */
94
95 static int      siba_pcib_activate_resource(device_t, device_t, int,
96                     int, struct resource *);
97 static struct resource *
98                 siba_pcib_alloc_resource(device_t, device_t, int, int *,
99                     u_long , u_long, u_long, u_int);
100 static int      siba_pcib_attach(device_t);
101 static int      siba_pcib_deactivate_resource(device_t, device_t, int,
102                     int, struct resource *);
103 static int      siba_pcib_maxslots(device_t);
104 static int      siba_pcib_probe(device_t);
105 static u_int32_t
106                 siba_pcib_read_config(device_t, u_int, u_int, u_int, u_int,
107                     int);
108 static int      siba_pcib_read_ivar(device_t, device_t, int, uintptr_t *);
109 static int      siba_pcib_release_resource(device_t, device_t, int, int,
110                     struct resource *);
111 static int      siba_pcib_route_interrupt(device_t, device_t, int);
112 static int      siba_pcib_setup_intr(device_t, device_t, struct resource *,
113                     int, driver_filter_t *, driver_intr_t *, void *, void **);
114 static int      siba_pcib_teardown_intr(device_t, device_t, struct resource *,
115                     void *);
116 static void     siba_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
117                     u_int32_t, int);
118 static int      siba_pcib_write_ivar(device_t, device_t, int, uintptr_t);
119
120 static int
121 siba_pcib_probe(device_t dev)
122 {
123
124         /* TODO: support earlier cores. */
125         /* TODO: Check if PCI host mode is enabled in the SPROM. */
126         if (siba_get_vendor(dev) == SIBA_VID_BROADCOM &&
127             siba_get_device(dev) == SIBA_DEVID_PCI) {
128                 device_set_desc(dev, "SiBa-to-PCI host bridge");
129                 return (BUS_PROBE_DEFAULT);
130         }
131
132         return (ENXIO);
133 }
134
135 //extern int rman_debug;
136
137 static int
138 siba_pcib_attach(device_t dev)
139 {
140         struct siba_pcib_softc *sc = device_get_softc(dev);
141         int rid;
142
143         /*
144          * Allocate the resources which the parent bus has already
145          * determined for us.
146          */
147         rid = MIPS_MEM_RID;     /* XXX */
148         //rman_debug = 1;
149         sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
150             RF_ACTIVE);
151         if (sc->sc_mem == NULL) {
152                 device_printf(dev, "unable to allocate memory\n");
153                 return (ENXIO);
154         }
155
156         sc->sc_bt = rman_get_bustag(sc->sc_mem);
157         sc->sc_bh = rman_get_bushandle(sc->sc_mem);
158
159         device_printf(dev, "bridge registers addr 0x%08x vaddr %p\n",
160             (uint32_t)sc->sc_bh, rman_get_virtual(sc->sc_mem));
161
162         SBPCI_WRITE_4(sc, 0x0000, 0x05);
163         SBPCI_WRITE_4(sc, 0x0000, 0x0D);
164         DELAY(150);
165         SBPCI_WRITE_4(sc, 0x0000, 0x0F);
166         SBPCI_WRITE_4(sc, 0x0010, 0x01);
167         DELAY(1);
168
169         bus_space_handle_t sc_cfg_hand;
170         int error;
171
172         /*
173          * XXX this doesn't actually do anything on mips; however... should
174          * we not be mapping to KSEG1? we need to wire down the range.
175          */
176         error = bus_space_map(sc->sc_bt, SBPCI_CFGBASE, SBPCI_CFGSIZE,
177             0, &sc_cfg_hand);
178         if (error) {
179                 device_printf(dev, "cannot map PCI configuration space\n");
180                 return (ENXIO);
181         }
182         device_printf(dev, "mapped pci config space at 0x%08x\n",
183             (uint32_t)sc_cfg_hand);
184
185         /*
186          * Setup configuration, io, and dma space windows.
187          * XXX we need to be able to do type 1 too.
188          * we probably don't need to be able to do i/o cycles.
189          */
190         SBPCI_WRITE_4(sc, SBPCI_SBTOPCI0, 1);   /* I/O read/write window */
191         SBPCI_WRITE_4(sc, SBPCI_SBTOPCI1, 2);   /* type 0 configuration only */
192         SBPCI_WRITE_4(sc, SBPCI_SBTOPCI2, 1 << 30); /* memory only */
193         DELAY(500);
194
195         /* XXX resource managers */
196
197         device_add_child(dev, "pci", -1);
198         return (bus_generic_attach(dev));
199 }
200
201 /* bus functions */
202
203 static int
204 siba_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
205 {
206         struct siba_pcib_softc *sc;
207
208         sc = device_get_softc(dev);
209         switch (which) {
210         case PCIB_IVAR_BUS:
211                 *result = sc->sc_bus;
212                 return (0);
213         }
214
215         return (ENOENT);
216 }
217
218 static int
219 siba_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
220 {
221         struct siba_pcib_softc *sc;
222
223         sc = device_get_softc(dev);
224         switch (which) {
225         case PCIB_IVAR_BUS:
226                 sc->sc_bus = value;
227                 return (0);
228         }
229
230         return (ENOENT);
231 }
232
233 static int
234 siba_pcib_setup_intr(device_t dev, device_t child, struct resource *ires,
235     int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
236     void **cookiep)
237 {
238
239         return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
240             filt, intr, arg, cookiep));
241 }
242
243 static int
244 siba_pcib_teardown_intr(device_t dev, device_t child, struct resource *vec,
245      void *cookie)
246 {
247
248         return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, cookie));
249 }
250
251 static struct resource *
252 siba_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid,
253     u_long start, u_long end, u_long count, u_int flags)
254 {
255 #if 1
256
257         //device_printf(bus, "%s: not yet implemented\n", __func__);
258         return (NULL);
259 #else
260         bus_space_tag_t tag;
261         struct siba_pcib_softc *sc = device_get_softc(bus);
262         struct rman *rmanp;
263         struct resource *rv;
264
265         tag = 0;
266         rv = NULL;
267         switch (type) {
268         case SYS_RES_IRQ:
269                 rmanp = &sc->sc_irq_rman;
270                 break;
271
272         case SYS_RES_MEMORY:
273                 rmanp = &sc->sc_mem_rman;
274                 tag = &sc->sc_pci_memt;
275                 break;
276
277         default:
278                 return (rv);
279         }
280
281         rv = rman_reserve_resource(rmanp, start, end, count, flags, child);
282         if (rv != NULL) {
283                 rman_set_rid(rv, *rid);
284                 if (type == SYS_RES_MEMORY) {
285 #if 0
286                         rman_set_bustag(rv, tag);
287                         rman_set_bushandle(rv, rman_get_bushandle(sc->sc_mem) +
288                             (rman_get_start(rv) - IXP425_PCI_MEM_HWBASE));
289 #endif
290                 }
291         }
292
293         return (rv);
294 #endif
295 }
296
297 static int
298 siba_pcib_activate_resource(device_t bus, device_t child, int type, int rid,
299     struct resource *r)
300 {
301
302         device_printf(bus, "%s: not yet implemented\n", __func__);
303         device_printf(bus, "%s called activate_resource\n",
304             device_get_nameunit(child));
305         return (ENXIO);
306 }
307
308 static int
309 siba_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid,
310     struct resource *r)
311 {
312
313         device_printf(bus, "%s: not yet implemented\n", __func__);
314         device_printf(bus, "%s called deactivate_resource\n",
315             device_get_nameunit(child));
316         return (ENXIO);
317 }
318
319 static int
320 siba_pcib_release_resource(device_t bus, device_t child, int type, int rid,
321     struct resource *r)
322 {
323
324         device_printf(bus, "%s: not yet implemented\n", __func__);
325         device_printf(bus, "%s called release_resource\n",
326             device_get_nameunit(child));
327         return (ENXIO);
328 }
329
330 /* pcib interface functions */
331
332 static int
333 siba_pcib_maxslots(device_t dev)
334 {
335
336         return (SBPCI_SLOTMAX);
337 }
338
339 /*
340  * This needs hacking and fixery. It is currently broke and hangs.
341  * Debugging it will be tricky; there seems to be no way to enable
342  * a target abort which would cause a nice target abort.
343  * Look at linux again?
344  */
345 static u_int32_t
346 siba_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
347     u_int reg, int bytes)
348 {
349         struct siba_pcib_softc *sc = device_get_softc(dev);
350         bus_addr_t cfgaddr;
351         uint32_t cfgtag;
352         uint32_t val;
353
354         /* XXX anything higher than slot 2 currently seems to hang the bus.
355          * not sure why this is; look at linux again
356          */
357         if (bus != 0 || slot > 2) {
358                 printf("%s: bad b/s/f %d/%d/%d\n", __func__, bus, slot, func);
359                 return 0xffffffff;      // XXX
360         }
361
362         device_printf(dev, "requested %d bytes from b/s/f %d/%d/%d reg %d\n",
363             bytes, bus, slot, func, reg);
364
365         /*
366          * The configuration tag on the broadcom is weird.
367          */
368         SBPCI_WRITE_4(sc, SBPCI_SBTOPCI1, 2);   /* XXX again??? */
369         cfgtag = ((1 << slot) << 16) | (func << 8);
370         cfgaddr = SBPCI_CFGBASE | cfgtag | (reg & ~3);
371
372         /* cfg space i/o is always 32 bits on this bridge */
373         printf("reading 4 bytes from %08x\n", cfgaddr);
374         val = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(cfgaddr); /* XXX MIPS */
375
376         val = bswap32(val);     /* XXX seems to be needed for now */
377
378         /* swizzle and return what was asked for */
379         val &= 0xffffffff >> ((4 - bytes) * 8);
380
381         return (val);
382 }
383
384 static void
385 siba_pcib_write_config(device_t dev, u_int bus, u_int slot,
386     u_int func, u_int reg, u_int32_t val, int bytes)
387 {
388
389         /* write to pci configuration space */
390         //device_printf(dev, "%s: not yet implemented\n", __func__);
391 }
392
393 static int
394 siba_pcib_route_interrupt(device_t bridge, device_t device, int pin)
395 {
396
397         //device_printf(bridge, "%s: not yet implemented\n", __func__);
398         return (-1);
399 }
400
401 static device_method_t siba_pcib_methods[] = {
402         /* Device interface */
403         DEVMETHOD(device_attach,        siba_pcib_attach),
404         DEVMETHOD(device_probe,         siba_pcib_probe),
405
406         /* Bus interface */
407         DEVMETHOD(bus_print_child,      bus_generic_print_child),
408         DEVMETHOD(bus_read_ivar,        siba_pcib_read_ivar),
409         DEVMETHOD(bus_write_ivar,       siba_pcib_write_ivar),
410         DEVMETHOD(bus_setup_intr,       siba_pcib_setup_intr),
411         DEVMETHOD(bus_teardown_intr,    siba_pcib_teardown_intr),
412         DEVMETHOD(bus_alloc_resource,   siba_pcib_alloc_resource),
413         DEVMETHOD(bus_activate_resource,        siba_pcib_activate_resource),
414         DEVMETHOD(bus_deactivate_resource,      siba_pcib_deactivate_resource),
415         DEVMETHOD(bus_release_resource, siba_pcib_release_resource),
416
417         /* pcib interface */
418         DEVMETHOD(pcib_maxslots,        siba_pcib_maxslots),
419         DEVMETHOD(pcib_read_config,     siba_pcib_read_config),
420         DEVMETHOD(pcib_write_config,    siba_pcib_write_config),
421         DEVMETHOD(pcib_route_interrupt, siba_pcib_route_interrupt),
422
423         {0, 0},
424 };
425
426 static driver_t siba_pcib_driver = {
427         "pcib",
428         siba_pcib_methods,
429         sizeof(struct siba_softc),
430 };
431 static devclass_t siba_pcib_devclass;
432
433 DRIVER_MODULE(siba_pcib, siba, siba_pcib_driver, siba_pcib_devclass, 0, 0);