11844Swollman/*-
250476Speter * Copyright (c) 2005 Olivier Houchard.  All rights reserved.
31844Swollman * Copyright (c) 2010 Greg Ansley.  All rights reserved.
41638Srgrimes *
594940Sru * Redistribution and use in source and binary forms, with or without
61638Srgrimes * modification, are permitted provided that the following conditions
71844Swollman * are met:
81844Swollman * 1. Redistributions of source code must retain the above copyright
938655Sjb *    notice, this list of conditions and the following disclaimer.
101844Swollman * 2. Redistributions in binary form must reproduce the above copyright
111844Swollman *    notice, this list of conditions and the following disclaimer in the
1228945Speter *    documentation and/or other materials provided with the distribution.
131844Swollman *
1442915Sjdp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1542915Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1642915Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1742915Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1842915Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1942915Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2042915Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2142915Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2242915Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2342915Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2442915Sjdp * SUCH DAMAGE.
2542915Sjdp */
2629141Speter
2742915Sjdp#include <sys/cdefs.h>
2842915Sjdp__FBSDID("$FreeBSD$");
2942915Sjdp
3042915Sjdp#include <sys/param.h>
3142915Sjdp#include <sys/systm.h>
3242915Sjdp#include <sys/bus.h>
3342915Sjdp#include <sys/kernel.h>
3429141Speter#include <sys/malloc.h>
352827Sjkh#include <sys/module.h>
362827Sjkh
372827Sjkh#define	_ARM32_BUS_DMA_PRIVATE
382827Sjkh#include <machine/bus.h>
392827Sjkh
401638Srgrimes#include <arm/at91/at91var.h>
412827Sjkh#include <arm/at91/at91_aicreg.h>
421638Srgrimes#include <arm/at91/at91sam9260reg.h>
4343055Sjdp#include <arm/at91/at91_pmcreg.h>
4418529Sbde#include <arm/at91/at91_pmcvar.h>
4531809Sbde
4618529Sbdestruct at91sam9_softc {
471638Srgrimes	device_t dev;
4842450Sjdp	bus_space_tag_t sc_st;
491638Srgrimes	bus_space_handle_t sc_sh;
5095064Sobrien	bus_space_handle_t sc_sys_sh;
511638Srgrimes	bus_space_handle_t sc_aic_sh;
5292491Smarkm	bus_space_handle_t sc_dbg_sh;
5392491Smarkm	bus_space_handle_t sc_matrix_sh;
5492553Sru};
5592491Smarkm
5692491Smarkm/*
5792553Sru * Standard priority levels for the system.  0 is lowest and 7 is highest.
5892553Sru * These values are the ones Atmel uses for its Linux port
5992491Smarkm */
601638Srgrimesstatic const int at91_irq_prio[32] =
611844Swollman{
6238186Speter	7,	/* Advanced Interrupt Controller */
6338186Speter	7,	/* System Peripherals */
641638Srgrimes	1,	/* Parallel IO Controller A */
651638Srgrimes	1,	/* Parallel IO Controller B */
6624761Sjdp	1,	/* Parallel IO Controller C */
6738186Speter	0,	/* Analog-to-Digital Converter */
6838186Speter	5,	/* USART 0 */
691638Srgrimes	5,	/* USART 1 */
7042450Sjdp	5,	/* USART 2 */
711844Swollman	0,	/* Multimedia Card Interface */
7238186Speter	2,	/* USB Device Port */
7338186Speter	6,	/* Two-Wire Interface */
741844Swollman	5,	/* Serial Peripheral Interface 0 */
7536673Sdt	5,	/* Serial Peripheral Interface 1 */
761844Swollman	5,	/* Serial Synchronous Controller */
7738186Speter	0,	/* (reserved) */
7838186Speter	0,	/* (reserved) */
791844Swollman	0,	/* Timer Counter 0 */
8036673Sdt	0,	/* Timer Counter 1 */
8124761Sjdp	0,	/* Timer Counter 2 */
8238186Speter	2,	/* USB Host port */
8338186Speter	3,	/* Ethernet */
841844Swollman	0,	/* Image Sensor Interface */
8542450Sjdp	5,	/* USART 3 */
861844Swollman	5,	/* USART 4 */
8738186Speter	5,	/* USART 5 */
8838186Speter	0,	/* Timer Counter 3 */
891844Swollman	0,	/* Timer Counter 4 */
901844Swollman	0,	/* Timer Counter 5 */
911844Swollman	0,	/* Advanced Interrupt Controller IRQ0 */
9238186Speter	0,	/* Advanced Interrupt Controller IRQ1 */
9338186Speter	0,	/* Advanced Interrupt Controller IRQ2 */
941844Swollman};
951844Swollman
9624761Sjdp#define	DEVICE(_name, _id, _unit)		\
9738186Speter	{					\
9838186Speter		_name, _unit,			\
991844Swollman		AT91SAM9260_ ## _id ##_BASE,	\
10042450Sjdp		AT91SAM9260_ ## _id ## _SIZE,	\
1011844Swollman		AT91SAM9260_IRQ_ ## _id		\
10238186Speter	}
10338186Speter
1041844Swollmanstatic const struct cpu_devs at91_devs[] =
10536054Sbde{
10636054Sbde	DEVICE("at91_pmc", PMC,  0),
10738186Speter	DEVICE("at91_wdt", WDT,  0),
10838186Speter	DEVICE("at91_rst", RSTC, 0),
10936054Sbde	DEVICE("at91_pit", PIT,  0),
11036054Sbde	DEVICE("at91_pio", PIOA, 0),
11136054Sbde	DEVICE("at91_pio", PIOB, 1),
11238186Speter	DEVICE("at91_pio", PIOC, 2),
11338186Speter	DEVICE("at91_twi", TWI, 0),
11436054Sbde	DEVICE("at91_mci", MCI, 0),
11542450Sjdp	DEVICE("uart", DBGU,   0),
11636054Sbde	DEVICE("uart", USART0, 1),
11738186Speter	DEVICE("uart", USART1, 2),
11838186Speter	DEVICE("uart", USART2, 3),
11936054Sbde	DEVICE("uart", USART3, 4),
12095251Sru	DEVICE("uart", USART4, 5),
12126715Sasami	DEVICE("uart", USART5, 6),
12217510Speter	DEVICE("spi",  SPI0,   0),
12338186Speter	DEVICE("spi",  SPI1,   1),
12438186Speter	DEVICE("ate",  EMAC,   0),
1251638Srgrimes	DEVICE("macb", EMAC,   0),
12695251Sru	DEVICE("nand", NAND,   0),
12726715Sasami	DEVICE("ohci", OHCI,   0),
12817510Speter	{ 0, 0, 0, 0, 0 }
12938186Speter};
13038186Speter
1311638Srgrimesstatic void
13295251Sruat91_add_child(device_t dev, int prio, const char *name, int unit,
13395216Smarkm    bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2)
13495216Smarkm{
13538186Speter	device_t kid;
13638186Speter	struct at91_ivar *ivar;
1371638Srgrimes
1381844Swollman	kid = device_add_child_ordered(dev, prio, name, unit);
13926715Sasami	if (kid == NULL) {
14038186Speter	    printf("Can't add child %s%d ordered\n", name, unit);
14138186Speter	    return;
1421844Swollman	}
1431844Swollman	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
14426715Sasami	if (ivar == NULL) {
14538186Speter		device_delete_child(dev, kid);
14638186Speter		printf("Can't add alloc ivar\n");
1471844Swollman		return;
14842450Sjdp	}
14995216Smarkm	device_set_ivars(kid, ivar);
15095216Smarkm	resource_list_init(&ivar->resources);
15138186Speter	if (irq0 != -1) {
15238186Speter		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
1531844Swollman		if (irq0 != AT91SAM9260_IRQ_SYSTEM)
1542870Swollman			at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0);
1552868Swollman	}
1561638Srgrimes	if (irq1 != 0)
1571638Srgrimes		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
1581638Srgrimes	if (irq2 != 0)
1591638Srgrimes		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
1602870Swollman	if (addr != 0 && addr < AT91SAM9260_BASE)
1611638Srgrimes		addr += AT91SAM9260_BASE;
16242915Sjdp	if (addr != 0)
16342915Sjdp		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
1641638Srgrimes}
1651844Swollman
1661844Swollmanstatic void
1671844Swollmanat91_cpu_add_builtin_children(device_t dev)
1681638Srgrimes{
1691844Swollman	int i;
17092128Sobrien	const struct cpu_devs *walker;
17192128Sobrien
17292128Sobrien	for (i = 1, walker = at91_devs; walker->name; i++, walker++) {
1731844Swollman		at91_add_child(dev, i, walker->name, walker->unit,
1741844Swollman		    walker->mem_base, walker->mem_len, walker->irq0,
17592128Sobrien		    walker->irq1, walker->irq2);
1761638Srgrimes	}
17795114Sobrien}
17895114Sobrien
17995114Sobrienstatic uint32_t
18095114Sobrienat91_pll_outa(int freq)
18195114Sobrien{
18295114Sobrien
18395114Sobrien	if (freq > 195000000)
18495306Sru		return (0x20000000);
18595306Sru	else
18674805Sru		return (0x20008000);
18795306Sru}
18874805Sru
1891844Swollmanstatic uint32_t
1901844Swollmanat91_pll_outb(int freq)
1911844Swollman{
19242915Sjdp
19366534Speter	return (0x4000);
1941638Srgrimes}
19542915Sjdp
1961844Swollmanstatic void
1971638Srgrimesat91_identify(driver_t *drv, device_t parent)
19842915Sjdp{
1993859Sbde
2001638Srgrimes	switch (AT91_CPU(at91_chip_id)) {
2012353Sbde	case AT91_CPU_SAM9260:
2021638Srgrimes	case AT91_CPU_SAM9XE128:
20317400Sjkh	case AT91_CPU_SAM9XE256:
2041844Swollman	case AT91_CPU_SAM9XE512:
2053859Sbde		at91_add_child(parent, 0, "at91sam9260", 0, 0, 0, -1, 0, 0);
2061638Srgrimes		at91_cpu_add_builtin_children(parent);
20742450Sjdp		break;
20828945Speter	}
20942915Sjdp}
21042915Sjdp
21142915Sjdpstatic int
21242915Sjdpat91_probe(device_t dev)
21342915Sjdp{
21442915Sjdp	const char *desc;
21542915Sjdp
21638655Sjb	switch (AT91_CPU(at91_chip_id)) {
21791011Sru	case AT91_CPU_SAM9260:
21842915Sjdp		desc = "AT91SAM9260";
21991011Sru		break;
22028945Speter	case AT91_CPU_SAM9XE128:
22191011Sru		desc = "AT91SAM9XE128";
22242915Sjdp		break;
22391011Sru	case AT91_CPU_SAM9XE256:
22428945Speter		desc = "AT91SAM9XE256";
22542915Sjdp		break;
2261844Swollman	case AT91_CPU_SAM9XE512:
22742915Sjdp		desc = "AT91SAM9XE512";
2281844Swollman		break;
2292353Sbde	default:
2301844Swollman		return (ENXIO);
2315253Sache	}
2321844Swollman	device_set_desc(dev, desc);
2333859Sbde	return (0);
2341844Swollman}
23592553Sru
23692491Smarkmstatic int
23792553Sruat91_attach(device_t dev)
23892491Smarkm{
23992491Smarkm	struct at91_pmc_clock *clk;
24092491Smarkm	struct at91sam9_softc *sc = device_get_softc(dev);
2411638Srgrimes	int i;
2421638Srgrimes
24395306Sru	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));
24442915Sjdp
24592553Sru	sc->sc_st = at91sc->sc_st;
24638187Speter	sc->sc_sh = at91sc->sc_sh;
24742450Sjdp	sc->dev = dev;
24842915Sjdp
24942450Sjdp	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_SYS_BASE,
25092491Smarkm	    AT91SAM9260_SYS_SIZE, &sc->sc_sys_sh) != 0)
25116826Sphk		panic("Enable to map system registers");
25216437Sphk
2531638Srgrimes	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_DBGU_BASE,
25416437Sphk	    AT91SAM9260_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
2551638Srgrimes		panic("Enable to map DBGU registers");
25634179Sbde
25724750Sbde	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_AIC_BASE,
25842450Sjdp	    AT91SAM9260_AIC_SIZE, &sc->sc_aic_sh) != 0)
25924750Sbde		panic("Enable to map system registers");
26024750Sbde
26142915Sjdp	/* XXX Hack to tell atmelarm about the AIC */
26238655Sjb	at91sc->sc_aic_sh = sc->sc_aic_sh;
26342915Sjdp	at91sc->sc_irq_system = AT91SAM9260_IRQ_SYSTEM;
26491011Sru
26525468Sjdp	for (i = 0; i < 32; i++) {
26628945Speter		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
26731809Sbde		    i * 4, i);
26842915Sjdp		/* Priority. */
26927910Sasami		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
27028945Speter		    at91_irq_prio[i]);
27128945Speter		if (i < 8)
2721638Srgrimes			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
2731638Srgrimes			    1);
2741638Srgrimes	}
27555954Srgrimes
2761638Srgrimes	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
2771638Srgrimes	/* No debug. */
27855954Srgrimes	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
27955954Srgrimes	/* Disable and clear all interrupts. */
28055954Srgrimes	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
28155954Srgrimes	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);
28255954Srgrimes
28395216Smarkm	/* Disable all interrupts for DBGU */
28455954Srgrimes	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);
28555954Srgrimes
28655954Srgrimes	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
28748204Sjmg	    AT91SAM9260_MATRIX_BASE, AT91SAM9260_MATRIX_SIZE,
2882298Swollman	    &sc->sc_matrix_sh) != 0)
2892298Swollman		panic("Enable to map matrix registers");
2902298Swollman
29149328Shoek	/* activate NAND*/
29249328Shoek	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
29349328Shoek	    AT91SAM9260_EBICSA);
29449328Shoek	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
29556971Sru	    AT91SAM9260_EBICSA,
29649328Shoek	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
29749328Shoek
29849328Shoek	/* Update USB device port clock info */
29949328Shoek	clk = at91_pmc_clock_ref("udpck");
3001638Srgrimes	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
30195306Sru	at91_pmc_clock_deref(clk);
30295306Sru
3032298Swollman	/* Update USB host port clock info */
30492980Sdes	clk = at91_pmc_clock_ref("uhpck");
30549328Shoek	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
3061638Srgrimes	at91_pmc_clock_deref(clk);
30792980Sdes
30849328Shoek	/* Each SOC has different PLL contraints */
3091638Srgrimes	clk = at91_pmc_clock_ref("plla");
3102298Swollman	clk->pll_min_in    = SAM9260_PLL_A_MIN_IN_FREQ;		/*   1 MHz */
31142915Sjdp	clk->pll_max_in    = SAM9260_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
31248204Sjmg	clk->pll_min_out   = SAM9260_PLL_A_MIN_OUT_FREQ;	/*  80 MHz */
31349328Shoek	clk->pll_max_out   = SAM9260_PLL_A_MAX_OUT_FREQ;	/* 240 MHz */
31442915Sjdp	clk->pll_mul_shift = SAM9260_PLL_A_MUL_SHIFT;
31542915Sjdp	clk->pll_mul_mask  = SAM9260_PLL_A_MUL_MASK;
31644946Sbde	clk->pll_div_shift = SAM9260_PLL_A_DIV_SHIFT;
3171844Swollman	clk->pll_div_mask  = SAM9260_PLL_A_DIV_MASK;
31828945Speter	clk->set_outb      = at91_pll_outa;
3191844Swollman	at91_pmc_clock_deref(clk);
3201844Swollman
32149328Shoek	/*
3221844Swollman	 * Fudge MAX pll in frequence down below 3.0 MHz to ensure
3231638Srgrimes	 * PMC alogrithm choose the divisor that causes the input clock
3241638Srgrimes	 * to be near the optimal 2 MHz per datasheet.  We know
3251638Srgrimes	 * we are going to be using this for the USB clock at 96 MHz.
3261638Srgrimes	 * Causes no extra frequency deviation for all recomended crystal
3271638Srgrimes	 * values.
3281638Srgrimes	 */
3291638Srgrimes	clk = at91_pmc_clock_ref("pllb");
3302353Sbde	clk->pll_min_in    = SAM9260_PLL_B_MIN_IN_FREQ;		/*   1 MHz */
33144946Sbde	clk->pll_max_in    = SAM9260_PLL_B_MAX_IN_FREQ;		/*   5 MHz */
3321638Srgrimes	clk->pll_max_in    = 2999999;				/*  ~3 MHz */
3331638Srgrimes	clk->pll_min_out   = SAM9260_PLL_B_MIN_OUT_FREQ;	/*  70 MHz */
33444946Sbde	clk->pll_max_out   = SAM9260_PLL_B_MAX_OUT_FREQ;	/* 130 MHz */
33544946Sbde	clk->pll_mul_shift = SAM9260_PLL_B_MUL_SHIFT;
33644946Sbde	clk->pll_mul_mask  = SAM9260_PLL_B_MUL_MASK;
33744946Sbde	clk->pll_div_shift = SAM9260_PLL_B_DIV_SHIFT;
33844946Sbde	clk->pll_div_mask  = SAM9260_PLL_B_DIV_MASK;
33944946Sbde	clk->set_outb      = at91_pll_outb;
34044946Sbde	at91_pmc_clock_deref(clk);
34144946Sbde	return (0);
34244946Sbde}
34344946Sbde
34444946Sbdestatic device_method_t at91sam9260_methods[] = {
34592553Sru	DEVMETHOD(device_probe, at91_probe),
34692491Smarkm	DEVMETHOD(device_attach, at91_attach),
34792491Smarkm	DEVMETHOD(device_identify, at91_identify),
34892491Smarkm	DEVMETHOD_END
3491638Srgrimes};
35096162Sru
35196162Srustatic driver_t at91sam9260_driver = {
35296162Sru	"at91sam9260",
35396162Sru	at91sam9260_methods,
35495306Sru	sizeof(struct at91sam9_softc),
35595306Sru};
3561638Srgrimes
3571638Srgrimesstatic devclass_t at91sam9260_devclass;
3581638Srgrimes
35995306SruDRIVER_MODULE(at91sam9260, atmelarm, at91sam9260_driver, at91sam9260_devclass,
36092553Sru    NULL, NULL);
3611638Srgrimes