at91sam9260.c revision 236658
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/at91sam9260.c 236658 2012-06-06 06:19:52Z 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/at91_aicreg.h>
42#include <arm/at91/at91sam9260reg.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		AT91SAM9260_ ## _id ##_BASE,	\
100		AT91SAM9260_ ## _id ## _SIZE,	\
101		AT91SAM9260_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 != AT91SAM9260_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 < AT91SAM9260_BASE)
161		addr += AT91SAM9260_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 uint32_t
180at91_pll_outa(int freq)
181{
182
183	if (freq > 195000000)
184		return (0x20000000);
185	else
186		return (0x20008000);
187}
188
189static uint32_t
190at91_pll_outb(int freq)
191{
192
193	return (0x4000);
194}
195
196static void
197at91_identify(driver_t *drv, device_t parent)
198{
199
200	if (soc_data.type == AT91_CPU_SAM9260) {
201		at91_add_child(parent, 0, "at91sam9260", 0, 0, 0, -1, 0, 0);
202		at91_cpu_add_builtin_children(parent);
203		break;
204	}
205}
206
207static int
208at91_probe(device_t dev)
209{
210
211	device_set_desc(dev, soc_data.name);
212	return (0);
213}
214
215static int
216at91_attach(device_t dev)
217{
218	struct at91_pmc_clock *clk;
219	struct at91sam9_softc *sc = device_get_softc(dev);
220	int i;
221
222	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
223
224	sc->sc_st = at91sc->sc_st;
225	sc->sc_sh = at91sc->sc_sh;
226	sc->dev = dev;
227
228	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_SYS_BASE,
229	    AT91SAM9260_SYS_SIZE, &sc->sc_sys_sh) != 0)
230		panic("Enable to map system registers");
231
232	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_DBGU_BASE,
233	    AT91SAM9260_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
234		panic("Enable to map DBGU registers");
235
236	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_AIC_BASE,
237	    AT91SAM9260_AIC_SIZE, &sc->sc_aic_sh) != 0)
238		panic("Enable to map system registers");
239
240	/* XXX Hack to tell atmelarm about the AIC */
241	at91sc->sc_aic_sh = sc->sc_aic_sh;
242	at91sc->sc_irq_system = AT91SAM9260_IRQ_SYSTEM;
243
244	for (i = 0; i < 32; i++) {
245		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
246		    i * 4, i);
247		/* Priority. */
248		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
249		    at91_irq_prio[i]);
250		if (i < 8)
251			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
252			    1);
253	}
254
255	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
256	/* No debug. */
257	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
258	/* Disable and clear all interrupts. */
259	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
260	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
261
262	/* Disable all interrupts for DBGU */
263	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);
264
265	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
266	    AT91SAM9260_MATRIX_BASE, AT91SAM9260_MATRIX_SIZE,
267	    &sc->sc_matrix_sh) != 0)
268		panic("Enable to map matrix registers");
269
270	/* activate NAND*/
271	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
272	    AT91SAM9260_EBICSA);
273	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
274	    AT91SAM9260_EBICSA,
275	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
276
277	/* Update USB device port clock info */
278	clk = at91_pmc_clock_ref("udpck");
279	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
280	at91_pmc_clock_deref(clk);
281
282	/* Update USB host port clock info */
283	clk = at91_pmc_clock_ref("uhpck");
284	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
285	at91_pmc_clock_deref(clk);
286
287	/* Each SOC has different PLL contraints */
288	clk = at91_pmc_clock_ref("plla");
289	clk->pll_min_in    = SAM9260_PLL_A_MIN_IN_FREQ;		/*   1 MHz */
290	clk->pll_max_in    = SAM9260_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
291	clk->pll_min_out   = SAM9260_PLL_A_MIN_OUT_FREQ;	/*  80 MHz */
292	clk->pll_max_out   = SAM9260_PLL_A_MAX_OUT_FREQ;	/* 240 MHz */
293	clk->pll_mul_shift = SAM9260_PLL_A_MUL_SHIFT;
294	clk->pll_mul_mask  = SAM9260_PLL_A_MUL_MASK;
295	clk->pll_div_shift = SAM9260_PLL_A_DIV_SHIFT;
296	clk->pll_div_mask  = SAM9260_PLL_A_DIV_MASK;
297	clk->set_outb      = at91_pll_outa;
298	at91_pmc_clock_deref(clk);
299
300	/*
301	 * Fudge MAX pll in frequence down below 3.0 MHz to ensure
302	 * PMC alogrithm choose the divisor that causes the input clock
303	 * to be near the optimal 2 MHz per datasheet.  We know
304	 * we are going to be using this for the USB clock at 96 MHz.
305	 * Causes no extra frequency deviation for all recomended crystal
306	 * values.
307	 */
308	clk = at91_pmc_clock_ref("pllb");
309	clk->pll_min_in    = SAM9260_PLL_B_MIN_IN_FREQ;		/*   1 MHz */
310	clk->pll_max_in    = SAM9260_PLL_B_MAX_IN_FREQ;		/*   5 MHz */
311	clk->pll_max_in    = 2999999;				/*  ~3 MHz */
312	clk->pll_min_out   = SAM9260_PLL_B_MIN_OUT_FREQ;	/*  70 MHz */
313	clk->pll_max_out   = SAM9260_PLL_B_MAX_OUT_FREQ;	/* 130 MHz */
314	clk->pll_mul_shift = SAM9260_PLL_B_MUL_SHIFT;
315	clk->pll_mul_mask  = SAM9260_PLL_B_MUL_MASK;
316	clk->pll_div_shift = SAM9260_PLL_B_DIV_SHIFT;
317	clk->pll_div_mask  = SAM9260_PLL_B_DIV_MASK;
318	clk->set_outb      = at91_pll_outb;
319	at91_pmc_clock_deref(clk);
320	return (0);
321}
322
323static device_method_t at91sam9260_methods[] = {
324	DEVMETHOD(device_probe, at91_probe),
325	DEVMETHOD(device_attach, at91_attach),
326	DEVMETHOD(device_identify, at91_identify),
327	DEVMETHOD_END
328};
329
330static driver_t at91sam9260_driver = {
331	"at91sam9260",
332	at91sam9260_methods,
333	sizeof(struct at91sam9_softc),
334};
335
336static devclass_t at91sam9260_devclass;
337
338DRIVER_MODULE(at91sam9260, atmelarm, at91sam9260_driver, at91sam9260_devclass,
339    NULL, NULL);
340