at91sam9g20.c revision 238331
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 238331 2012-07-10 02:39:03Z 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/at91_aicreg.h> 43#include <arm/at91/at91sam9g20reg.h> 44#include <arm/at91/at91_pmcreg.h> 45#include <arm/at91/at91_pmcvar.h> 46 47struct at91sam9_softc { 48 device_t dev; 49 bus_space_tag_t sc_st; 50 bus_space_handle_t sc_sh; 51 bus_space_handle_t sc_sys_sh; 52 bus_space_handle_t sc_aic_sh; 53 bus_space_handle_t sc_dbg_sh; 54 bus_space_handle_t sc_matrix_sh; 55}; 56 57/* 58 * Standard priority levels for the system. 0 is lowest and 7 is highest. 59 * These values are the ones Atmel uses for its Linux port 60 */ 61static const int at91_irq_prio[32] = 62{ 63 7, /* Advanced Interrupt Controller */ 64 7, /* System Peripherals */ 65 1, /* Parallel IO Controller A */ 66 1, /* Parallel IO Controller B */ 67 1, /* Parallel IO Controller C */ 68 0, /* Analog-to-Digital Converter */ 69 5, /* USART 0 */ 70 5, /* USART 1 */ 71 5, /* USART 2 */ 72 0, /* Multimedia Card Interface */ 73 2, /* USB Device Port */ 74 6, /* Two-Wire Interface */ 75 5, /* Serial Peripheral Interface 0 */ 76 5, /* Serial Peripheral Interface 1 */ 77 5, /* Serial Synchronous Controller */ 78 0, /* (reserved) */ 79 0, /* (reserved) */ 80 0, /* Timer Counter 0 */ 81 0, /* Timer Counter 1 */ 82 0, /* Timer Counter 2 */ 83 2, /* USB Host port */ 84 3, /* Ethernet */ 85 0, /* Image Sensor Interface */ 86 5, /* USART 3 */ 87 5, /* USART 4 */ 88 5, /* USART 5 */ 89 0, /* Timer Counter 3 */ 90 0, /* Timer Counter 4 */ 91 0, /* Timer Counter 5 */ 92 0, /* Advanced Interrupt Controller IRQ0 */ 93 0, /* Advanced Interrupt Controller IRQ1 */ 94 0, /* Advanced Interrupt Controller IRQ2 */ 95}; 96 97#define DEVICE(_name, _id, _unit) \ 98 { \ 99 _name, _unit, \ 100 AT91SAM9G20_ ## _id ##_BASE, \ 101 AT91SAM9G20_ ## _id ## _SIZE, \ 102 AT91SAM9G20_IRQ_ ## _id \ 103 } 104 105static const struct cpu_devs at91_devs[] = 106{ 107 DEVICE("at91_pmc", PMC, 0), 108 DEVICE("at91_wdt", WDT, 0), 109 DEVICE("at91_rst", RSTC, 0), 110 DEVICE("at91_pit", PIT, 0), 111 DEVICE("at91_pio", PIOA, 0), 112 DEVICE("at91_pio", PIOB, 1), 113 DEVICE("at91_pio", PIOC, 2), 114 DEVICE("at91_twi", TWI, 0), 115 DEVICE("at91_mci", MCI, 0), 116 DEVICE("uart", DBGU, 0), 117 DEVICE("uart", USART0, 1), 118 DEVICE("uart", USART1, 2), 119 DEVICE("uart", USART2, 3), 120 DEVICE("uart", USART3, 4), 121 DEVICE("uart", USART4, 5), 122 DEVICE("uart", USART5, 6), 123 DEVICE("spi", SPI0, 0), 124 DEVICE("spi", SPI1, 1), 125 DEVICE("ate", EMAC, 0), 126 DEVICE("macb", EMAC, 0), 127 DEVICE("nand", NAND, 0), 128 DEVICE("ohci", OHCI, 0), 129 { 0, 0, 0, 0, 0 } 130}; 131 132static void 133at91_add_child(device_t dev, int prio, const char *name, int unit, 134 bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) 135{ 136 device_t kid; 137 struct at91_ivar *ivar; 138 139 kid = device_add_child_ordered(dev, prio, name, unit); 140 if (kid == NULL) { 141 printf("Can't add child %s%d ordered\n", name, unit); 142 return; 143 } 144 ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 145 if (ivar == NULL) { 146 device_delete_child(dev, kid); 147 printf("Can't add alloc ivar\n"); 148 return; 149 } 150 device_set_ivars(kid, ivar); 151 resource_list_init(&ivar->resources); 152 if (irq0 != -1) { 153 bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); 154 if (irq0 != AT91_IRQ_SYSTEM) 155 at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); 156 } 157 if (irq1 != 0) 158 bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); 159 if (irq2 != 0) 160 bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); 161 if (addr != 0 && addr < AT91_BASE) 162 addr += AT91_BASE; 163 if (addr != 0) 164 bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); 165} 166 167static void 168at91_cpu_add_builtin_children(device_t dev) 169{ 170 int i; 171 const struct cpu_devs *walker; 172 173 for (i = 1, walker = at91_devs; walker->name; i++, walker++) { 174 at91_add_child(dev, i, walker->name, walker->unit, 175 walker->mem_base, walker->mem_len, walker->irq0, 176 walker->irq1, walker->irq2); 177 } 178} 179 180static uint32_t 181at91_pll_outa(int freq) 182{ 183 184 switch (freq / 10000000) { 185 case 747 ... 801: return ((1 << 29) | (0 << 14)); 186 case 697 ... 746: return ((1 << 29) | (1 << 14)); 187 case 647 ... 696: return ((1 << 29) | (2 << 14)); 188 case 597 ... 646: return ((1 << 29) | (3 << 14)); 189 case 547 ... 596: return ((1 << 29) | (1 << 14)); 190 case 497 ... 546: return ((1 << 29) | (2 << 14)); 191 case 447 ... 496: return ((1 << 29) | (3 << 14)); 192 case 397 ... 446: return ((1 << 29) | (4 << 14)); 193 default: return (1 << 29); 194 } 195} 196 197static uint32_t 198at91_pll_outb(int freq) 199{ 200 201 return (0); 202} 203 204static void 205at91_identify(driver_t *drv, device_t parent) 206{ 207 208 if (at91_cpu_is(AT91_T_SAM9G20)) { 209 at91_add_child(parent, 0, "at91sam", 9, 0, 0, -1, 0, 0); 210 at91_cpu_add_builtin_children(parent); 211 } 212} 213 214static int 215at91_probe(device_t dev) 216{ 217 218 device_set_desc(dev, soc_data.name); 219 return (0); 220} 221 222static int 223at91_attach(device_t dev) 224{ 225 struct at91_pmc_clock *clk; 226 struct at91sam9_softc *sc = device_get_softc(dev); 227 int i; 228 229 struct at91_softc *at91sc = device_get_softc(device_get_parent(dev)); 230 231 sc->sc_st = at91sc->sc_st; 232 sc->sc_sh = at91sc->sc_sh; 233 sc->dev = dev; 234 235 /* 236 * XXX These values work for the RM9200, SAM926[01], and SAM9G20 237 * will have to fix this when we want to support anything else. XXX 238 */ 239 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_SYS_BASE, 240 AT91SAM9G20_SYS_SIZE, &sc->sc_sys_sh) != 0) 241 panic("Enable to map system registers"); 242 243 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_DBGU_BASE, 244 AT91SAM9G20_DBGU_SIZE, &sc->sc_dbg_sh) != 0) 245 panic("Enable to map DBGU registers"); 246 247 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_AIC_BASE, 248 AT91SAM9G20_AIC_SIZE, &sc->sc_aic_sh) != 0) 249 panic("Enable to map system registers"); 250 251 /* XXX Hack to tell atmelarm about the AIC */ 252 at91sc->sc_aic_sh = sc->sc_aic_sh; 253 at91sc->sc_irq_system = AT91_IRQ_SYSTEM; 254 255 for (i = 0; i < 32; i++) { 256 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR + 257 i * 4, i); 258 /* Priority. */ 259 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4, 260 at91_irq_prio[i]); 261 if (i < 8) 262 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR, 263 1); 264 } 265 266 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32); 267 /* No debug. */ 268 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0); 269 /* Disable and clear all interrupts. */ 270 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff); 271 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff); 272 273 /* Disable all interrupts for DBGU */ 274 bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff); 275 276 if (bus_space_subregion(sc->sc_st, sc->sc_sh, 277 AT91SAM9G20_MATRIX_BASE, AT91SAM9G20_MATRIX_SIZE, 278 &sc->sc_matrix_sh) != 0) 279 panic("Enable to map matrix registers"); 280 281 /* activate NAND*/ 282 i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh, 283 AT91SAM9G20_EBICSA); 284 bus_space_write_4(sc->sc_st, sc->sc_matrix_sh, 285 AT91SAM9G20_EBICSA, 286 i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); 287 288 289 /* Update USB device port clock info */ 290 clk = at91_pmc_clock_ref("udpck"); 291 clk->pmc_mask = PMC_SCER_UDP_SAM9; 292 at91_pmc_clock_deref(clk); 293 294 /* Update USB host port clock info */ 295 clk = at91_pmc_clock_ref("uhpck"); 296 clk->pmc_mask = PMC_SCER_UHP_SAM9; 297 at91_pmc_clock_deref(clk); 298 299 /* Each SOC has different PLL contraints */ 300 clk = at91_pmc_clock_ref("plla"); 301 clk->pll_min_in = SAM9G20_PLL_A_MIN_IN_FREQ; /* 2 MHz */ 302 clk->pll_max_in = SAM9G20_PLL_A_MAX_IN_FREQ; /* 32 MHz */ 303 clk->pll_min_out = SAM9G20_PLL_A_MIN_OUT_FREQ; /* 400 MHz */ 304 clk->pll_max_out = SAM9G20_PLL_A_MAX_OUT_FREQ; /* 800 MHz */ 305 clk->pll_mul_shift = SAM9G20_PLL_A_MUL_SHIFT; 306 clk->pll_mul_mask = SAM9G20_PLL_A_MUL_MASK; 307 clk->pll_div_shift = SAM9G20_PLL_A_DIV_SHIFT; 308 clk->pll_div_mask = SAM9G20_PLL_A_DIV_MASK; 309 clk->set_outb = at91_pll_outa; 310 at91_pmc_clock_deref(clk); 311 312 clk = at91_pmc_clock_ref("pllb"); 313 clk->pll_min_in = SAM9G20_PLL_B_MIN_IN_FREQ; /* 2 MHz */ 314 clk->pll_max_in = SAM9G20_PLL_B_MAX_IN_FREQ; /* 32 MHz */ 315 clk->pll_min_out = SAM9G20_PLL_B_MIN_OUT_FREQ; /* 30 MHz */ 316 clk->pll_max_out = SAM9G20_PLL_B_MAX_OUT_FREQ; /* 100 MHz */ 317 clk->pll_mul_shift = SAM9G20_PLL_B_MUL_SHIFT; 318 clk->pll_mul_mask = SAM9G20_PLL_B_MUL_MASK; 319 clk->pll_div_shift = SAM9G20_PLL_B_DIV_SHIFT; 320 clk->pll_div_mask = SAM9G20_PLL_B_DIV_MASK; 321 clk->set_outb = at91_pll_outb; 322 at91_pmc_clock_deref(clk); 323 return (0); 324} 325 326static device_method_t at91_methods[] = { 327 DEVMETHOD(device_probe, at91_probe), 328 DEVMETHOD(device_attach, at91_attach), 329 DEVMETHOD(device_identify, at91_identify), 330 {0, 0}, 331}; 332 333static driver_t at91sam9_driver = { 334 "at91sam", 335 at91_methods, 336 sizeof(struct at91sam9_softc), 337}; 338 339static devclass_t at91sam9_devclass; 340 341DRIVER_MODULE(at91sam, atmelarm, at91sam9_driver, at91sam9_devclass, 0, 0); 342