iq80321.c revision 278613
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: stable/10/sys/arm/xscale/i80321/iq80321.c 278613 2015-02-12 03:50:33Z ian $");
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#include <sys/rman.h>
55#include <machine/armreg.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
68int	iq80321_probe(device_t);
69void	iq80321_identify(driver_t *, device_t);
70int	iq80321_attach(device_t);
71
72int
73iq80321_probe(device_t dev)
74{
75	device_set_desc(dev, "Intel 80321");
76	return (BUS_PROBE_NOWILDCARD);
77}
78
79void
80iq80321_identify(driver_t *driver, device_t parent)
81{
82
83	BUS_ADD_CHILD(parent, 0, "iq", 0);
84}
85
86static struct arm32_dma_range i80321_dr;
87static int dma_range_init = 0;
88
89struct arm32_dma_range *
90bus_dma_get_range(void)
91{
92	if (dma_range_init == 0)
93		return (NULL);
94	return (&i80321_dr);
95}
96
97int
98bus_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
108int
109iq80321_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 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
162#ifdef VERBOSE_INIT_ARM
163	printf("i80321: BAR0 = %08x.%08x BAR1 = %08x.%08x\n",
164		   b0l,b0u, b1l, b1u );
165#endif
166
167#define PCI_MAPREG_MEM_ADDR_MASK	0xfffffff0
168	b0l &= PCI_MAPREG_MEM_ADDR_MASK;
169	b0u &= PCI_MAPREG_MEM_ADDR_MASK;
170	b1l &= PCI_MAPREG_MEM_ADDR_MASK;
171	b1u &= PCI_MAPREG_MEM_ADDR_MASK;
172
173#ifdef VERBOSE_INIT_ARM
174	printf("i80219: BAR0 = %08x.%08x BAR1 = %08x.%08x\n",
175		   b0l,b0u, b1l, b1u );
176#endif
177
178	if ((b0u != b1u) || (b0l != 0) || ((b1l & ~0x80000000U) != 0))
179		sc->sc_is_host = 0;
180	else
181		sc->sc_is_host = 1;
182
183	/* FIXME: i force it's */
184
185#ifdef CPU_XSCALE_80219
186	sc->sc_is_host = 1;
187#endif
188
189	i80321_sdram_bounds(sc->sc_st, sc->sc_mcu_sh, &memstart, &memsize);
190	/*
191	 * We set up the Inbound Windows as follows:
192	 *
193	 *	0	Access to i80321 PMMRs
194	 *
195	 *	1	Reserve space for private devices
196	 *
197	 *	2	RAM access
198	 *
199	 *	3	Unused.
200	 *
201	 * This chunk needs to be customized for each IOP321 application.
202	 */
203#if 0
204	sc->sc_iwin[0].iwin_base_lo = VERDE_PMMR_BASE;
205	sc->sc_iwin[0].iwin_base_hi = 0;
206	sc->sc_iwin[0].iwin_xlate = VERDE_PMMR_BASE;
207	sc->sc_iwin[0].iwin_size = VERDE_PMMR_SIZE;
208#endif
209	if (sc->sc_is_host) {
210
211		/* Map PCI:Local 1:1. */
212		sc->sc_iwin[1].iwin_base_lo = VERDE_OUT_XLATE_MEM_WIN0_BASE |
213		    PCI_MAPREG_MEM_PREFETCHABLE_MASK |
214		    PCI_MAPREG_MEM_TYPE_64BIT;
215		sc->sc_iwin[1].iwin_base_hi = 0;
216	} else {
217
218		sc->sc_iwin[1].iwin_base_lo = 0;
219		sc->sc_iwin[1].iwin_base_hi = 0;
220	}
221	sc->sc_iwin[1].iwin_xlate = VERDE_OUT_XLATE_MEM_WIN0_BASE;
222	sc->sc_iwin[1].iwin_size = VERDE_OUT_XLATE_MEM_WIN_SIZE;
223
224	if (sc->sc_is_host) {
225		sc->sc_iwin[2].iwin_base_lo = memstart |
226		    PCI_MAPREG_MEM_PREFETCHABLE_MASK |
227		    PCI_MAPREG_MEM_TYPE_64BIT;
228		sc->sc_iwin[2].iwin_base_hi = 0;
229	} else {
230		sc->sc_iwin[2].iwin_base_lo = 0;
231		sc->sc_iwin[2].iwin_base_hi = 0;
232	}
233	sc->sc_iwin[2].iwin_xlate = memstart;
234	sc->sc_iwin[2].iwin_size = memsize;
235
236	if (sc->sc_is_host) {
237		sc->sc_iwin[3].iwin_base_lo = 0 |
238		    PCI_MAPREG_MEM_PREFETCHABLE_MASK |
239		    PCI_MAPREG_MEM_TYPE_64BIT;
240	} else {
241		sc->sc_iwin[3].iwin_base_lo = 0;
242	}
243	sc->sc_iwin[3].iwin_base_hi = 0;
244	sc->sc_iwin[3].iwin_xlate = 0;
245	sc->sc_iwin[3].iwin_size = 0;
246
247#ifdef 	VERBOSE_INIT_ARM
248	printf("i80321: Reserve space for private devices (Inbound Window 1) \n hi:0x%08x lo:0x%08x xlate:0x%08x size:0x%08x\n",
249		   sc->sc_iwin[1].iwin_base_hi,
250		   sc->sc_iwin[1].iwin_base_lo,
251		   sc->sc_iwin[1].iwin_xlate,
252		   sc->sc_iwin[1].iwin_size
253		);
254	printf("i80321: RAM access (Inbound Window 2) \n hi:0x%08x lo:0x%08x xlate:0x%08x size:0x%08x\n",
255		   sc->sc_iwin[2].iwin_base_hi,
256		   sc->sc_iwin[2].iwin_base_lo,
257		   sc->sc_iwin[2].iwin_xlate,
258		   sc->sc_iwin[2].iwin_size
259		);
260#endif
261
262	/*
263	 * We set up the Outbound Windows as follows:
264	 *
265	 *	0	Access to private PCI space.
266	 *
267	 *	1	Unused.
268	 */
269#define PCI_MAPREG_MEM_ADDR(x) ((x) & 0xfffffff0)
270	sc->sc_owin[0].owin_xlate_lo =
271    	    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo);
272	sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi;
273	/*
274	 * Set the Secondary Outbound I/O window to map
275	 * to PCI address 0 for all 64K of the I/O space.
276	 */
277	sc->sc_ioout_xlate = 0;
278	i80321_attach(sc);
279	i80321_dr.dr_sysbase = sc->sc_iwin[2].iwin_xlate;
280	i80321_dr.dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo);
281	i80321_dr.dr_len = sc->sc_iwin[2].iwin_size;
282	dma_range_init = 1;
283	busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
284	busno = PCIXSR_BUSNO(busno);
285	if (busno == 0xff)
286		busno = 0;
287	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
288	sc->sc_irq_rman.rm_descr = "i80321 IRQs";
289	if (rman_init(&sc->sc_irq_rman) != 0 ||
290	    rman_manage_region(&sc->sc_irq_rman, 0, 25) != 0)
291		panic("i80321_attach: failed to set up IRQ rman");
292
293	device_add_child(dev, "obio", 0);
294	device_add_child(dev, "itimer", 0);
295	device_add_child(dev, "iopwdog", 0);
296#ifndef 	CPU_XSCALE_80219
297	device_add_child(dev, "iqseg", 0);
298#endif
299	device_add_child(dev, "pcib", busno);
300	device_add_child(dev, "i80321_dma", 0);
301	device_add_child(dev, "i80321_dma", 1);
302#ifndef CPU_XSCALE_80219
303	device_add_child(dev, "i80321_aau", 0);
304#endif
305	bus_generic_probe(dev);
306	bus_generic_attach(dev);
307
308	return (0);
309}
310
311void
312arm_mask_irq(uintptr_t nb)
313{
314	intr_enabled &= ~(1 << nb);
315	i80321_set_intrmask();
316}
317
318void
319arm_unmask_irq(uintptr_t nb)
320{
321	intr_enabled |= (1 << nb);
322	i80321_set_intrmask();
323}
324
325
326void
327cpu_reset()
328{
329	(void) disable_interrupts(PSR_I|PSR_F);
330	*(__volatile uint32_t *)(IQ80321_80321_VBASE + VERDE_ATU_BASE +
331	    ATU_PCSR) = PCSR_RIB | PCSR_RPB;
332	printf("Reset failed!\n");
333	for(;;);
334}
335
336static struct resource *
337iq80321_alloc_resource(device_t dev, device_t child, int type, int *rid,
338    u_long start, u_long end, u_long count, u_int flags)
339{
340	struct i80321_softc *sc = device_get_softc(dev);
341	struct resource *rv;
342
343	if (type == SYS_RES_IRQ) {
344		rv = rman_reserve_resource(&sc->sc_irq_rman,
345		    start, end, count, flags, child);
346		if (rv != NULL)
347			rman_set_rid(rv, *rid);
348		return (rv);
349	}
350	return (NULL);
351}
352
353static int
354iq80321_setup_intr(device_t dev, device_t child,
355    struct resource *ires, int flags, driver_filter_t *filt,
356    driver_intr_t *intr, void *arg, void **cookiep)
357{
358	int error;
359
360	error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
361	    filt, intr, arg, cookiep);
362	if (error)
363		return (error);
364	intr_enabled |= 1 << rman_get_start(ires);
365	i80321_set_intrmask();
366
367	return (0);
368}
369
370static int
371iq80321_teardown_intr(device_t dev, device_t child, struct resource *res,
372    void *cookie)
373{
374	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
375}
376
377static device_method_t iq80321_methods[] = {
378	DEVMETHOD(device_probe, iq80321_probe),
379	DEVMETHOD(device_attach, iq80321_attach),
380	DEVMETHOD(device_identify, iq80321_identify),
381	DEVMETHOD(bus_alloc_resource, iq80321_alloc_resource),
382	DEVMETHOD(bus_setup_intr, iq80321_setup_intr),
383	DEVMETHOD(bus_teardown_intr, iq80321_teardown_intr),
384	{0, 0},
385};
386
387static driver_t iq80321_driver = {
388	"iq",
389	iq80321_methods,
390	sizeof(struct i80321_softc),
391};
392static devclass_t iq80321_devclass;
393
394DRIVER_MODULE(iq, nexus, iq80321_driver, iq80321_devclass, 0, 0);
395