at91rm9200.c revision 238331
1126385Smlaier/*-
2126385Smlaier * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
3240494Sglebius * Copyright (c) 2010 Greg Ansley.  All rights reserved.
4240494Sglebius *
5126385Smlaier * Redistribution and use in source and binary forms, with or without
6126385Smlaier * modification, are permitted provided that the following conditions
7240494Sglebius * are met:
8126385Smlaier * 1. Redistributions of source code must retain the above copyright
9126385Smlaier *    notice, this list of conditions and the following disclaimer.
10126385Smlaier * 2. Redistributions in binary form must reproduce the above copyright
11145841Smlaier *    notice, this list of conditions and the following disclaimer in the
12171173Smlaier *    documentation and/or other materials provided with the distribution.
13126385Smlaier *
14198236Sru * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15126385Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16240494Sglebius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17240494Sglebius * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18126385Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19126385Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20126385Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21126385Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22157721Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23126385Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24126385Smlaier * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/arm/at91/at91rm9200.c 238331 2012-07-10 02:39:03Z imp $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/kernel.h>
34#include <sys/malloc.h>
35#include <sys/module.h>
36
37#define	_ARM32_BUS_DMA_PRIVATE
38#include <machine/bus.h>
39
40#include <arm/at91/at91var.h>
41#include <arm/at91/at91reg.h>
42#include <arm/at91/at91rm92reg.h>
43#include <arm/at91/at91_aicreg.h>
44#include <arm/at91/at91_pmcreg.h>
45#include <arm/at91/at91_pmcvar.h>
46
47struct at91rm92_softc {
48	device_t dev;
49	bus_space_tag_t sc_st;
50	bus_space_handle_t sc_sh;
51	bus_space_handle_t sc_sys_sh;
52	bus_space_handle_t sc_aic_sh;
53	bus_space_handle_t sc_dbg_sh;
54	bus_space_handle_t sc_matrix_sh;
55};
56/*
57 * Standard priority levels for the system.  0 is lowest and 7 is highest.
58 * These values are the ones Atmel uses for its Linux port, which differ
59 * a little form the ones that are in the standard distribution.  Also,
60 * the ones marked with 'TWEEK' are different based on experience.
61 */
62static const int at91_irq_prio[32] =
63{
64	7,	/* Advanced Interrupt Controller (FIQ) */
65	7,	/* System Peripherals */
66	1,	/* Parallel IO Controller A */
67	1,	/* Parallel IO Controller B */
68	1,	/* Parallel IO Controller C */
69	1,	/* Parallel IO Controller D */
70	5,	/* USART 0 */
71	5,	/* USART 1 */
72	5,	/* USART 2 */
73	5,	/* USART 3 */
74	0,	/* Multimedia Card Interface */
75	2,	/* USB Device Port */
76	4,	/* Two-Wire Interface */		/* TWEEK */
77	5,	/* Serial Peripheral Interface */
78	4,	/* Serial Synchronous Controller 0 */
79	6,	/* Serial Synchronous Controller 1 */	/* TWEEK */
80	4,	/* Serial Synchronous Controller 2 */
81	0,	/* Timer Counter 0 */
82	6,	/* Timer Counter 1 */			/* TWEEK */
83	0,	/* Timer Counter 2 */
84	0,	/* Timer Counter 3 */
85	0,	/* Timer Counter 4 */
86	0,	/* Timer Counter 5 */
87	2,	/* USB Host port */
88	3,	/* Ethernet MAC */
89	0,	/* Advanced Interrupt Controller (IRQ0) */
90	0,	/* Advanced Interrupt Controller (IRQ1) */
91	0,	/* Advanced Interrupt Controller (IRQ2) */
92	0,	/* Advanced Interrupt Controller (IRQ3) */
93	0,	/* Advanced Interrupt Controller (IRQ4) */
94	0,	/* Advanced Interrupt Controller (IRQ5) */
95 	0	/* Advanced Interrupt Controller (IRQ6) */
96};
97
98#define DEVICE(_name, _id, _unit)		\
99	{					\
100		_name, _unit,			\
101		AT91RM92_ ## _id ##_BASE,	\
102		AT91RM92_ ## _id ## _SIZE,	\
103		AT91RM92_IRQ_ ## _id		\
104	}
105
106static const struct cpu_devs at91_devs[] =
107{
108	DEVICE("at91_pmc",   PMC,    0),
109	DEVICE("at91_st",    ST,     0),
110	DEVICE("at91_pio",   PIOA,   0),
111	DEVICE("at91_pio",   PIOB,   1),
112	DEVICE("at91_pio",   PIOC,   2),
113	DEVICE("at91_pio",   PIOD,   3),
114	DEVICE("at91_rtc",   RTC,    0),
115
116	DEVICE("at91_mci",   MCI,    0),
117	DEVICE("at91_twi",   TWI,    0),
118	DEVICE("at91_udp",   UDP,    0),
119	DEVICE("ate",        EMAC,   0),
120	DEVICE("at91_ssc",   SSC0,   0),
121	DEVICE("at91_ssc",   SSC1,   1),
122	DEVICE("at91_ssc",   SSC2,   2),
123	DEVICE("spi",        SPI,    0),
124
125	DEVICE("uart",       DBGU,   0),
126	DEVICE("uart",       USART0, 1),
127	DEVICE("uart",       USART1, 2),
128	DEVICE("uart",       USART2, 3),
129	DEVICE("uart",       USART3, 4),
130	DEVICE("at91_aic",   AIC,    0),
131	DEVICE("at91_mc",    MC,     0),
132	DEVICE("at91_tc",    TC0,    0),
133	DEVICE("at91_tc",    TC1,    1),
134	DEVICE("ohci",       OHCI,   0),
135	DEVICE("af91_cfata", CF,     0),
136	{	0, 0, 0, 0, 0 }
137};
138
139static void
140at91_add_child(device_t dev, int prio, const char *name, int unit,
141    bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
142{
143	device_t kid;
144	struct at91_ivar *ivar;
145
146	kid = device_add_child_ordered(dev, prio, name, unit);
147	if (kid == NULL) {
148	    printf("Can't add child %s%d ordered\n", name, unit);
149	    return;
150	}
151	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
152	if (ivar == NULL) {
153		device_delete_child(dev, kid);
154		printf("Can't add alloc ivar\n");
155		return;
156	}
157	device_set_ivars(kid, ivar);
158	resource_list_init(&ivar->resources);
159	if (irq0 != -1) {
160		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
161		if (irq0 != AT91_IRQ_SYSTEM)
162			at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
163	}
164	if (irq1 != 0)
165		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
166	if (irq2 != 0)
167		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
168	if (addr != 0 && addr < AT91_BASE)
169		addr += AT91_BASE;
170	if (addr != 0)
171		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
172}
173
174static void
175at91_cpu_add_builtin_children(device_t dev)
176{
177	int i;
178	const struct cpu_devs *walker;
179
180	for (i = 1, walker = at91_devs; walker->name; i++, walker++) {
181		at91_add_child(dev, i, walker->name, walker->unit,
182		    walker->mem_base, walker->mem_len, walker->irq0,
183		    walker->irq1, walker->irq2);
184	}
185}
186
187static uint32_t
188at91_pll_outb(int freq)
189{
190
191	if (freq > 155000000)
192		return (0x0000);
193	else
194		return (0x8000);
195}
196
197static void
198at91_identify(driver_t *drv, device_t parent)
199{
200
201	if (at91_cpu_is(AT91_T_RM9200)) {
202		at91_add_child(parent, 0, "at91rm920", 0, 0, 0, -1, 0, 0);
203		at91_cpu_add_builtin_children(parent);
204	}
205}
206
207static int
208at91_probe(device_t dev)
209{
210
211	device_set_desc(dev, soc_data.name);
212	return (0);
213}
214
215static int
216at91_attach(device_t dev)
217{
218	struct at91_pmc_clock *clk;
219	struct at91rm92_softc *sc = device_get_softc(dev);
220	int i;
221
222	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
223
224	sc->sc_st = at91sc->sc_st;
225	sc->sc_sh = at91sc->sc_sh;
226	sc->dev = dev;
227
228	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_SYS_BASE,
229	    AT91RM92_SYS_SIZE, &sc->sc_sys_sh) != 0)
230		panic("Enable to map system registers");
231
232	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_DBGU_BASE,
233	    AT91RM92_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
234		panic("Enable to map DBGU registers");
235
236	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_AIC_BASE,
237	    AT91RM92_AIC_SIZE, &sc->sc_aic_sh) != 0)
238		panic("Enable to map system registers");
239
240	/* XXX Hack to tell atmelarm about the AIC */
241	at91sc->sc_aic_sh = sc->sc_aic_sh;
242	at91sc->sc_irq_system = AT91_IRQ_SYSTEM;
243
244	for (i = 0; i < 32; i++) {
245		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
246		    i * 4, i);
247		/* Priority. */
248		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
249		    at91_irq_prio[i]);
250		if (i < 8)
251			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
252			    1);
253	}
254
255	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
256	/* No debug. */
257	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
258	/* Disable and clear all interrupts. */
259	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
260	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
261
262	/* Disable all interrupts for RTC (0xe24 == RTC_IDR) */
263	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xe24, 0xffffffff);
264
265	/* Disable all interrupts for the SDRAM controller */
266	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xfa8, 0xffffffff);
267
268	/* Disable all interrupts for DBGU */
269	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);
270
271	/* Update USB device port clock info */
272	clk = at91_pmc_clock_ref("udpck");
273	clk->pmc_mask  = PMC_SCER_UDP;
274	at91_pmc_clock_deref(clk);
275
276	/* Update USB host port clock info */
277	clk = at91_pmc_clock_ref("uhpck");
278	clk->pmc_mask  = PMC_SCER_UHP;
279	at91_pmc_clock_deref(clk);
280
281	/* Each SOC has different PLL contraints */
282	clk = at91_pmc_clock_ref("plla");
283	clk->pll_min_in    = RM9200_PLL_A_MIN_IN_FREQ;		/*   1 MHz */
284	clk->pll_max_in    = RM9200_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
285	clk->pll_min_out   = RM9200_PLL_A_MIN_OUT_FREQ;		/*  80 MHz */
286	clk->pll_max_out   = RM9200_PLL_A_MAX_OUT_FREQ;		/* 180 MHz */
287	clk->pll_mul_shift = RM9200_PLL_A_MUL_SHIFT;
288	clk->pll_mul_mask  = RM9200_PLL_A_MUL_MASK;
289	clk->pll_div_shift = RM9200_PLL_A_DIV_SHIFT;
290	clk->pll_div_mask  = RM9200_PLL_A_DIV_MASK;
291	clk->set_outb      = at91_pll_outb;
292	at91_pmc_clock_deref(clk);
293
294	clk = at91_pmc_clock_ref("pllb");
295	clk->pll_min_in    = RM9200_PLL_B_MIN_IN_FREQ;		/* 100 KHz */
296	clk->pll_max_in    = RM9200_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
297	clk->pll_min_out   = RM9200_PLL_B_MIN_OUT_FREQ;		/*  30 MHz */
298	clk->pll_max_out   = RM9200_PLL_B_MAX_OUT_FREQ;		/* 240 MHz */
299	clk->pll_mul_shift = RM9200_PLL_B_MUL_SHIFT;
300	clk->pll_mul_mask  = RM9200_PLL_B_MUL_MASK;
301	clk->pll_div_shift = RM9200_PLL_B_DIV_SHIFT;
302	clk->pll_div_mask  = RM9200_PLL_B_DIV_MASK;
303	clk->set_outb      = at91_pll_outb;
304	at91_pmc_clock_deref(clk);
305
306	return (0);
307}
308
309static device_method_t at91_methods[] = {
310	DEVMETHOD(device_probe, at91_probe),
311	DEVMETHOD(device_attach, at91_attach),
312	DEVMETHOD(device_identify, at91_identify),
313	{0, 0},
314};
315
316static driver_t at91rm92_driver = {
317	"at91rm920",
318	at91_methods,
319	sizeof(struct at91rm92_softc),
320};
321
322static devclass_t at91rm92_devclass;
323
324DRIVER_MODULE(at91rm920, atmelarm, at91rm92_driver, at91rm92_devclass, 0, 0);
325