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