at91sam9x5.c revision 237742
1/*-
2 * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
3 * Copyright (c) 2010 Greg Ansley.  All rights reserved.
4 * Copyright (c) 2012 M. Warner Losh..  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9x25.c 237742 2012-06-29 04:18:52Z imp $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bus.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/module.h>
37
38#include <machine/bus.h>
39
40#include <arm/at91/at91var.h>
41#include <arm/at91/at91_aicreg.h>
42#include <arm/at91/at91sam9x25reg.h>
43#include <arm/at91/at91_pmcreg.h>
44#include <arm/at91/at91_pmcvar.h>
45
46struct at91sam9x25_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		AT91SAM9X25_ ## _id ##_BASE,	\
100		AT91SAM9X25_ ## _id ## _SIZE,	\
101		AT91SAM9X25_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", TWI0, 0),
114	DEVICE("at91_twi", TWI1, 1),
115	DEVICE("at91_twi", TWI2, 2),
116	DEVICE("at91_mci", HSMCI0, 0),
117	DEVICE("at91_mci", HSMCI1, 1),
118	DEVICE("uart", DBGU,   0),
119	DEVICE("uart", USART0, 1),
120	DEVICE("uart", USART1, 2),
121	DEVICE("uart", USART2, 3),
122	DEVICE("uart", USART3, 4),
123	DEVICE("spi",  SPI0,   0),
124	DEVICE("spi",  SPI1,   1),
125	DEVICE("macb", EMAC0,  0),
126	DEVICE("macb", EMAC1,  0),
127	DEVICE("nand", NAND,   0),
128	DEVICE("ohci", OHCI,   0),
129	DEVICE("ehci", EHCI,   0),
130	{ 0, 0, 0, 0, 0 }
131};
132
133static void
134at91_add_child(device_t dev, int prio, const char *name, int unit,
135    bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
136{
137	device_t kid;
138	struct at91_ivar *ivar;
139
140	kid = device_add_child_ordered(dev, prio, name, unit);
141	if (kid == NULL) {
142	    printf("Can't add child %s%d ordered\n", name, unit);
143	    return;
144	}
145	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
146	if (ivar == NULL) {
147		device_delete_child(dev, kid);
148		printf("Can't add alloc ivar\n");
149		return;
150	}
151	device_set_ivars(kid, ivar);
152	resource_list_init(&ivar->resources);
153	if (irq0 != -1) {
154		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
155		if (irq0 != AT91SAM9X25_IRQ_SYSTEM)
156			at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
157	}
158	if (irq1 != 0)
159		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
160	if (irq2 != 0)
161		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
162	if (addr != 0 && addr < AT91SAM9X25_BASE)
163		addr += AT91SAM9X25_BASE;
164	if (addr != 0)
165		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
166}
167
168static void
169at91_cpu_add_builtin_children(device_t dev)
170{
171	int i;
172	const struct cpu_devs *walker;
173
174	for (i = 1, walker = at91_devs; walker->name; i++, walker++) {
175		at91_add_child(dev, i, walker->name, walker->unit,
176		    walker->mem_base, walker->mem_len, walker->irq0,
177		    walker->irq1, walker->irq2);
178	}
179}
180
181static uint32_t
182at91_pll_outa(int freq)
183{
184
185	switch (freq / 10000000) {
186		case 747 ... 801: return ((1 << 29) | (0 << 14));
187		case 697 ... 746: return ((1 << 29) | (1 << 14));
188		case 647 ... 696: return ((1 << 29) | (2 << 14));
189		case 597 ... 646: return ((1 << 29) | (3 << 14));
190		case 547 ... 596: return ((1 << 29) | (1 << 14));
191		case 497 ... 546: return ((1 << 29) | (2 << 14));
192		case 447 ... 496: return ((1 << 29) | (3 << 14));
193		case 397 ... 446: return ((1 << 29) | (4 << 14));
194		default: return (1 << 29);
195	}
196}
197
198static uint32_t
199at91_pll_outb(int freq)
200{
201
202	return (0);
203}
204
205static void
206at91_identify(driver_t *drv, device_t parent)
207{
208
209	if (soc_data.type == AT91_T_SAM9X5 && soc_data.subtype == AT91_ST_SAM9X25) {
210		at91_add_child(parent, 0, "at91sam9x25", 0, 0, 0, -1, 0, 0);
211		at91_cpu_add_builtin_children(parent);
212	}
213}
214
215static int
216at91_probe(device_t dev)
217{
218
219	device_set_desc(dev, "AT91SAM9X25");
220	return (0);
221}
222
223static int
224at91_attach(device_t dev)
225{
226	struct at91_pmc_clock *clk;
227	struct at91sam9x25_softc *sc = device_get_softc(dev);
228	int i;
229
230	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
231
232	sc->sc_st = at91sc->sc_st;
233	sc->sc_sh = at91sc->sc_sh;
234	sc->dev = dev;
235
236	/*
237	 * XXX These values work for the RM9200, SAM926[01], and SAM9X25
238	 * will have to fix this when we want to support anything else. XXX
239	 */
240	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_SYS_BASE,
241	    AT91SAM9X25_SYS_SIZE, &sc->sc_sys_sh) != 0)
242		panic("Enable to map system registers");
243
244	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_DBGU_BASE,
245	    AT91SAM9X25_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
246		panic("Enable to map DBGU registers");
247
248	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_AIC_BASE,
249	    AT91SAM9X25_AIC_SIZE, &sc->sc_aic_sh) != 0)
250		panic("Enable to map system registers");
251
252	/* XXX Hack to tell atmelarm about the AIC */
253	at91sc->sc_aic_sh = sc->sc_aic_sh;
254	at91sc->sc_irq_system = AT91SAM9X25_IRQ_SYSTEM;
255
256	for (i = 0; i < 32; i++) {
257		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
258		    i * 4, i);
259		/* Priority. */
260		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
261		    at91_irq_prio[i]);
262		if (i < 8)
263			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
264			    1);
265	}
266
267	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
268	/* No debug. */
269	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
270	/* Disable and clear all interrupts. */
271	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
272	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
273
274	/* Disable all interrupts for DBGU */
275	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);
276
277	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
278	    AT91SAM9X25_MATRIX_BASE, AT91SAM9X25_MATRIX_SIZE,
279	    &sc->sc_matrix_sh) != 0)
280		panic("Enable to map matrix registers");
281
282#if 0 /* wrong, placeholder */
283	/* activate NAND*/
284	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
285	    AT91SAM9X25_EBICSA);
286	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
287	    AT91SAM9X25_EBICSA,
288	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
289#endif
290
291	/* Update USB device port clock info */
292	clk = at91_pmc_clock_ref("udpck");
293	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
294	at91_pmc_clock_deref(clk);
295
296	/* Update USB host port clock info */
297	clk = at91_pmc_clock_ref("uhpck");
298	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
299	at91_pmc_clock_deref(clk);
300
301	/* Each SOC has different PLL contraints */
302	clk = at91_pmc_clock_ref("plla");
303	clk->pll_min_in    = SAM9X25_PLL_A_MIN_IN_FREQ;		/*   2 MHz */
304	clk->pll_max_in    = SAM9X25_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
305	clk->pll_min_out   = SAM9X25_PLL_A_MIN_OUT_FREQ;	/* 400 MHz */
306	clk->pll_max_out   = SAM9X25_PLL_A_MAX_OUT_FREQ;	/* 800 MHz */
307	clk->pll_mul_shift = SAM9X25_PLL_A_MUL_SHIFT;
308	clk->pll_mul_mask  = SAM9X25_PLL_A_MUL_MASK;
309	clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT;
310	clk->pll_div_mask  = SAM9X25_PLL_A_DIV_MASK;
311	clk->set_outb      = at91_pll_outa;
312	at91_pmc_clock_deref(clk);
313
314	clk = at91_pmc_clock_ref("pllb");
315	clk->pll_min_in    = SAM9X25_PLL_B_MIN_IN_FREQ;		/*   2 MHz */
316	clk->pll_max_in    = SAM9X25_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
317	clk->pll_min_out   = SAM9X25_PLL_B_MIN_OUT_FREQ;	/*  30 MHz */
318	clk->pll_max_out   = SAM9X25_PLL_B_MAX_OUT_FREQ;	/* 100 MHz */
319	clk->pll_mul_shift = SAM9X25_PLL_B_MUL_SHIFT;
320	clk->pll_mul_mask  = SAM9X25_PLL_B_MUL_MASK;
321	clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT;
322	clk->pll_div_mask  = SAM9X25_PLL_B_DIV_MASK;
323	clk->set_outb      = at91_pll_outb;
324	at91_pmc_clock_deref(clk);
325	return (0);
326}
327
328static device_method_t at91sam9x25_methods[] = {
329	DEVMETHOD(device_probe, at91_probe),
330	DEVMETHOD(device_attach, at91_attach),
331	DEVMETHOD(device_identify, at91_identify),
332	{0, 0},
333};
334
335static driver_t at91sam9x25_driver = {
336	"at91sam9x25",
337	at91sam9x25_methods,
338	sizeof(struct at91sam9x25_softc),
339};
340
341static devclass_t at91sam9x25_devclass;
342
343DRIVER_MODULE(at91sam9x25, atmelarm, at91sam9x25_driver, at91sam9x25_devclass, 0, 0);
344