at91sam9g20.c revision 238376
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 238376 2012-07-11 20:17:14Z 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/at91soc.h>
43#include <arm/at91/at91_aicreg.h>
44#include <arm/at91/at91sam9g20reg.h>
45#include <arm/at91/at91_pitreg.h>
46#include <arm/at91/at91_pmcreg.h>
47#include <arm/at91/at91_pmcvar.h>
48#include <arm/at91/at91_rstreg.h>
49
50struct at91sam9_softc {
51	device_t dev;
52	bus_space_tag_t sc_st;
53	bus_space_handle_t sc_sh;
54	bus_space_handle_t sc_sys_sh;
55	bus_space_handle_t sc_aic_sh;
56	bus_space_handle_t sc_matrix_sh;
57};
58
59/*
60 * Standard priority levels for the system.  0 is lowest and 7 is highest.
61 * These values are the ones Atmel uses for its Linux port
62 */
63static const int at91_irq_prio[32] =
64{
65	7,	/* Advanced Interrupt Controller */
66	7,	/* System Peripherals */
67	1,	/* Parallel IO Controller A */
68	1,	/* Parallel IO Controller B */
69	1,	/* Parallel IO Controller C */
70	0,	/* Analog-to-Digital Converter */
71	5,	/* USART 0 */
72	5,	/* USART 1 */
73	5,	/* USART 2 */
74	0,	/* Multimedia Card Interface */
75	2,	/* USB Device Port */
76	6,	/* Two-Wire Interface */
77	5,	/* Serial Peripheral Interface 0 */
78	5,	/* Serial Peripheral Interface 1 */
79	5,	/* Serial Synchronous Controller */
80	0,	/* (reserved) */
81	0,	/* (reserved) */
82	0,	/* Timer Counter 0 */
83	0,	/* Timer Counter 1 */
84	0,	/* Timer Counter 2 */
85	2,	/* USB Host port */
86	3,	/* Ethernet */
87	0,	/* Image Sensor Interface */
88	5,	/* USART 3 */
89	5,	/* USART 4 */
90	5,	/* USART 5 */
91	0,	/* Timer Counter 3 */
92	0,	/* Timer Counter 4 */
93	0,	/* Timer Counter 5 */
94	0,	/* Advanced Interrupt Controller IRQ0 */
95	0,	/* Advanced Interrupt Controller IRQ1 */
96	0,	/* Advanced Interrupt Controller IRQ2 */
97};
98
99#define DEVICE(_name, _id, _unit)		\
100	{					\
101		_name, _unit,			\
102		AT91SAM9G20_ ## _id ##_BASE,	\
103		AT91SAM9G20_ ## _id ## _SIZE,	\
104		AT91SAM9G20_IRQ_ ## _id		\
105	}
106
107static const struct cpu_devs at91_devs[] =
108{
109	DEVICE("at91_pmc", PMC,  0),
110	DEVICE("at91_wdt", WDT,  0),
111	DEVICE("at91_rst", RSTC, 0),
112	DEVICE("at91_pit", PIT,  0),
113	DEVICE("at91_pio", PIOA, 0),
114	DEVICE("at91_pio", PIOB, 1),
115	DEVICE("at91_pio", PIOC, 2),
116	DEVICE("at91_twi", TWI, 0),
117	DEVICE("at91_mci", MCI, 0),
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("uart", USART4, 5),
124	DEVICE("uart", USART5, 6),
125	DEVICE("spi",  SPI0,   0),
126	DEVICE("spi",  SPI1,   1),
127	DEVICE("ate",  EMAC,   0),
128	DEVICE("macb", EMAC,   0),
129	DEVICE("nand", NAND,   0),
130	DEVICE("ohci", OHCI,   0),
131	{ 0, 0, 0, 0, 0 }
132};
133
134static void
135at91_cpu_add_builtin_children(device_t dev)
136{
137	int i;
138	const struct cpu_devs *walker;
139
140	for (i = 1, walker = at91_devs; walker->name; i++, walker++) {
141		at91_add_child(dev, i, walker->name, walker->unit,
142		    walker->mem_base, walker->mem_len, walker->irq0,
143		    walker->irq1, walker->irq2);
144	}
145}
146
147static uint32_t
148at91_pll_outa(int freq)
149{
150
151	switch (freq / 10000000) {
152		case 747 ... 801: return ((1 << 29) | (0 << 14));
153		case 697 ... 746: return ((1 << 29) | (1 << 14));
154		case 647 ... 696: return ((1 << 29) | (2 << 14));
155		case 597 ... 646: return ((1 << 29) | (3 << 14));
156		case 547 ... 596: return ((1 << 29) | (1 << 14));
157		case 497 ... 546: return ((1 << 29) | (2 << 14));
158		case 447 ... 496: return ((1 << 29) | (3 << 14));
159		case 397 ... 446: return ((1 << 29) | (4 << 14));
160		default: return (1 << 29);
161	}
162}
163
164static uint32_t
165at91_pll_outb(int freq)
166{
167
168	return (0);
169}
170
171static void
172at91_identify(driver_t *drv, device_t parent)
173{
174
175	if (at91_cpu_is(AT91_T_SAM9G20)) {
176		at91_add_child(parent, 0, "at91sam", 9, 0, 0, -1, 0, 0);
177		at91_cpu_add_builtin_children(parent);
178	}
179}
180
181static int
182at91_probe(device_t dev)
183{
184
185	device_set_desc(dev, soc_info.name);
186	return (0);
187}
188
189static int
190at91_attach(device_t dev)
191{
192	struct at91_pmc_clock *clk;
193	struct at91sam9_softc *sc = device_get_softc(dev);
194	int i;
195
196	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
197
198	sc->sc_st = at91sc->sc_st;
199	sc->sc_sh = at91sc->sc_sh;
200	sc->dev = dev;
201
202	/*
203	 * XXX These values work for the RM9200, SAM926[01], and SAM9G20
204	 * will have to fix this when we want to support anything else. XXX
205	 */
206	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_SYS_BASE,
207	    AT91SAM9G20_SYS_SIZE, &sc->sc_sys_sh) != 0)
208		panic("Enable to map system registers");
209
210	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_AIC_BASE,
211	    AT91SAM9G20_AIC_SIZE, &sc->sc_aic_sh) != 0)
212		panic("Enable to map system registers");
213
214	/* XXX Hack to tell atmelarm about the AIC */
215	at91sc->sc_aic_sh = sc->sc_aic_sh;
216
217	for (i = 0; i < 32; i++) {
218		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
219		    i * 4, i);
220		/* Priority. */
221		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
222		    at91_irq_prio[i]);
223		if (i < 8)
224			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
225			    1);
226	}
227
228	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
229	/* No debug. */
230	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
231	/* Disable and clear all interrupts. */
232	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
233	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
234
235	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
236	    AT91SAM9G20_MATRIX_BASE, AT91SAM9G20_MATRIX_SIZE,
237	    &sc->sc_matrix_sh) != 0)
238		panic("Enable to map matrix registers");
239
240	/* activate NAND*/
241	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
242	    AT91SAM9G20_EBICSA);
243	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
244	    AT91SAM9G20_EBICSA,
245	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
246
247
248	/* Update USB device port clock info */
249	clk = at91_pmc_clock_ref("udpck");
250	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
251	at91_pmc_clock_deref(clk);
252
253	/* Update USB host port clock info */
254	clk = at91_pmc_clock_ref("uhpck");
255	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
256	at91_pmc_clock_deref(clk);
257
258	/* Each SOC has different PLL contraints */
259	clk = at91_pmc_clock_ref("plla");
260	clk->pll_min_in    = SAM9G20_PLL_A_MIN_IN_FREQ;		/*   2 MHz */
261	clk->pll_max_in    = SAM9G20_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
262	clk->pll_min_out   = SAM9G20_PLL_A_MIN_OUT_FREQ;	/* 400 MHz */
263	clk->pll_max_out   = SAM9G20_PLL_A_MAX_OUT_FREQ;	/* 800 MHz */
264	clk->pll_mul_shift = SAM9G20_PLL_A_MUL_SHIFT;
265	clk->pll_mul_mask  = SAM9G20_PLL_A_MUL_MASK;
266	clk->pll_div_shift = SAM9G20_PLL_A_DIV_SHIFT;
267	clk->pll_div_mask  = SAM9G20_PLL_A_DIV_MASK;
268	clk->set_outb      = at91_pll_outa;
269	at91_pmc_clock_deref(clk);
270
271	clk = at91_pmc_clock_ref("pllb");
272	clk->pll_min_in    = SAM9G20_PLL_B_MIN_IN_FREQ;		/*   2 MHz */
273	clk->pll_max_in    = SAM9G20_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
274	clk->pll_min_out   = SAM9G20_PLL_B_MIN_OUT_FREQ;	/*  30 MHz */
275	clk->pll_max_out   = SAM9G20_PLL_B_MAX_OUT_FREQ;	/* 100 MHz */
276	clk->pll_mul_shift = SAM9G20_PLL_B_MUL_SHIFT;
277	clk->pll_mul_mask  = SAM9G20_PLL_B_MUL_MASK;
278	clk->pll_div_shift = SAM9G20_PLL_B_DIV_SHIFT;
279	clk->pll_div_mask  = SAM9G20_PLL_B_DIV_MASK;
280	clk->set_outb      = at91_pll_outb;
281	at91_pmc_clock_deref(clk);
282	return (0);
283}
284
285static device_method_t at91_methods[] = {
286	DEVMETHOD(device_probe, at91_probe),
287	DEVMETHOD(device_attach, at91_attach),
288	DEVMETHOD(device_identify, at91_identify),
289	{0, 0},
290};
291
292static driver_t at91sam9_driver = {
293	"at91sam",
294	at91_methods,
295	sizeof(struct at91sam9_softc),
296};
297
298static devclass_t at91sam9_devclass;
299
300DRIVER_MODULE(at91sam, atmelarm, at91sam9_driver, at91sam9_devclass, 0, 0);
301
302static struct at91_soc_data soc_data = {
303	.soc_delay = at91_pit_delay,
304	.soc_reset = at91_rst_cpu_reset
305};
306
307AT91_SOC(AT91_T_SAM9G20, &soc_data);
308