at91sam9x5.c revision 238331
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 238331 2012-07-10 02:39:03Z 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/at91reg.h>
42#include <arm/at91/at91_aicreg.h>
43#include <arm/at91/at91sam9x25reg.h>
44#include <arm/at91/at91_pmcreg.h>
45#include <arm/at91/at91_pmcvar.h>
46
47struct at91sam9x25_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/*
58 * Standard priority levels for the system.  0 is lowest and 7 is highest.
59 * These values are the ones Atmel uses for its Linux port
60 */
61static const int at91_irq_prio[32] =
62{
63	7,	/* Advanced Interrupt Controller (FIQ) */
64	7,	/* System Peripherals */
65	1,	/* Parallel IO Controller A and B */
66	1,	/* Parallel IO Controller C and D */
67	4,	/* Soft Modem */
68	5,	/* USART 0 */
69	5,	/* USART 1 */
70	5,	/* USART 2 */
71	5,	/* USART 3 */
72	6,	/* Two-Wire Interface 0 */
73	6,	/* Two-Wire Interface 1 */
74	6,	/* Two-Wire Interface 2 */
75	0,	/* Multimedia Card Interface 0 */
76	5,	/* Serial Peripheral Interface 0 */
77	5,	/* Serial Peripheral Interface 1 */
78	5,	/* UART 0 */
79	5,	/* UART 1 */
80	0,	/* Timer Counter 0, 1, 2, 3, 4 and 5 */
81	0,	/* Pulse Width Modulation Controller */
82	0,	/* ADC Controller */
83	0,	/* DMA Controller 0 */
84	0,	/* DMA Controller 1 */
85	2,	/* USB Host High Speed port */
86	2,	/* USB Device High speed port */
87	3,	/* Ethernet MAC 0 */
88	3,	/* LDC Controller or Image Sensor Interface */
89	0,	/* Multimedia Card Interface 1 */
90	3,	/* Ethernet MAC 1 */
91	4,	/* Synchronous Serial Interface */
92	4,	/* CAN Controller 0 */
93	4,	/* CAN Controller 1 */
94	0,	/* Advanced Interrupt Controller (IRQ0) */
95};
96
97#define DEVICE(_name, _id, _unit)		\
98	{					\
99		_name, _unit,			\
100		AT91SAM9X25_ ## _id ##_BASE,	\
101		AT91SAM9X25_ ## _id ## _SIZE,	\
102		AT91SAM9X25_IRQ_ ## _id		\
103	}
104
105static const struct cpu_devs at91_devs[] =
106{
107	DEVICE("at91_pmc", PMC,  0),
108	DEVICE("at91_wdt", WDT,  0),
109	DEVICE("at91_rst", RSTC, 0),
110	DEVICE("at91_pit", PIT,  0),
111	DEVICE("at91_pio", PIOA, 0),
112	DEVICE("at91_pio", PIOB, 1),
113	DEVICE("at91_pio", PIOC, 2),
114	DEVICE("at91_pio", PIOD, 3),
115	DEVICE("at91_twi", TWI0, 0),
116	DEVICE("at91_twi", TWI1, 1),
117	DEVICE("at91_twi", TWI2, 2),
118	DEVICE("at91_mci", HSMCI0, 0),
119	DEVICE("at91_mci", HSMCI1, 1),
120	DEVICE("uart", DBGU,   0),
121	DEVICE("uart", USART0, 1),
122	DEVICE("uart", USART1, 2),
123	DEVICE("uart", USART2, 3),
124	DEVICE("uart", USART3, 4),
125	DEVICE("spi",  SPI0,   0),
126	DEVICE("spi",  SPI1,   1),
127	DEVICE("macb", EMAC0,  0),
128	DEVICE("macb", EMAC1,  0),
129	DEVICE("nand", NAND,   0),
130	DEVICE("ohci", OHCI,   0),
131	DEVICE("ehci", EHCI,   0),
132	{ 0, 0, 0, 0, 0 }
133};
134
135static void
136at91_add_child(device_t dev, int prio, const char *name, int unit,
137    bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
138{
139	device_t kid;
140	struct at91_ivar *ivar;
141
142	kid = device_add_child_ordered(dev, prio, name, unit);
143	if (kid == NULL) {
144	    printf("Can't add child %s%d ordered\n", name, unit);
145	    return;
146	}
147	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
148	if (ivar == NULL) {
149		device_delete_child(dev, kid);
150		printf("Can't add alloc ivar\n");
151		return;
152	}
153	device_set_ivars(kid, ivar);
154	resource_list_init(&ivar->resources);
155	if (irq0 != -1) {
156		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
157		if (irq0 != AT91_IRQ_SYSTEM)
158			at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
159	}
160	if (irq1 != 0)
161		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
162	if (irq2 != 0)
163		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
164	if (addr != 0 && addr < AT91_BASE)
165		addr += AT91_BASE;
166	if (addr != 0)
167		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
168}
169
170static void
171at91_cpu_add_builtin_children(device_t dev)
172{
173	int i;
174	const struct cpu_devs *walker;
175
176	for (i = 1, walker = at91_devs; walker->name; i++, walker++) {
177		at91_add_child(dev, i, walker->name, walker->unit,
178		    walker->mem_base, walker->mem_len, walker->irq0,
179		    walker->irq1, walker->irq2);
180	}
181}
182
183static uint32_t
184at91_pll_outa(int freq)
185{
186
187	switch (freq / 10000000) {
188		case 747 ... 801: return ((1 << 29) | (0 << 14));
189		case 697 ... 746: return ((1 << 29) | (1 << 14));
190		case 647 ... 696: return ((1 << 29) | (2 << 14));
191		case 597 ... 646: return ((1 << 29) | (3 << 14));
192		case 547 ... 596: return ((1 << 29) | (1 << 14));
193		case 497 ... 546: return ((1 << 29) | (2 << 14));
194		case 447 ... 496: return ((1 << 29) | (3 << 14));
195		case 397 ... 446: return ((1 << 29) | (4 << 14));
196		default: return (1 << 29);
197	}
198}
199
200static uint32_t
201at91_pll_outb(int freq)
202{
203
204	return (0);
205}
206
207static void
208at91_identify(driver_t *drv, device_t parent)
209{
210
211	if (soc_data.type == AT91_T_SAM9X5 && soc_data.subtype == AT91_ST_SAM9X25) {
212		at91_add_child(parent, 0, "at91sam9x25", 0, 0, 0, -1, 0, 0);
213		at91_cpu_add_builtin_children(parent);
214	}
215}
216
217static int
218at91_probe(device_t dev)
219{
220
221	device_set_desc(dev, "AT91SAM9X25");
222	return (0);
223}
224
225static int
226at91_attach(device_t dev)
227{
228	struct at91_pmc_clock *clk;
229	struct at91sam9x25_softc *sc = device_get_softc(dev);
230	int i;
231
232	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
233
234	sc->sc_st = at91sc->sc_st;
235	sc->sc_sh = at91sc->sc_sh;
236	sc->dev = dev;
237
238	/*
239	 * XXX These values work for the RM9200, SAM926[01], and SAM9X25
240	 * will have to fix this when we want to support anything else. XXX
241	 */
242	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_SYS_BASE,
243	    AT91SAM9X25_SYS_SIZE, &sc->sc_sys_sh) != 0)
244		panic("Enable to map system registers");
245
246	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_DBGU_BASE,
247	    AT91SAM9X25_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
248		panic("Enable to map DBGU registers");
249
250	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_AIC_BASE,
251	    AT91SAM9X25_AIC_SIZE, &sc->sc_aic_sh) != 0)
252		panic("Enable to map system registers");
253
254	/* XXX Hack to tell atmelarm about the AIC */
255	at91sc->sc_aic_sh = sc->sc_aic_sh;
256	at91sc->sc_irq_system = AT91_IRQ_SYSTEM;
257
258	for (i = 0; i < 32; i++) {
259		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
260		    i * 4, i);
261		/* Priority. */
262		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
263		    at91_irq_prio[i]);
264		if (i < 8)
265			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
266			    1);
267	}
268
269	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
270	/* No debug. */
271	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
272	/* Disable and clear all interrupts. */
273	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
274	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
275
276	/* Disable all interrupts for DBGU */
277	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);
278
279	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
280	    AT91SAM9X25_MATRIX_BASE, AT91SAM9X25_MATRIX_SIZE,
281	    &sc->sc_matrix_sh) != 0)
282		panic("Enable to map matrix registers");
283
284#if 0 /* wrong, placeholder */
285	/* activate NAND*/
286	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
287	    AT91SAM9X25_EBICSA);
288	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
289	    AT91SAM9X25_EBICSA,
290	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
291#endif
292
293	/* Update USB device port clock info */
294	clk = at91_pmc_clock_ref("udpck");
295	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
296	at91_pmc_clock_deref(clk);
297
298	/* Update USB host port clock info */
299	clk = at91_pmc_clock_ref("uhpck");
300	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
301	at91_pmc_clock_deref(clk);
302
303	/* Each SOC has different PLL contraints */
304	clk = at91_pmc_clock_ref("plla");
305	clk->pll_min_in    = SAM9X25_PLL_A_MIN_IN_FREQ;		/*   2 MHz */
306	clk->pll_max_in    = SAM9X25_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
307	clk->pll_min_out   = SAM9X25_PLL_A_MIN_OUT_FREQ;	/* 400 MHz */
308	clk->pll_max_out   = SAM9X25_PLL_A_MAX_OUT_FREQ;	/* 800 MHz */
309	clk->pll_mul_shift = SAM9X25_PLL_A_MUL_SHIFT;
310	clk->pll_mul_mask  = SAM9X25_PLL_A_MUL_MASK;
311	clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT;
312	clk->pll_div_mask  = SAM9X25_PLL_A_DIV_MASK;
313	clk->set_outb      = at91_pll_outa;
314	at91_pmc_clock_deref(clk);
315
316	clk = at91_pmc_clock_ref("pllb");
317	clk->pll_min_in    = SAM9X25_PLL_B_MIN_IN_FREQ;		/*   2 MHz */
318	clk->pll_max_in    = SAM9X25_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
319	clk->pll_min_out   = SAM9X25_PLL_B_MIN_OUT_FREQ;	/*  30 MHz */
320	clk->pll_max_out   = SAM9X25_PLL_B_MAX_OUT_FREQ;	/* 100 MHz */
321	clk->pll_mul_shift = SAM9X25_PLL_B_MUL_SHIFT;
322	clk->pll_mul_mask  = SAM9X25_PLL_B_MUL_MASK;
323	clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT;
324	clk->pll_div_mask  = SAM9X25_PLL_B_DIV_MASK;
325	clk->set_outb      = at91_pll_outb;
326	at91_pmc_clock_deref(clk);
327	return (0);
328}
329
330static device_method_t at91sam9x25_methods[] = {
331	DEVMETHOD(device_probe, at91_probe),
332	DEVMETHOD(device_attach, at91_attach),
333	DEVMETHOD(device_identify, at91_identify),
334	{0, 0},
335};
336
337static driver_t at91sam9x25_driver = {
338	"at91sam9x25",
339	at91sam9x25_methods,
340	sizeof(struct at91sam9x25_softc),
341};
342
343static devclass_t at91sam9x25_devclass;
344
345DRIVER_MODULE(at91sam9x25, atmelarm, at91sam9x25_driver, at91sam9x25_devclass, 0, 0);
346