at91sam9x5.c revision 238331
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 238331 2012-07-10 02:39:03Z 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/at91_aicreg.h> 43#include <arm/at91/at91sam9x25reg.h> 44#include <arm/at91/at91_pmcreg.h> 45#include <arm/at91/at91_pmcvar.h> 46 47struct at91sam9x25_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 (FIQ) */ 64 7, /* System Peripherals */ 65 1, /* Parallel IO Controller A and B */ 66 1, /* Parallel IO Controller C and D */ 67 4, /* Soft Modem */ 68 5, /* USART 0 */ 69 5, /* USART 1 */ 70 5, /* USART 2 */ 71 5, /* USART 3 */ 72 6, /* Two-Wire Interface 0 */ 73 6, /* Two-Wire Interface 1 */ 74 6, /* Two-Wire Interface 2 */ 75 0, /* Multimedia Card Interface 0 */ 76 5, /* Serial Peripheral Interface 0 */ 77 5, /* Serial Peripheral Interface 1 */ 78 5, /* UART 0 */ 79 5, /* UART 1 */ 80 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */ 81 0, /* Pulse Width Modulation Controller */ 82 0, /* ADC Controller */ 83 0, /* DMA Controller 0 */ 84 0, /* DMA Controller 1 */ 85 2, /* USB Host High Speed port */ 86 2, /* USB Device High speed port */ 87 3, /* Ethernet MAC 0 */ 88 3, /* LDC Controller or Image Sensor Interface */ 89 0, /* Multimedia Card Interface 1 */ 90 3, /* Ethernet MAC 1 */ 91 4, /* Synchronous Serial Interface */ 92 4, /* CAN Controller 0 */ 93 4, /* CAN Controller 1 */ 94 0, /* Advanced Interrupt Controller (IRQ0) */ 95}; 96 97#define DEVICE(_name, _id, _unit) \ 98 { \ 99 _name, _unit, \ 100 AT91SAM9X25_ ## _id ##_BASE, \ 101 AT91SAM9X25_ ## _id ## _SIZE, \ 102 AT91SAM9X25_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_pio", PIOD, 3), 115 DEVICE("at91_twi", TWI0, 0), 116 DEVICE("at91_twi", TWI1, 1), 117 DEVICE("at91_twi", TWI2, 2), 118 DEVICE("at91_mci", HSMCI0, 0), 119 DEVICE("at91_mci", HSMCI1, 1), 120 DEVICE("uart", DBGU, 0), 121 DEVICE("uart", USART0, 1), 122 DEVICE("uart", USART1, 2), 123 DEVICE("uart", USART2, 3), 124 DEVICE("uart", USART3, 4), 125 DEVICE("spi", SPI0, 0), 126 DEVICE("spi", SPI1, 1), 127 DEVICE("macb", EMAC0, 0), 128 DEVICE("macb", EMAC1, 0), 129 DEVICE("nand", NAND, 0), 130 DEVICE("ohci", OHCI, 0), 131 DEVICE("ehci", EHCI, 0), 132 { 0, 0, 0, 0, 0 } 133}; 134 135static void 136at91_add_child(device_t dev, int prio, const char *name, int unit, 137 bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) 138{ 139 device_t kid; 140 struct at91_ivar *ivar; 141 142 kid = device_add_child_ordered(dev, prio, name, unit); 143 if (kid == NULL) { 144 printf("Can't add child %s%d ordered\n", name, unit); 145 return; 146 } 147 ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 148 if (ivar == NULL) { 149 device_delete_child(dev, kid); 150 printf("Can't add alloc ivar\n"); 151 return; 152 } 153 device_set_ivars(kid, ivar); 154 resource_list_init(&ivar->resources); 155 if (irq0 != -1) { 156 bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); 157 if (irq0 != AT91_IRQ_SYSTEM) 158 at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); 159 } 160 if (irq1 != 0) 161 bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); 162 if (irq2 != 0) 163 bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); 164 if (addr != 0 && addr < AT91_BASE) 165 addr += AT91_BASE; 166 if (addr != 0) 167 bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); 168} 169 170static void 171at91_cpu_add_builtin_children(device_t dev) 172{ 173 int i; 174 const struct cpu_devs *walker; 175 176 for (i = 1, walker = at91_devs; walker->name; i++, walker++) { 177 at91_add_child(dev, i, walker->name, walker->unit, 178 walker->mem_base, walker->mem_len, walker->irq0, 179 walker->irq1, walker->irq2); 180 } 181} 182 183static uint32_t 184at91_pll_outa(int freq) 185{ 186 187 switch (freq / 10000000) { 188 case 747 ... 801: return ((1 << 29) | (0 << 14)); 189 case 697 ... 746: return ((1 << 29) | (1 << 14)); 190 case 647 ... 696: return ((1 << 29) | (2 << 14)); 191 case 597 ... 646: return ((1 << 29) | (3 << 14)); 192 case 547 ... 596: return ((1 << 29) | (1 << 14)); 193 case 497 ... 546: return ((1 << 29) | (2 << 14)); 194 case 447 ... 496: return ((1 << 29) | (3 << 14)); 195 case 397 ... 446: return ((1 << 29) | (4 << 14)); 196 default: return (1 << 29); 197 } 198} 199 200static uint32_t 201at91_pll_outb(int freq) 202{ 203 204 return (0); 205} 206 207static void 208at91_identify(driver_t *drv, device_t parent) 209{ 210 211 if (soc_data.type == AT91_T_SAM9X5 && soc_data.subtype == AT91_ST_SAM9X25) { 212 at91_add_child(parent, 0, "at91sam9x25", 0, 0, 0, -1, 0, 0); 213 at91_cpu_add_builtin_children(parent); 214 } 215} 216 217static int 218at91_probe(device_t dev) 219{ 220 221 device_set_desc(dev, "AT91SAM9X25"); 222 return (0); 223} 224 225static int 226at91_attach(device_t dev) 227{ 228 struct at91_pmc_clock *clk; 229 struct at91sam9x25_softc *sc = device_get_softc(dev); 230 int i; 231 232 struct at91_softc *at91sc = device_get_softc(device_get_parent(dev)); 233 234 sc->sc_st = at91sc->sc_st; 235 sc->sc_sh = at91sc->sc_sh; 236 sc->dev = dev; 237 238 /* 239 * XXX These values work for the RM9200, SAM926[01], and SAM9X25 240 * will have to fix this when we want to support anything else. XXX 241 */ 242 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_SYS_BASE, 243 AT91SAM9X25_SYS_SIZE, &sc->sc_sys_sh) != 0) 244 panic("Enable to map system registers"); 245 246 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_DBGU_BASE, 247 AT91SAM9X25_DBGU_SIZE, &sc->sc_dbg_sh) != 0) 248 panic("Enable to map DBGU registers"); 249 250 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_AIC_BASE, 251 AT91SAM9X25_AIC_SIZE, &sc->sc_aic_sh) != 0) 252 panic("Enable to map system registers"); 253 254 /* XXX Hack to tell atmelarm about the AIC */ 255 at91sc->sc_aic_sh = sc->sc_aic_sh; 256 at91sc->sc_irq_system = AT91_IRQ_SYSTEM; 257 258 for (i = 0; i < 32; i++) { 259 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR + 260 i * 4, i); 261 /* Priority. */ 262 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4, 263 at91_irq_prio[i]); 264 if (i < 8) 265 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR, 266 1); 267 } 268 269 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32); 270 /* No debug. */ 271 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0); 272 /* Disable and clear all interrupts. */ 273 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff); 274 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff); 275 276 /* Disable all interrupts for DBGU */ 277 bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff); 278 279 if (bus_space_subregion(sc->sc_st, sc->sc_sh, 280 AT91SAM9X25_MATRIX_BASE, AT91SAM9X25_MATRIX_SIZE, 281 &sc->sc_matrix_sh) != 0) 282 panic("Enable to map matrix registers"); 283 284#if 0 /* wrong, placeholder */ 285 /* activate NAND*/ 286 i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh, 287 AT91SAM9X25_EBICSA); 288 bus_space_write_4(sc->sc_st, sc->sc_matrix_sh, 289 AT91SAM9X25_EBICSA, 290 i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); 291#endif 292 293 /* Update USB device port clock info */ 294 clk = at91_pmc_clock_ref("udpck"); 295 clk->pmc_mask = PMC_SCER_UDP_SAM9; 296 at91_pmc_clock_deref(clk); 297 298 /* Update USB host port clock info */ 299 clk = at91_pmc_clock_ref("uhpck"); 300 clk->pmc_mask = PMC_SCER_UHP_SAM9; 301 at91_pmc_clock_deref(clk); 302 303 /* Each SOC has different PLL contraints */ 304 clk = at91_pmc_clock_ref("plla"); 305 clk->pll_min_in = SAM9X25_PLL_A_MIN_IN_FREQ; /* 2 MHz */ 306 clk->pll_max_in = SAM9X25_PLL_A_MAX_IN_FREQ; /* 32 MHz */ 307 clk->pll_min_out = SAM9X25_PLL_A_MIN_OUT_FREQ; /* 400 MHz */ 308 clk->pll_max_out = SAM9X25_PLL_A_MAX_OUT_FREQ; /* 800 MHz */ 309 clk->pll_mul_shift = SAM9X25_PLL_A_MUL_SHIFT; 310 clk->pll_mul_mask = SAM9X25_PLL_A_MUL_MASK; 311 clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT; 312 clk->pll_div_mask = SAM9X25_PLL_A_DIV_MASK; 313 clk->set_outb = at91_pll_outa; 314 at91_pmc_clock_deref(clk); 315 316 clk = at91_pmc_clock_ref("pllb"); 317 clk->pll_min_in = SAM9X25_PLL_B_MIN_IN_FREQ; /* 2 MHz */ 318 clk->pll_max_in = SAM9X25_PLL_B_MAX_IN_FREQ; /* 32 MHz */ 319 clk->pll_min_out = SAM9X25_PLL_B_MIN_OUT_FREQ; /* 30 MHz */ 320 clk->pll_max_out = SAM9X25_PLL_B_MAX_OUT_FREQ; /* 100 MHz */ 321 clk->pll_mul_shift = SAM9X25_PLL_B_MUL_SHIFT; 322 clk->pll_mul_mask = SAM9X25_PLL_B_MUL_MASK; 323 clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT; 324 clk->pll_div_mask = SAM9X25_PLL_B_DIV_MASK; 325 clk->set_outb = at91_pll_outb; 326 at91_pmc_clock_deref(clk); 327 return (0); 328} 329 330static device_method_t at91sam9x25_methods[] = { 331 DEVMETHOD(device_probe, at91_probe), 332 DEVMETHOD(device_attach, at91_attach), 333 DEVMETHOD(device_identify, at91_identify), 334 {0, 0}, 335}; 336 337static driver_t at91sam9x25_driver = { 338 "at91sam9x25", 339 at91sam9x25_methods, 340 sizeof(struct at91sam9x25_softc), 341}; 342 343static devclass_t at91sam9x25_devclass; 344 345DRIVER_MODULE(at91sam9x25, atmelarm, at91sam9x25_driver, at91sam9x25_devclass, 0, 0); 346