]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/arm/xscale/i80321/iq80321.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / sys / arm / xscale / i80321 / iq80321.c
1 /*      $NetBSD: i80321_mainbus.c,v 1.13 2003/12/17 22:03:24 abs Exp $  */
2
3 /*-
4  * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project by
20  *      Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37
38 /*
39  * IQ80321 front-end for the i80321 I/O Processor.  We take care
40  * of setting up the i80321 memory map, PCI interrupt routing, etc.,
41  * which are all specific to the board the i80321 is wired up to.
42  */
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #define _ARM32_BUS_DMA_PRIVATE
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/bus.h>
51 #include <sys/kernel.h>
52 #include <sys/module.h>
53 #include <sys/malloc.h>
54 #define __RMAN_RESOURCE_VISIBLE
55 #include <sys/rman.h>
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58
59 #include <arm/xscale/i80321/i80321reg.h>
60 #include <arm/xscale/i80321/i80321var.h>
61 #include <arm/xscale/i80321/iq80321reg.h>
62 #include <arm/xscale/i80321/iq80321var.h>
63 #include <arm/xscale/i80321/i80321_intr.h>
64
65 #include <dev/pci/pcireg.h>
66
67
68 int     iq80321_probe(device_t);
69 void    iq80321_identify(driver_t *, device_t);
70 int     iq80321_attach(device_t);
71
72 int
73 iq80321_probe(device_t dev)
74 {
75         device_set_desc(dev, "Intel 80321");
76         return (0);
77 }
78
79 void
80 iq80321_identify(driver_t *driver, device_t parent)
81 {
82         
83         BUS_ADD_CHILD(parent, 0, "iq", 0);
84 }
85
86 static struct arm32_dma_range i80321_dr;
87 static int dma_range_init = 0;
88
89 struct arm32_dma_range *
90 bus_dma_get_range(void)
91 {
92         if (dma_range_init == 0)
93                 return (NULL);
94         return (&i80321_dr);
95 }
96
97 int
98 bus_dma_get_range_nb(void)
99 {
100         if (dma_range_init == 0)
101                 return (0);
102         return (1);
103 }
104
105 #define PCI_MAPREG_MEM_PREFETCHABLE_MASK        0x00000008
106 #define PCI_MAPREG_MEM_TYPE_64BIT               0x00000004
107
108 int
109 iq80321_attach(device_t dev)
110 {
111         struct i80321_softc *sc = device_get_softc(dev);
112         int b0u, b0l, b1u, b1l;
113         vm_paddr_t memstart = 0;
114         vm_size_t memsize = 0;
115         int busno;
116
117         /*
118          * Fill in the space tag for the i80321's own devices,
119          * and hand-craft the space handle for it (the device
120          * was mapped during early bootstrap).
121          */
122         i80321_bs_init(&i80321_bs_tag, sc);
123         sc->sc_st = &i80321_bs_tag;
124         sc->sc_sh = IQ80321_80321_VBASE;
125         sc->dev = dev;
126         sc->sc_is_host = 1;
127
128         /*
129          * Slice off a subregion for the Memory Controller -- we need it
130          * here in order read the memory size.
131          */
132         if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_MCU_BASE,
133             VERDE_MCU_SIZE, &sc->sc_mcu_sh))
134                 panic("%s: unable to subregion MCU registers",
135                     device_get_name(dev));
136
137         if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_ATU_BASE,
138             VERDE_ATU_SIZE, &sc->sc_atu_sh))
139                 panic("%s: unable to subregion ATU registers",
140                     device_get_name(dev));
141
142         /*
143          * We have mapped the the PCI I/O windows in the early
144          * bootstrap phase.
145          */
146         sc->sc_iow_vaddr = IQ80321_IOW_VBASE;
147
148         /*
149          * Check the configuration of the ATU to see if another BIOS
150          * has configured us.  If a PC BIOS didn't configure us, then:
151          *      IQ80321: BAR0 00000000.0000000c BAR1 is 00000000.8000000c.
152          *      IQ31244: BAR0 00000000.00000004 BAR1 is 00000000.0000000c.
153          * If a BIOS has configured us, at least one of those should be
154          * different.  This is pretty fragile, but it's not clear what
155          * would work better.
156          */
157         b0l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x0);
158         b0u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x4);
159         b1l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x8);
160         b1u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0xc);
161 #define PCI_MAPREG_MEM_ADDR_MASK        0xfffffff0
162         b0l &= PCI_MAPREG_MEM_ADDR_MASK;
163         b0u &= PCI_MAPREG_MEM_ADDR_MASK;
164         b1l &= PCI_MAPREG_MEM_ADDR_MASK;
165         b1u &= PCI_MAPREG_MEM_ADDR_MASK;
166
167         if ((b0u != b1u) || (b0l != 0) || ((b1l & ~0x80000000U) != 0))
168                 sc->sc_is_host = 0;
169         else
170                 sc->sc_is_host = 1;
171         i80321_sdram_bounds(sc->sc_st, sc->sc_mcu_sh, &memstart, &memsize);
172         /*
173          * We set up the Inbound Windows as follows:
174          *
175          *      0       Access to i80321 PMMRs
176          *
177          *      1       Reserve space for private devices
178          *
179          *      2       RAM access
180          *
181          *      3       Unused.
182          *
183          * This chunk needs to be customized for each IOP321 application.
184          */
185 #if 0
186         sc->sc_iwin[0].iwin_base_lo = VERDE_PMMR_BASE;
187         sc->sc_iwin[0].iwin_base_hi = 0;
188         sc->sc_iwin[0].iwin_xlate = VERDE_PMMR_BASE;
189         sc->sc_iwin[0].iwin_size = VERDE_PMMR_SIZE;
190 #endif
191         if (sc->sc_is_host) {
192                 
193                 /* Map PCI:Local 1:1. */
194                 sc->sc_iwin[1].iwin_base_lo = VERDE_OUT_XLATE_MEM_WIN0_BASE |
195                     PCI_MAPREG_MEM_PREFETCHABLE_MASK |
196                     PCI_MAPREG_MEM_TYPE_64BIT;
197                 sc->sc_iwin[1].iwin_base_hi = 0;
198         } else {
199                 
200                 sc->sc_iwin[1].iwin_base_lo = 0;
201                 sc->sc_iwin[1].iwin_base_hi = 0;
202         }
203         sc->sc_iwin[1].iwin_xlate = VERDE_OUT_XLATE_MEM_WIN0_BASE;
204         sc->sc_iwin[1].iwin_size = VERDE_OUT_XLATE_MEM_WIN_SIZE;
205         
206         if (sc->sc_is_host) {
207                 sc->sc_iwin[2].iwin_base_lo = memstart |
208                     PCI_MAPREG_MEM_PREFETCHABLE_MASK |
209                     PCI_MAPREG_MEM_TYPE_64BIT;
210                 sc->sc_iwin[2].iwin_base_hi = 0;
211         } else {
212                 sc->sc_iwin[2].iwin_base_lo = 0;
213                 sc->sc_iwin[2].iwin_base_hi = 0;
214         }
215         sc->sc_iwin[2].iwin_xlate = memstart;
216         sc->sc_iwin[2].iwin_size = memsize;
217
218         if (sc->sc_is_host) {
219                 sc->sc_iwin[3].iwin_base_lo = 0 |
220                     PCI_MAPREG_MEM_PREFETCHABLE_MASK |
221                     PCI_MAPREG_MEM_TYPE_64BIT;
222         } else {
223                 sc->sc_iwin[3].iwin_base_lo = 0;
224         }
225         sc->sc_iwin[3].iwin_base_hi = 0;
226         sc->sc_iwin[3].iwin_xlate = 0;
227         sc->sc_iwin[3].iwin_size = 0;
228
229         /*
230          * We set up the Outbound Windows as follows:
231          *
232          *      0       Access to private PCI space.
233          *
234          *      1       Unused.
235          */
236 #define PCI_MAPREG_MEM_ADDR(x) ((x) & 0xfffffff0)
237         sc->sc_owin[0].owin_xlate_lo =
238             PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo);
239         sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi;
240         /*
241          * Set the Secondary Outbound I/O window to map
242          * to PCI address 0 for all 64K of the I/O space.
243          */
244         sc->sc_ioout_xlate = 0;
245         i80321_attach(sc);
246         i80321_dr.dr_sysbase = sc->sc_iwin[2].iwin_xlate;
247         i80321_dr.dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo);
248         i80321_dr.dr_len = sc->sc_iwin[2].iwin_size;
249         dma_range_init = 1;
250         busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
251         busno = PCIXSR_BUSNO(busno);
252         if (busno == 0xff)
253                 busno = 0;
254         device_add_child(dev, "obio", 0);
255         device_add_child(dev, "itimer", 0);
256         device_add_child(dev, "iopwdog", 0);
257         device_add_child(dev, "iqseg", 0);
258         device_add_child(dev, "pcib", busno);
259         bus_generic_probe(dev);
260         bus_generic_attach(dev);
261
262         return (0);
263 }
264
265 void
266 arm_mask_irq(uintptr_t nb)
267 {
268         intr_enabled &= ~(1 << nb);
269         i80321_set_intrmask();
270 }
271
272 void
273 arm_unmask_irq(uintptr_t nb)
274 {
275         intr_enabled |= (1 << nb);
276         i80321_set_intrmask();
277 }
278
279
280 void
281 cpu_reset()
282 {       
283         (void) disable_interrupts(I32_bit|F32_bit);
284         *(__volatile uint32_t *)(IQ80321_80321_VBASE + VERDE_ATU_BASE +
285             ATU_PCSR) = PCSR_RIB | PCSR_RPB;
286         printf("Reset failed :'(\n");
287         for(;;);
288 }
289
290 static struct resource *
291 iq80321_alloc_resource(device_t dev, device_t child, int type, int *rid,
292     u_long start, u_long end, u_long count, u_int flags)
293 {
294         if (type == SYS_RES_IRQ) {
295                 struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK);
296                 res->r_start = start;
297                 res->r_end = end;
298                 return (res);
299         }
300         return (NULL);
301 }
302
303 static int
304 iq80321_setup_intr(device_t dev, device_t child,
305     struct resource *ires, int flags, driver_intr_t *intr, void *arg,
306     void **cookiep)
307 {
308         BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, intr, arg,
309             cookiep);
310         intr_enabled |= 1 << ires->r_start;
311         i80321_set_intrmask();
312         
313         return (0);
314 }
315
316 static int
317 iq80321_teardown_intr(device_t dev, device_t child, struct resource *res,
318     void *cookie)
319 {
320         return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
321 }
322
323 static device_method_t iq80321_methods[] = {
324         DEVMETHOD(device_probe, iq80321_probe),
325         DEVMETHOD(device_attach, iq80321_attach),
326         DEVMETHOD(device_identify, iq80321_identify),
327         DEVMETHOD(bus_alloc_resource, iq80321_alloc_resource),
328         DEVMETHOD(bus_setup_intr, iq80321_setup_intr),
329         DEVMETHOD(bus_teardown_intr, iq80321_teardown_intr),
330         {0, 0},
331 };
332
333 static driver_t iq80321_driver = {
334         "iq",
335         iq80321_methods,
336         sizeof(struct i80321_softc),
337 };
338 static devclass_t iq80321_devclass;
339
340 DRIVER_MODULE(iq, nexus, iq80321_driver, iq80321_devclass, 0, 0);