at91sam9g20.c revision 238390
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 238390 2012-07-12 04:23:11Z 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	bus_space_tag_t sc_st;
52	bus_space_handle_t sc_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		AT91SAM9G20_ ## _id ##_BASE,	\
100		AT91SAM9G20_ ## _id ## _SIZE,	\
101		AT91SAM9G20_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 uint32_t
132at91_pll_outa(int freq)
133{
134
135	switch (freq / 10000000) {
136		case 747 ... 801: return ((1 << 29) | (0 << 14));
137		case 697 ... 746: return ((1 << 29) | (1 << 14));
138		case 647 ... 696: return ((1 << 29) | (2 << 14));
139		case 597 ... 646: return ((1 << 29) | (3 << 14));
140		case 547 ... 596: return ((1 << 29) | (1 << 14));
141		case 497 ... 546: return ((1 << 29) | (2 << 14));
142		case 447 ... 496: return ((1 << 29) | (3 << 14));
143		case 397 ... 446: return ((1 << 29) | (4 << 14));
144		default: return (1 << 29);
145	}
146}
147
148static uint32_t
149at91_pll_outb(int freq)
150{
151
152	return (0);
153}
154
155static void
156at91_identify(driver_t *drv, device_t parent)
157{
158
159	if (at91_cpu_is(AT91_T_SAM9G20))
160		at91_add_child(parent, 0, "at91sam", 9, 0, 0, -1, 0, 0);
161}
162
163static int
164at91_probe(device_t dev)
165{
166
167	device_set_desc(dev, soc_info.name);
168	return (0);
169}
170
171static int
172at91_attach(device_t dev)
173{
174	struct at91_pmc_clock *clk;
175	struct at91sam9_softc *sc = device_get_softc(dev);
176	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
177	uint32_t i;
178
179	sc->sc_st = at91sc->sc_st;
180	sc->sc_sh = at91sc->sc_sh;
181
182	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
183	    AT91SAM9G20_MATRIX_BASE, AT91SAM9G20_MATRIX_SIZE,
184	    &sc->sc_matrix_sh) != 0)
185		panic("Enable to map matrix registers");
186
187	/* activate NAND*/
188	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
189	    AT91SAM9G20_EBICSA);
190	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
191	    AT91SAM9G20_EBICSA,
192	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
193
194
195	/* Update USB device port clock info */
196	clk = at91_pmc_clock_ref("udpck");
197	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
198	at91_pmc_clock_deref(clk);
199
200	/* Update USB host port clock info */
201	clk = at91_pmc_clock_ref("uhpck");
202	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
203	at91_pmc_clock_deref(clk);
204
205	/* Each SOC has different PLL contraints */
206	clk = at91_pmc_clock_ref("plla");
207	clk->pll_min_in    = SAM9G20_PLL_A_MIN_IN_FREQ;		/*   2 MHz */
208	clk->pll_max_in    = SAM9G20_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
209	clk->pll_min_out   = SAM9G20_PLL_A_MIN_OUT_FREQ;	/* 400 MHz */
210	clk->pll_max_out   = SAM9G20_PLL_A_MAX_OUT_FREQ;	/* 800 MHz */
211	clk->pll_mul_shift = SAM9G20_PLL_A_MUL_SHIFT;
212	clk->pll_mul_mask  = SAM9G20_PLL_A_MUL_MASK;
213	clk->pll_div_shift = SAM9G20_PLL_A_DIV_SHIFT;
214	clk->pll_div_mask  = SAM9G20_PLL_A_DIV_MASK;
215	clk->set_outb      = at91_pll_outa;
216	at91_pmc_clock_deref(clk);
217
218	clk = at91_pmc_clock_ref("pllb");
219	clk->pll_min_in    = SAM9G20_PLL_B_MIN_IN_FREQ;		/*   2 MHz */
220	clk->pll_max_in    = SAM9G20_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
221	clk->pll_min_out   = SAM9G20_PLL_B_MIN_OUT_FREQ;	/*  30 MHz */
222	clk->pll_max_out   = SAM9G20_PLL_B_MAX_OUT_FREQ;	/* 100 MHz */
223	clk->pll_mul_shift = SAM9G20_PLL_B_MUL_SHIFT;
224	clk->pll_mul_mask  = SAM9G20_PLL_B_MUL_MASK;
225	clk->pll_div_shift = SAM9G20_PLL_B_DIV_SHIFT;
226	clk->pll_div_mask  = SAM9G20_PLL_B_DIV_MASK;
227	clk->set_outb      = at91_pll_outb;
228	at91_pmc_clock_deref(clk);
229	return (0);
230}
231
232static device_method_t at91_methods[] = {
233	DEVMETHOD(device_probe, at91_probe),
234	DEVMETHOD(device_attach, at91_attach),
235	DEVMETHOD(device_identify, at91_identify),
236	{0, 0},
237};
238
239static driver_t at91sam9_driver = {
240	"at91sam",
241	at91_methods,
242	sizeof(struct at91sam9_softc),
243};
244
245static devclass_t at91sam9_devclass;
246
247DRIVER_MODULE(at91sam, atmelarm, at91sam9_driver, at91sam9_devclass, 0, 0);
248
249static struct at91_soc_data soc_data = {
250	.soc_delay = at91_pit_delay,
251	.soc_reset = at91_rst_cpu_reset,
252	.soc_irq_prio = at91_irq_prio,
253	.soc_childpren = at91_devs,
254};
255
256AT91_SOC(AT91_T_SAM9G20, &soc_data);
257