at91sam9x5.c revision 237744
172172Sphantom/*- 272172Sphantom * Copyright (c) 2005 Olivier Houchard. All rights reserved. 372172Sphantom * Copyright (c) 2010 Greg Ansley. All rights reserved. 472172Sphantom * Copyright (c) 2012 M. Warner Losh.. All rights reserved. 572172Sphantom * 672172Sphantom * Redistribution and use in source and binary forms, with or without 772172Sphantom * modification, are permitted provided that the following conditions 872172Sphantom * are met: 972172Sphantom * 1. Redistributions of source code must retain the above copyright 1072277Sache * notice, this list of conditions and the following disclaimer. 1172329Sache * 2. Redistributions in binary form must reproduce the above copyright 1272172Sphantom * 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 237744 2012-06-29 06:05:44Z 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 (FIQ) */ 63 7, /* System Peripherals */ 64 1, /* Parallel IO Controller A and B */ 65 1, /* Parallel IO Controller C and D */ 66 4, /* Soft Modem */ 67 5, /* USART 0 */ 68 5, /* USART 1 */ 69 5, /* USART 2 */ 70 5, /* USART 3 */ 71 6, /* Two-Wire Interface 0 */ 72 6, /* Two-Wire Interface 1 */ 73 6, /* Two-Wire Interface 2 */ 74 0, /* Multimedia Card Interface 0 */ 75 5, /* Serial Peripheral Interface 0 */ 76 5, /* Serial Peripheral Interface 1 */ 77 5, /* UART 0 */ 78 5, /* UART 1 */ 79 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */ 80 0, /* Pulse Width Modulation Controller */ 81 0, /* ADC Controller */ 82 0, /* DMA Controller 0 */ 83 0, /* DMA Controller 1 */ 84 2, /* USB Host High Speed port */ 85 2, /* USB Device High speed port */ 86 3, /* Ethernet MAC 0 */ 87 3, /* LDC Controller or Image Sensor Interface */ 88 0, /* Multimedia Card Interface 1 */ 89 3, /* Ethernet MAC 1 */ 90 4, /* Synchronous Serial Interface */ 91 4, /* CAN Controller 0 */ 92 4, /* CAN Controller 1 */ 93 0, /* Advanced Interrupt Controller (IRQ0) */ 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_pio", PIOD, 3), 114 DEVICE("at91_twi", TWI0, 0), 115 DEVICE("at91_twi", TWI1, 1), 116 DEVICE("at91_twi", TWI2, 2), 117 DEVICE("at91_mci", HSMCI0, 0), 118 DEVICE("at91_mci", HSMCI1, 1), 119 DEVICE("uart", DBGU, 0), 120 DEVICE("uart", USART0, 1), 121 DEVICE("uart", USART1, 2), 122 DEVICE("uart", USART2, 3), 123 DEVICE("uart", USART3, 4), 124 DEVICE("spi", SPI0, 0), 125 DEVICE("spi", SPI1, 1), 126 DEVICE("macb", EMAC0, 0), 127 DEVICE("macb", EMAC1, 0), 128 DEVICE("nand", NAND, 0), 129 DEVICE("ohci", OHCI, 0), 130 DEVICE("ehci", EHCI, 0), 131 { 0, 0, 0, 0, 0 } 132}; 133 134static void 135at91_add_child(device_t dev, int prio, const char *name, int unit, 136 bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) 137{ 138 device_t kid; 139 struct at91_ivar *ivar; 140 141 kid = device_add_child_ordered(dev, prio, name, unit); 142 if (kid == NULL) { 143 printf("Can't add child %s%d ordered\n", name, unit); 144 return; 145 } 146 ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 147 if (ivar == NULL) { 148 device_delete_child(dev, kid); 149 printf("Can't add alloc ivar\n"); 150 return; 151 } 152 device_set_ivars(kid, ivar); 153 resource_list_init(&ivar->resources); 154 if (irq0 != -1) { 155 bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); 156 if (irq0 != AT91SAM9X25_IRQ_SYSTEM) 157 at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); 158 } 159 if (irq1 != 0) 160 bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); 161 if (irq2 != 0) 162 bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); 163 if (addr != 0 && addr < AT91SAM9X25_BASE) 164 addr += AT91SAM9X25_BASE; 165 if (addr != 0) 166 bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); 167} 168 169static void 170at91_cpu_add_builtin_children(device_t dev) 171{ 172 int i; 173 const struct cpu_devs *walker; 174 175 for (i = 1, walker = at91_devs; walker->name; i++, walker++) { 176 at91_add_child(dev, i, walker->name, walker->unit, 177 walker->mem_base, walker->mem_len, walker->irq0, 178 walker->irq1, walker->irq2); 179 } 180} 181 182static uint32_t 183at91_pll_outa(int freq) 184{ 185 186 switch (freq / 10000000) { 187 case 747 ... 801: return ((1 << 29) | (0 << 14)); 188 case 697 ... 746: return ((1 << 29) | (1 << 14)); 189 case 647 ... 696: return ((1 << 29) | (2 << 14)); 190 case 597 ... 646: return ((1 << 29) | (3 << 14)); 191 case 547 ... 596: return ((1 << 29) | (1 << 14)); 192 case 497 ... 546: return ((1 << 29) | (2 << 14)); 193 case 447 ... 496: return ((1 << 29) | (3 << 14)); 194 case 397 ... 446: return ((1 << 29) | (4 << 14)); 195 default: return (1 << 29); 196 } 197} 198 199static uint32_t 200at91_pll_outb(int freq) 201{ 202 203 return (0); 204} 205 206static void 207at91_identify(driver_t *drv, device_t parent) 208{ 209 210 if (soc_data.type == AT91_T_SAM9X5 && soc_data.subtype == AT91_ST_SAM9X25) { 211 at91_add_child(parent, 0, "at91sam9x25", 0, 0, 0, -1, 0, 0); 212 at91_cpu_add_builtin_children(parent); 213 } 214} 215 216static int 217at91_probe(device_t dev) 218{ 219 220 device_set_desc(dev, "AT91SAM9X25"); 221 return (0); 222} 223 224static int 225at91_attach(device_t dev) 226{ 227 struct at91_pmc_clock *clk; 228 struct at91sam9x25_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 SAM9X25 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, AT91SAM9X25_SYS_BASE, 242 AT91SAM9X25_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, AT91SAM9X25_DBGU_BASE, 246 AT91SAM9X25_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, AT91SAM9X25_AIC_BASE, 250 AT91SAM9X25_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 = AT91SAM9X25_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 AT91SAM9X25_MATRIX_BASE, AT91SAM9X25_MATRIX_SIZE, 280 &sc->sc_matrix_sh) != 0) 281 panic("Enable to map matrix registers"); 282 283#if 0 /* wrong, placeholder */ 284 /* activate NAND*/ 285 i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh, 286 AT91SAM9X25_EBICSA); 287 bus_space_write_4(sc->sc_st, sc->sc_matrix_sh, 288 AT91SAM9X25_EBICSA, 289 i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); 290#endif 291 292 /* Update USB device port clock info */ 293 clk = at91_pmc_clock_ref("udpck"); 294 clk->pmc_mask = PMC_SCER_UDP_SAM9; 295 at91_pmc_clock_deref(clk); 296 297 /* Update USB host port clock info */ 298 clk = at91_pmc_clock_ref("uhpck"); 299 clk->pmc_mask = PMC_SCER_UHP_SAM9; 300 at91_pmc_clock_deref(clk); 301 302 /* Each SOC has different PLL contraints */ 303 clk = at91_pmc_clock_ref("plla"); 304 clk->pll_min_in = SAM9X25_PLL_A_MIN_IN_FREQ; /* 2 MHz */ 305 clk->pll_max_in = SAM9X25_PLL_A_MAX_IN_FREQ; /* 32 MHz */ 306 clk->pll_min_out = SAM9X25_PLL_A_MIN_OUT_FREQ; /* 400 MHz */ 307 clk->pll_max_out = SAM9X25_PLL_A_MAX_OUT_FREQ; /* 800 MHz */ 308 clk->pll_mul_shift = SAM9X25_PLL_A_MUL_SHIFT; 309 clk->pll_mul_mask = SAM9X25_PLL_A_MUL_MASK; 310 clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT; 311 clk->pll_div_mask = SAM9X25_PLL_A_DIV_MASK; 312 clk->set_outb = at91_pll_outa; 313 at91_pmc_clock_deref(clk); 314 315 clk = at91_pmc_clock_ref("pllb"); 316 clk->pll_min_in = SAM9X25_PLL_B_MIN_IN_FREQ; /* 2 MHz */ 317 clk->pll_max_in = SAM9X25_PLL_B_MAX_IN_FREQ; /* 32 MHz */ 318 clk->pll_min_out = SAM9X25_PLL_B_MIN_OUT_FREQ; /* 30 MHz */ 319 clk->pll_max_out = SAM9X25_PLL_B_MAX_OUT_FREQ; /* 100 MHz */ 320 clk->pll_mul_shift = SAM9X25_PLL_B_MUL_SHIFT; 321 clk->pll_mul_mask = SAM9X25_PLL_B_MUL_MASK; 322 clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT; 323 clk->pll_div_mask = SAM9X25_PLL_B_DIV_MASK; 324 clk->set_outb = at91_pll_outb; 325 at91_pmc_clock_deref(clk); 326 return (0); 327} 328 329static device_method_t at91sam9x25_methods[] = { 330 DEVMETHOD(device_probe, at91_probe), 331 DEVMETHOD(device_attach, at91_attach), 332 DEVMETHOD(device_identify, at91_identify), 333 {0, 0}, 334}; 335 336static driver_t at91sam9x25_driver = { 337 "at91sam9x25", 338 at91sam9x25_methods, 339 sizeof(struct at91sam9x25_softc), 340}; 341 342static devclass_t at91sam9x25_devclass; 343 344DRIVER_MODULE(at91sam9x25, atmelarm, at91sam9x25_driver, at91sam9x25_devclass, 0, 0); 345