at91sam9g20.c revision 213496
1/*-
2 * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
3 * Copyright (c) 2010 Greg Ansley.  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 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 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#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9g20.c 213496 2010-10-06 22:25:21Z cognet $");
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/at91_aicreg.h>
42#include <arm/at91/at91sam9g20reg.h>
43#include <arm/at91/at91_pmcreg.h>
44#include <arm/at91/at91_pmcvar.h>
45
46struct at91sam9_softc {
47	device_t dev;
48	bus_space_tag_t sc_st;
49	bus_space_handle_t sc_sh;
50	bus_space_handle_t sc_sys_sh;
51	bus_space_handle_t sc_aic_sh;
52	bus_space_handle_t sc_dbg_sh;
53	bus_space_handle_t sc_matrix_sh;
54};
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
59 */
60static const int at91_irq_prio[32] =
61{
62	7,	/* Advanced Interrupt Controller */
63	7,	/* System Peripherals */
64	1,	/* Parallel IO Controller A */
65	1,	/* Parallel IO Controller B */
66	1,	/* Parallel IO Controller C */
67	0,	/* Analog-to-Digital Converter */
68	5,	/* USART 0 */
69	5,	/* USART 1 */
70	5,	/* USART 2 */
71	0,	/* Multimedia Card Interface */
72	2,	/* USB Device Port */
73	6,	/* Two-Wire Interface */
74	5,	/* Serial Peripheral Interface 0 */
75	5,	/* Serial Peripheral Interface 1 */
76	5,	/* Serial Synchronous Controller */
77	0,	/* (reserved) */
78	0,	/* (reserved) */
79	0,	/* Timer Counter 0 */
80	0,	/* Timer Counter 1 */
81	0,	/* Timer Counter 2 */
82	2,	/* USB Host port */
83	3,	/* Ethernet */
84	0,	/* Image Sensor Interface */
85	5,	/* USART 3 */
86	5,	/* USART 4 */
87	5,	/* USART 5 */
88	0,	/* Timer Counter 3 */
89	0,	/* Timer Counter 4 */
90	0,	/* Timer Counter 5 */
91	0,	/* Advanced Interrupt Controller IRQ0 */
92	0,	/* Advanced Interrupt Controller IRQ1 */
93	0,	/* Advanced Interrupt Controller IRQ2 */
94};
95
96#define DEVICE(_name, _id, _unit)		\
97	{					\
98		_name, _unit,			\
99		AT91SAM9G20_ ## _id ##_BASE,	\
100		AT91SAM9G20_ ## _id ## _SIZE,	\
101		AT91SAM9G20_IRQ_ ## _id		\
102	}
103
104static const struct cpu_devs at91_devs[] =
105{
106	DEVICE("at91_pmc", PMC,  0),
107	DEVICE("at91_wdt", WDT,  0),
108	DEVICE("at91_rst", RSTC, 0),
109	DEVICE("at91_pit", PIT,  0),
110	DEVICE("at91_pio", PIOA, 0),
111	DEVICE("at91_pio", PIOB, 1),
112	DEVICE("at91_pio", PIOC, 2),
113	DEVICE("at91_twi", TWI, 0),
114	DEVICE("at91_mci", MCI, 0),
115	DEVICE("uart", DBGU,   0),
116	DEVICE("uart", USART0, 1),
117	DEVICE("uart", USART1, 2),
118	DEVICE("uart", USART2, 3),
119	DEVICE("uart", USART3, 4),
120	DEVICE("uart", USART4, 5),
121	DEVICE("uart", USART5, 6),
122	DEVICE("spi",  SPI0,   0),
123	DEVICE("spi",  SPI1,   1),
124	DEVICE("ate",  EMAC,   0),
125	DEVICE("macb", EMAC,   0),
126	DEVICE("nand", NAND,   0),
127	DEVICE("ohci", OHCI,   0),
128	{ 0, 0, 0, 0, 0 }
129};
130
131static void
132at91_add_child(device_t dev, int prio, const char *name, int unit,
133    bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
134{
135	device_t kid;
136	struct at91_ivar *ivar;
137
138	kid = device_add_child_ordered(dev, prio, name, unit);
139	if (kid == NULL) {
140	    printf("Can't add child %s%d ordered\n", name, unit);
141	    return;
142	}
143	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
144	if (ivar == NULL) {
145		device_delete_child(dev, kid);
146		printf("Can't add alloc ivar\n");
147		return;
148	}
149	device_set_ivars(kid, ivar);
150	resource_list_init(&ivar->resources);
151	if (irq0 != -1) {
152		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
153		if (irq0 != AT91SAM9G20_IRQ_SYSTEM)
154			at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
155	}
156	if (irq1 != 0)
157		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
158	if (irq2 != 0)
159		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
160	if (addr != 0 && addr < AT91SAM9G20_BASE)
161		addr += AT91SAM9G20_BASE;
162	if (addr != 0)
163		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
164}
165
166static void
167at91_cpu_add_builtin_children(device_t dev)
168{
169	int i;
170	const struct cpu_devs *walker;
171
172	for (i = 1, walker = at91_devs; walker->name; i++, walker++) {
173		at91_add_child(dev, i, walker->name, walker->unit,
174		    walker->mem_base, walker->mem_len, walker->irq0,
175		    walker->irq1, walker->irq2);
176	}
177}
178
179static void
180at91_identify(driver_t *drv, device_t parent)
181{
182
183	if (at91_cpu_is(AT91_CPU_SAM9G20)) {
184		at91_add_child(parent, 0, "at91sam", 9, 0, 0, -1, 0, 0);
185		at91_cpu_add_builtin_children(parent);
186	}
187}
188
189static int
190at91_probe(device_t dev)
191{
192
193	if (at91_cpu_is(AT91_CPU_SAM9G20)) {
194		device_set_desc(dev, "AT91SAM9G20");
195		return (0);
196	}
197	return (ENXIO);
198}
199
200static int
201at91_attach(device_t dev)
202{
203	struct at91_pmc_clock *clk;
204	struct at91sam9_softc *sc = device_get_softc(dev);
205	int i;
206
207	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
208
209	sc->sc_st = at91sc->sc_st;
210	sc->sc_sh = at91sc->sc_sh;
211	sc->dev = dev;
212
213	/*
214	 * XXX These values work for the RM9200, SAM926[01], and SAM9G20
215	 * will have to fix this when we want to support anything else. XXX
216	 */
217	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_SYS_BASE,
218	    AT91SAM9G20_SYS_SIZE, &sc->sc_sys_sh) != 0)
219		panic("Enable to map system registers");
220
221	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_DBGU_BASE,
222	    AT91SAM9G20_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
223		panic("Enable to map DBGU registers");
224
225	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_AIC_BASE,
226	    AT91SAM9G20_AIC_SIZE, &sc->sc_aic_sh) != 0)
227		panic("Enable to map system registers");
228
229	/* XXX Hack to tell atmelarm about the AIC */
230	at91sc->sc_aic_sh = sc->sc_aic_sh;
231	at91sc->sc_irq_system = AT91SAM9G20_IRQ_SYSTEM;
232
233	for (i = 0; i < 32; i++) {
234		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
235		    i * 4, i);
236		/* Priority. */
237		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
238		    at91_irq_prio[i]);
239		if (i < 8)
240			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
241			    1);
242	}
243
244	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
245	/* No debug. */
246	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
247	/* Disable and clear all interrupts. */
248	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
249	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
250
251	/* Disable all interrupts for DBGU */
252	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);
253
254	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
255	    AT91SAM9G20_MATRIX_BASE, AT91SAM9G20_MATRIX_SIZE,
256	    &sc->sc_matrix_sh) != 0)
257		panic("Enable to map matrix registers");
258
259	/* activate NAND*/
260	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
261	    AT91SAM9G20_EBICSA);
262	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
263	    AT91SAM9G20_EBICSA,
264	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
265
266
267	/* Update USB device port clock info */
268	clk = at91_pmc_clock_ref("udpck");
269	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
270	at91_pmc_clock_deref(clk);
271
272	/* Update USB host port clock info */
273	clk = at91_pmc_clock_ref("uhpck");
274	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
275	at91_pmc_clock_deref(clk);
276
277	/* Each SOC has different PLL contraints */
278	clk = at91_pmc_clock_ref("plla");
279	clk->pll_min_in    = SAM9G20_PLL_A_MIN_IN_FREQ;		/*   2 MHz */
280	clk->pll_max_in    = SAM9G20_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
281	clk->pll_min_out   = SAM9G20_PLL_A_MIN_OUT_FREQ;	/* 400 MHz */
282	clk->pll_max_out   = SAM9G20_PLL_A_MAX_OUT_FREQ;	/* 800 MHz */
283	clk->pll_mul_shift = SAM9G20_PLL_A_MUL_SHIFT;
284	clk->pll_mul_mask  = SAM9G20_PLL_A_MUL_MASK;
285	clk->pll_div_shift = SAM9G20_PLL_A_DIV_SHIFT;
286	clk->pll_div_mask  = SAM9G20_PLL_A_DIV_MASK;
287	at91_pmc_clock_deref(clk);
288
289	clk = at91_pmc_clock_ref("pllb");
290	clk->pll_min_in    = SAM9G20_PLL_B_MIN_IN_FREQ;		/*   2 MHz */
291	clk->pll_max_in    = SAM9G20_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
292	clk->pll_min_out   = SAM9G20_PLL_B_MIN_OUT_FREQ;	/*  30 MHz */
293	clk->pll_max_out   = SAM9G20_PLL_B_MAX_OUT_FREQ;	/* 100 MHz */
294	clk->pll_mul_shift = SAM9G20_PLL_B_MUL_SHIFT;
295	clk->pll_mul_mask  = SAM9G20_PLL_B_MUL_MASK;
296	clk->pll_div_shift = SAM9G20_PLL_B_DIV_SHIFT;
297	clk->pll_div_mask  = SAM9G20_PLL_B_DIV_MASK;
298	at91_pmc_clock_deref(clk);
299	return (0);
300}
301
302static device_method_t at91_methods[] = {
303	DEVMETHOD(device_probe, at91_probe),
304	DEVMETHOD(device_attach, at91_attach),
305	DEVMETHOD(device_identify, at91_identify),
306	{0, 0},
307};
308
309static driver_t at91sam9_driver = {
310	"at91sam",
311	at91_methods,
312	sizeof(struct at91sam9_softc),
313};
314
315static devclass_t at91sam9_devclass;
316
317DRIVER_MODULE(at91sam, atmelarm, at91sam9_driver, at91sam9_devclass, 0, 0);
318