at91sam9x5.c revision 237742
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 237742 2012-06-29 04:18:52Z 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/at91_aicreg.h> 42#include <arm/at91/at91sam9x25reg.h> 43#include <arm/at91/at91_pmcreg.h> 44#include <arm/at91/at91_pmcvar.h> 45 46struct at91sam9x25_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 AT91SAM9X25_ ## _id ##_BASE, \ 100 AT91SAM9X25_ ## _id ## _SIZE, \ 101 AT91SAM9X25_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", TWI0, 0), 114 DEVICE("at91_twi", TWI1, 1), 115 DEVICE("at91_twi", TWI2, 2), 116 DEVICE("at91_mci", HSMCI0, 0), 117 DEVICE("at91_mci", HSMCI1, 1), 118 DEVICE("uart", DBGU, 0), 119 DEVICE("uart", USART0, 1), 120 DEVICE("uart", USART1, 2), 121 DEVICE("uart", USART2, 3), 122 DEVICE("uart", USART3, 4), 123 DEVICE("spi", SPI0, 0), 124 DEVICE("spi", SPI1, 1), 125 DEVICE("macb", EMAC0, 0), 126 DEVICE("macb", EMAC1, 0), 127 DEVICE("nand", NAND, 0), 128 DEVICE("ohci", OHCI, 0), 129 DEVICE("ehci", EHCI, 0), 130 { 0, 0, 0, 0, 0 } 131}; 132 133static void 134at91_add_child(device_t dev, int prio, const char *name, int unit, 135 bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) 136{ 137 device_t kid; 138 struct at91_ivar *ivar; 139 140 kid = device_add_child_ordered(dev, prio, name, unit); 141 if (kid == NULL) { 142 printf("Can't add child %s%d ordered\n", name, unit); 143 return; 144 } 145 ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 146 if (ivar == NULL) { 147 device_delete_child(dev, kid); 148 printf("Can't add alloc ivar\n"); 149 return; 150 } 151 device_set_ivars(kid, ivar); 152 resource_list_init(&ivar->resources); 153 if (irq0 != -1) { 154 bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); 155 if (irq0 != AT91SAM9X25_IRQ_SYSTEM) 156 at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); 157 } 158 if (irq1 != 0) 159 bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); 160 if (irq2 != 0) 161 bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); 162 if (addr != 0 && addr < AT91SAM9X25_BASE) 163 addr += AT91SAM9X25_BASE; 164 if (addr != 0) 165 bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); 166} 167 168static void 169at91_cpu_add_builtin_children(device_t dev) 170{ 171 int i; 172 const struct cpu_devs *walker; 173 174 for (i = 1, walker = at91_devs; walker->name; i++, walker++) { 175 at91_add_child(dev, i, walker->name, walker->unit, 176 walker->mem_base, walker->mem_len, walker->irq0, 177 walker->irq1, walker->irq2); 178 } 179} 180 181static uint32_t 182at91_pll_outa(int freq) 183{ 184 185 switch (freq / 10000000) { 186 case 747 ... 801: return ((1 << 29) | (0 << 14)); 187 case 697 ... 746: return ((1 << 29) | (1 << 14)); 188 case 647 ... 696: return ((1 << 29) | (2 << 14)); 189 case 597 ... 646: return ((1 << 29) | (3 << 14)); 190 case 547 ... 596: return ((1 << 29) | (1 << 14)); 191 case 497 ... 546: return ((1 << 29) | (2 << 14)); 192 case 447 ... 496: return ((1 << 29) | (3 << 14)); 193 case 397 ... 446: return ((1 << 29) | (4 << 14)); 194 default: return (1 << 29); 195 } 196} 197 198static uint32_t 199at91_pll_outb(int freq) 200{ 201 202 return (0); 203} 204 205static void 206at91_identify(driver_t *drv, device_t parent) 207{ 208 209 if (soc_data.type == AT91_T_SAM9X5 && soc_data.subtype == AT91_ST_SAM9X25) { 210 at91_add_child(parent, 0, "at91sam9x25", 0, 0, 0, -1, 0, 0); 211 at91_cpu_add_builtin_children(parent); 212 } 213} 214 215static int 216at91_probe(device_t dev) 217{ 218 219 device_set_desc(dev, "AT91SAM9X25"); 220 return (0); 221} 222 223static int 224at91_attach(device_t dev) 225{ 226 struct at91_pmc_clock *clk; 227 struct at91sam9x25_softc *sc = device_get_softc(dev); 228 int i; 229 230 struct at91_softc *at91sc = device_get_softc(device_get_parent(dev)); 231 232 sc->sc_st = at91sc->sc_st; 233 sc->sc_sh = at91sc->sc_sh; 234 sc->dev = dev; 235 236 /* 237 * XXX These values work for the RM9200, SAM926[01], and SAM9X25 238 * will have to fix this when we want to support anything else. XXX 239 */ 240 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_SYS_BASE, 241 AT91SAM9X25_SYS_SIZE, &sc->sc_sys_sh) != 0) 242 panic("Enable to map system registers"); 243 244 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_DBGU_BASE, 245 AT91SAM9X25_DBGU_SIZE, &sc->sc_dbg_sh) != 0) 246 panic("Enable to map DBGU registers"); 247 248 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9X25_AIC_BASE, 249 AT91SAM9X25_AIC_SIZE, &sc->sc_aic_sh) != 0) 250 panic("Enable to map system registers"); 251 252 /* XXX Hack to tell atmelarm about the AIC */ 253 at91sc->sc_aic_sh = sc->sc_aic_sh; 254 at91sc->sc_irq_system = AT91SAM9X25_IRQ_SYSTEM; 255 256 for (i = 0; i < 32; i++) { 257 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR + 258 i * 4, i); 259 /* Priority. */ 260 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4, 261 at91_irq_prio[i]); 262 if (i < 8) 263 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR, 264 1); 265 } 266 267 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32); 268 /* No debug. */ 269 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0); 270 /* Disable and clear all interrupts. */ 271 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff); 272 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff); 273 274 /* Disable all interrupts for DBGU */ 275 bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff); 276 277 if (bus_space_subregion(sc->sc_st, sc->sc_sh, 278 AT91SAM9X25_MATRIX_BASE, AT91SAM9X25_MATRIX_SIZE, 279 &sc->sc_matrix_sh) != 0) 280 panic("Enable to map matrix registers"); 281 282#if 0 /* wrong, placeholder */ 283 /* activate NAND*/ 284 i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh, 285 AT91SAM9X25_EBICSA); 286 bus_space_write_4(sc->sc_st, sc->sc_matrix_sh, 287 AT91SAM9X25_EBICSA, 288 i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); 289#endif 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 = SAM9X25_PLL_A_MIN_IN_FREQ; /* 2 MHz */ 304 clk->pll_max_in = SAM9X25_PLL_A_MAX_IN_FREQ; /* 32 MHz */ 305 clk->pll_min_out = SAM9X25_PLL_A_MIN_OUT_FREQ; /* 400 MHz */ 306 clk->pll_max_out = SAM9X25_PLL_A_MAX_OUT_FREQ; /* 800 MHz */ 307 clk->pll_mul_shift = SAM9X25_PLL_A_MUL_SHIFT; 308 clk->pll_mul_mask = SAM9X25_PLL_A_MUL_MASK; 309 clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT; 310 clk->pll_div_mask = SAM9X25_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 = SAM9X25_PLL_B_MIN_IN_FREQ; /* 2 MHz */ 316 clk->pll_max_in = SAM9X25_PLL_B_MAX_IN_FREQ; /* 32 MHz */ 317 clk->pll_min_out = SAM9X25_PLL_B_MIN_OUT_FREQ; /* 30 MHz */ 318 clk->pll_max_out = SAM9X25_PLL_B_MAX_OUT_FREQ; /* 100 MHz */ 319 clk->pll_mul_shift = SAM9X25_PLL_B_MUL_SHIFT; 320 clk->pll_mul_mask = SAM9X25_PLL_B_MUL_MASK; 321 clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT; 322 clk->pll_div_mask = SAM9X25_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 at91sam9x25_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 at91sam9x25_driver = { 336 "at91sam9x25", 337 at91sam9x25_methods, 338 sizeof(struct at91sam9x25_softc), 339}; 340 341static devclass_t at91sam9x25_devclass; 342 343DRIVER_MODULE(at91sam9x25, atmelarm, at91sam9x25_driver, at91sam9x25_devclass, 0, 0); 344