at91sam9x5.c revision 238330
1277302Shselasky/*-
2277302Shselasky * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
3277302Shselasky * Copyright (c) 2010 Greg Ansley.  All rights reserved.
4277302Shselasky * Copyright (c) 2012 M. Warner Losh..  All rights reserved.
5277302Shselasky *
6277302Shselasky * Redistribution and use in source and binary forms, with or without
7277302Shselasky * modification, are permitted provided that the following conditions
8277302Shselasky * are met:
9277302Shselasky * 1. Redistributions of source code must retain the above copyright
10277302Shselasky *    notice, this list of conditions and the following disclaimer.
11277302Shselasky * 2. Redistributions in binary form must reproduce the above copyright
12277302Shselasky *    notice, this list of conditions and the following disclaimer in the
13277302Shselasky *    documentation and/or other materials provided with the distribution.
14277302Shselasky *
15277302Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16277302Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17277302Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18277302Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19277302Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20277302Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21277302Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22277302Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23277302Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24277302Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25277302Shselasky * SUCH DAMAGE.
26277302Shselasky */
27289644Shselasky
28289644Shselasky#include <sys/cdefs.h>
29289644Shselasky__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9x25.c 238330 2012-07-10 02:14:50Z imp $");
30277302Shselasky
31277302Shselasky#include <sys/param.h>
32277302Shselasky#include <sys/systm.h>
33289749Shselasky#include <sys/bus.h>
34289749Shselasky#include <sys/kernel.h>
35277302Shselasky#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 (FIQ) */
63	7,	/* System Peripherals */
64	1,	/* Parallel IO Controller A and B */
65	1,	/* Parallel IO Controller C and D */
66	4,	/* Soft Modem */
67	5,	/* USART 0 */
68	5,	/* USART 1 */
69	5,	/* USART 2 */
70	5,	/* USART 3 */
71	6,	/* Two-Wire Interface 0 */
72	6,	/* Two-Wire Interface 1 */
73	6,	/* Two-Wire Interface 2 */
74	0,	/* Multimedia Card Interface 0 */
75	5,	/* Serial Peripheral Interface 0 */
76	5,	/* Serial Peripheral Interface 1 */
77	5,	/* UART 0 */
78	5,	/* UART 1 */
79	0,	/* Timer Counter 0, 1, 2, 3, 4 and 5 */
80	0,	/* Pulse Width Modulation Controller */
81	0,	/* ADC Controller */
82	0,	/* DMA Controller 0 */
83	0,	/* DMA Controller 1 */
84	2,	/* USB Host High Speed port */
85	2,	/* USB Device High speed port */
86	3,	/* Ethernet MAC 0 */
87	3,	/* LDC Controller or Image Sensor Interface */
88	0,	/* Multimedia Card Interface 1 */
89	3,	/* Ethernet MAC 1 */
90	4,	/* Synchronous Serial Interface */
91	4,	/* CAN Controller 0 */
92	4,	/* CAN Controller 1 */
93	0,	/* Advanced Interrupt Controller (IRQ0) */
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_pio", PIOD, 3),
114	DEVICE("at91_twi", TWI0, 0),
115	DEVICE("at91_twi", TWI1, 1),
116	DEVICE("at91_twi", TWI2, 2),
117	DEVICE("at91_mci", HSMCI0, 0),
118	DEVICE("at91_mci", HSMCI1, 1),
119	DEVICE("uart", DBGU,   0),
120	DEVICE("uart", USART0, 1),
121	DEVICE("uart", USART1, 2),
122	DEVICE("uart", USART2, 3),
123	DEVICE("uart", USART3, 4),
124	DEVICE("spi",  SPI0,   0),
125	DEVICE("spi",  SPI1,   1),
126	DEVICE("macb", EMAC0,  0),
127	DEVICE("macb", EMAC1,  0),
128	DEVICE("nand", NAND,   0),
129	DEVICE("ohci", OHCI,   0),
130	DEVICE("ehci", EHCI,   0),
131	{ 0, 0, 0, 0, 0 }
132};
133
134static void
135at91_add_child(device_t dev, int prio, const char *name, int unit,
136    bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
137{
138	device_t kid;
139	struct at91_ivar *ivar;
140
141	kid = device_add_child_ordered(dev, prio, name, unit);
142	if (kid == NULL) {
143	    printf("Can't add child %s%d ordered\n", name, unit);
144	    return;
145	}
146	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
147	if (ivar == NULL) {
148		device_delete_child(dev, kid);
149		printf("Can't add alloc ivar\n");
150		return;
151	}
152	device_set_ivars(kid, ivar);
153	resource_list_init(&ivar->resources);
154	if (irq0 != -1) {
155		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
156		if (irq0 != AT91SAM9X25_IRQ_SYSTEM)
157			at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
158	}
159	if (irq1 != 0)
160		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
161	if (irq2 != 0)
162		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
163	if (addr != 0 && addr < AT91_BASE)
164		addr += AT91_BASE;
165	if (addr != 0)
166		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
167}
168
169static void
170at91_cpu_add_builtin_children(device_t dev)
171{
172	int i;
173	const struct cpu_devs *walker;
174
175	for (i = 1, walker = at91_devs; walker->name; i++, walker++) {
176		at91_add_child(dev, i, walker->name, walker->unit,
177		    walker->mem_base, walker->mem_len, walker->irq0,
178		    walker->irq1, walker->irq2);
179	}
180}
181
182static uint32_t
183at91_pll_outa(int freq)
184{
185
186	switch (freq / 10000000) {
187		case 747 ... 801: return ((1 << 29) | (0 << 14));
188		case 697 ... 746: return ((1 << 29) | (1 << 14));
189		case 647 ... 696: return ((1 << 29) | (2 << 14));
190		case 597 ... 646: return ((1 << 29) | (3 << 14));
191		case 547 ... 596: return ((1 << 29) | (1 << 14));
192		case 497 ... 546: return ((1 << 29) | (2 << 14));
193		case 447 ... 496: return ((1 << 29) | (3 << 14));
194		case 397 ... 446: return ((1 << 29) | (4 << 14));
195		default: return (1 << 29);
196	}
197}
198
199static uint32_t
200at91_pll_outb(int freq)
201{
202
203	return (0);
204}
205
206static void
207at91_identify(driver_t *drv, device_t parent)
208{
209
210	if (soc_data.type == AT91_T_SAM9X5 && soc_data.subtype == AT91_ST_SAM9X25) {
211		at91_add_child(parent, 0, "at91sam9x25", 0, 0, 0, -1, 0, 0);
212		at91_cpu_add_builtin_children(parent);
213	}
214}
215
216static int
217at91_probe(device_t dev)
218{
219
220	device_set_desc(dev, "AT91SAM9X25");
221	return (0);
222}
223
224static int
225at91_attach(device_t dev)
226{
227	struct at91_pmc_clock *clk;
228	struct at91sam9x25_softc *sc = device_get_softc(dev);
229	int i;
230
231	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
232
233	sc->sc_st = at91sc->sc_st;
234	sc->sc_sh = at91sc->sc_sh;
235	sc->dev = dev;
236
237	/*
238	 * XXX These values work for the RM9200, SAM926[01], and SAM9X25
239	 * will have to fix this when we want to support anything else. XXX
240	 */
241	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_SYS_BASE,
242	    AT91SAM9X25_SYS_SIZE, &sc->sc_sys_sh) != 0)
243		panic("Enable to map system registers");
244
245	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_DBGU_BASE,
246	    AT91SAM9X25_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
247		panic("Enable to map DBGU registers");
248
249	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_AIC_BASE,
250	    AT91SAM9X25_AIC_SIZE, &sc->sc_aic_sh) != 0)
251		panic("Enable to map system registers");
252
253	/* XXX Hack to tell atmelarm about the AIC */
254	at91sc->sc_aic_sh = sc->sc_aic_sh;
255	at91sc->sc_irq_system = AT91SAM9X25_IRQ_SYSTEM;
256
257	for (i = 0; i < 32; i++) {
258		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
259		    i * 4, i);
260		/* Priority. */
261		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
262		    at91_irq_prio[i]);
263		if (i < 8)
264			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
265			    1);
266	}
267
268	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
269	/* No debug. */
270	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
271	/* Disable and clear all interrupts. */
272	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
273	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
274
275	/* Disable all interrupts for DBGU */
276	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);
277
278	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
279	    AT91SAM9X25_MATRIX_BASE, AT91SAM9X25_MATRIX_SIZE,
280	    &sc->sc_matrix_sh) != 0)
281		panic("Enable to map matrix registers");
282
283#if 0 /* wrong, placeholder */
284	/* activate NAND*/
285	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
286	    AT91SAM9X25_EBICSA);
287	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
288	    AT91SAM9X25_EBICSA,
289	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
290#endif
291
292	/* Update USB device port clock info */
293	clk = at91_pmc_clock_ref("udpck");
294	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
295	at91_pmc_clock_deref(clk);
296
297	/* Update USB host port clock info */
298	clk = at91_pmc_clock_ref("uhpck");
299	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
300	at91_pmc_clock_deref(clk);
301
302	/* Each SOC has different PLL contraints */
303	clk = at91_pmc_clock_ref("plla");
304	clk->pll_min_in    = SAM9X25_PLL_A_MIN_IN_FREQ;		/*   2 MHz */
305	clk->pll_max_in    = SAM9X25_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
306	clk->pll_min_out   = SAM9X25_PLL_A_MIN_OUT_FREQ;	/* 400 MHz */
307	clk->pll_max_out   = SAM9X25_PLL_A_MAX_OUT_FREQ;	/* 800 MHz */
308	clk->pll_mul_shift = SAM9X25_PLL_A_MUL_SHIFT;
309	clk->pll_mul_mask  = SAM9X25_PLL_A_MUL_MASK;
310	clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT;
311	clk->pll_div_mask  = SAM9X25_PLL_A_DIV_MASK;
312	clk->set_outb      = at91_pll_outa;
313	at91_pmc_clock_deref(clk);
314
315	clk = at91_pmc_clock_ref("pllb");
316	clk->pll_min_in    = SAM9X25_PLL_B_MIN_IN_FREQ;		/*   2 MHz */
317	clk->pll_max_in    = SAM9X25_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
318	clk->pll_min_out   = SAM9X25_PLL_B_MIN_OUT_FREQ;	/*  30 MHz */
319	clk->pll_max_out   = SAM9X25_PLL_B_MAX_OUT_FREQ;	/* 100 MHz */
320	clk->pll_mul_shift = SAM9X25_PLL_B_MUL_SHIFT;
321	clk->pll_mul_mask  = SAM9X25_PLL_B_MUL_MASK;
322	clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT;
323	clk->pll_div_mask  = SAM9X25_PLL_B_DIV_MASK;
324	clk->set_outb      = at91_pll_outb;
325	at91_pmc_clock_deref(clk);
326	return (0);
327}
328
329static device_method_t at91sam9x25_methods[] = {
330	DEVMETHOD(device_probe, at91_probe),
331	DEVMETHOD(device_attach, at91_attach),
332	DEVMETHOD(device_identify, at91_identify),
333	{0, 0},
334};
335
336static driver_t at91sam9x25_driver = {
337	"at91sam9x25",
338	at91sam9x25_methods,
339	sizeof(struct at91sam9x25_softc),
340};
341
342static devclass_t at91sam9x25_devclass;
343
344DRIVER_MODULE(at91sam9x25, atmelarm, at91sam9x25_driver, at91sam9x25_devclass, 0, 0);
345