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$");
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/at91sam9g20reg.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		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 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 != AT91SAM9G20_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 < AT91SAM9G20_BASE)
161		addr += AT91SAM9G20_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	switch (freq / 10000000) {
184		case 747 ... 801: return ((1 << 29) | (0 << 14));
185		case 697 ... 746: return ((1 << 29) | (1 << 14));
186		case 647 ... 696: return ((1 << 29) | (2 << 14));
187		case 597 ... 646: return ((1 << 29) | (3 << 14));
188		case 547 ... 596: return ((1 << 29) | (1 << 14));
189		case 497 ... 546: return ((1 << 29) | (2 << 14));
190		case 447 ... 496: return ((1 << 29) | (3 << 14));
191		case 397 ... 446: return ((1 << 29) | (4 << 14));
192		default: return (1 << 29);
193	}
194}
195
196static uint32_t
197at91_pll_outb(int freq)
198{
199
200	return (0);
201}
202
203static void
204at91_identify(driver_t *drv, device_t parent)
205{
206
207	if (at91_cpu_is(AT91_CPU_SAM9G20)) {
208		at91_add_child(parent, 0, "at91sam", 9, 0, 0, -1, 0, 0);
209		at91_cpu_add_builtin_children(parent);
210	}
211}
212
213static int
214at91_probe(device_t dev)
215{
216
217	if (at91_cpu_is(AT91_CPU_SAM9G20)) {
218		device_set_desc(dev, "AT91SAM9G20");
219		return (0);
220	}
221	return (ENXIO);
222}
223
224static int
225at91_attach(device_t dev)
226{
227	struct at91_pmc_clock *clk;
228	struct at91sam9_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 SAM9G20
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, AT91SAM9G20_SYS_BASE,
242	    AT91SAM9G20_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, AT91SAM9G20_DBGU_BASE,
246	    AT91SAM9G20_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, AT91SAM9G20_AIC_BASE,
250	    AT91SAM9G20_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 = AT91SAM9G20_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	    AT91SAM9G20_MATRIX_BASE, AT91SAM9G20_MATRIX_SIZE,
280	    &sc->sc_matrix_sh) != 0)
281		panic("Enable to map matrix registers");
282
283	/* activate NAND*/
284	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
285	    AT91SAM9G20_EBICSA);
286	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
287	    AT91SAM9G20_EBICSA,
288	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
289
290
291	/* Update USB device port clock info */
292	clk = at91_pmc_clock_ref("udpck");
293	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
294	at91_pmc_clock_deref(clk);
295
296	/* Update USB host port clock info */
297	clk = at91_pmc_clock_ref("uhpck");
298	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
299	at91_pmc_clock_deref(clk);
300
301	/* Each SOC has different PLL contraints */
302	clk = at91_pmc_clock_ref("plla");
303	clk->pll_min_in    = SAM9G20_PLL_A_MIN_IN_FREQ;		/*   2 MHz */
304	clk->pll_max_in    = SAM9G20_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
305	clk->pll_min_out   = SAM9G20_PLL_A_MIN_OUT_FREQ;	/* 400 MHz */
306	clk->pll_max_out   = SAM9G20_PLL_A_MAX_OUT_FREQ;	/* 800 MHz */
307	clk->pll_mul_shift = SAM9G20_PLL_A_MUL_SHIFT;
308	clk->pll_mul_mask  = SAM9G20_PLL_A_MUL_MASK;
309	clk->pll_div_shift = SAM9G20_PLL_A_DIV_SHIFT;
310	clk->pll_div_mask  = SAM9G20_PLL_A_DIV_MASK;
311	clk->set_outb      = at91_pll_outa;
312	at91_pmc_clock_deref(clk);
313
314	clk = at91_pmc_clock_ref("pllb");
315	clk->pll_min_in    = SAM9G20_PLL_B_MIN_IN_FREQ;		/*   2 MHz */
316	clk->pll_max_in    = SAM9G20_PLL_B_MAX_IN_FREQ;		/*  32 MHz */
317	clk->pll_min_out   = SAM9G20_PLL_B_MIN_OUT_FREQ;	/*  30 MHz */
318	clk->pll_max_out   = SAM9G20_PLL_B_MAX_OUT_FREQ;	/* 100 MHz */
319	clk->pll_mul_shift = SAM9G20_PLL_B_MUL_SHIFT;
320	clk->pll_mul_mask  = SAM9G20_PLL_B_MUL_MASK;
321	clk->pll_div_shift = SAM9G20_PLL_B_DIV_SHIFT;
322	clk->pll_div_mask  = SAM9G20_PLL_B_DIV_MASK;
323	clk->set_outb      = at91_pll_outb;
324	at91_pmc_clock_deref(clk);
325	return (0);
326}
327
328static device_method_t at91_methods[] = {
329	DEVMETHOD(device_probe, at91_probe),
330	DEVMETHOD(device_attach, at91_attach),
331	DEVMETHOD(device_identify, at91_identify),
332	{0, 0},
333};
334
335static driver_t at91sam9_driver = {
336	"at91sam",
337	at91_methods,
338	sizeof(struct at91sam9_softc),
339};
340
341static devclass_t at91sam9_devclass;
342
343DRIVER_MODULE(at91sam, atmelarm, at91sam9_driver, at91sam9_devclass, 0, 0);
344