[687e34b] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @ingroup lpc24xx |
---|
| 5 | * |
---|
| 6 | * @brief Startup code. |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | /* |
---|
| 10 | * Copyright (c) 2008, 2009 |
---|
| 11 | * embedded brains GmbH |
---|
| 12 | * Obere Lagerstr. 30 |
---|
| 13 | * D-82178 Puchheim |
---|
| 14 | * Germany |
---|
| 15 | * <rtems@embedded-brains.de> |
---|
| 16 | * |
---|
| 17 | * The license and distribution terms for this file may be |
---|
| 18 | * found in the file LICENSE in this distribution or at |
---|
| 19 | * http://www.rtems.com/license/LICENSE. |
---|
| 20 | */ |
---|
| 21 | |
---|
| 22 | #include <stdbool.h> |
---|
| 23 | |
---|
| 24 | #include <bspopts.h> |
---|
| 25 | #include <bsp/start.h> |
---|
| 26 | #include <bsp/lpc24xx.h> |
---|
| 27 | #include <bsp/linker-symbols.h> |
---|
| 28 | |
---|
[22f107b6] | 29 | #if defined(LPC24XX_EMC_MICRON) || defined(LPC24XX_EMC_NUMONYX) |
---|
| 30 | #define LPC24XX_EMC_INIT |
---|
| 31 | #endif |
---|
| 32 | |
---|
[687e34b] | 33 | #ifdef LPC24XX_EMC_MICRON |
---|
[c468f18b] | 34 | static void BSP_START_SECTION lpc24xx_ram_test_32(void) |
---|
[687e34b] | 35 | { |
---|
| 36 | #ifdef LPC24XX_EMC_TEST |
---|
| 37 | int *begin = (int *) 0xa0000000; |
---|
| 38 | const int *end = (const int *) 0xa0800000; |
---|
| 39 | int *out = begin; |
---|
| 40 | |
---|
| 41 | while (out != end) { |
---|
| 42 | *out = (int) out; |
---|
| 43 | ++out; |
---|
| 44 | } |
---|
| 45 | |
---|
| 46 | out = begin; |
---|
| 47 | while (out != end) { |
---|
| 48 | if (*out != (int) out) { |
---|
| 49 | while (true) { |
---|
| 50 | /* Do nothing */ |
---|
| 51 | } |
---|
| 52 | } |
---|
| 53 | ++out; |
---|
| 54 | } |
---|
| 55 | #endif |
---|
| 56 | } |
---|
| 57 | |
---|
[c468f18b] | 58 | static void BSP_START_SECTION lpc24xx_cpu_delay( |
---|
[687e34b] | 59 | unsigned ticks |
---|
| 60 | ) |
---|
| 61 | { |
---|
| 62 | unsigned i = 0; |
---|
| 63 | |
---|
| 64 | /* One loop execution needs four instructions */ |
---|
| 65 | ticks /= 4; |
---|
| 66 | |
---|
| 67 | for (i = 0; i <= ticks; ++i) { |
---|
| 68 | asm volatile ("nop"); |
---|
| 69 | } |
---|
| 70 | } |
---|
| 71 | #endif |
---|
| 72 | |
---|
| 73 | /** |
---|
| 74 | * @brief EMC initialization hook 0. |
---|
| 75 | */ |
---|
[c468f18b] | 76 | static void BSP_START_SECTION lpc24xx_init_emc_0(void) |
---|
[687e34b] | 77 | { |
---|
| 78 | #ifdef LPC24XX_EMC_NUMONYX |
---|
| 79 | /* |
---|
| 80 | * Static Memory 1: Numonyx M29W160EB |
---|
| 81 | * |
---|
| 82 | * 1 clock cycle = 1/72MHz = 13.9ns |
---|
| 83 | * |
---|
| 84 | * We cannot use an initializer since this will result in the usage of the |
---|
| 85 | * read-only data section which is not available here. |
---|
| 86 | */ |
---|
| 87 | lpc24xx_emc_static numonyx; |
---|
| 88 | |
---|
| 89 | /* |
---|
| 90 | * 16 bit, page mode disabled, active LOW chip select, extended wait |
---|
| 91 | * disabled, writes not protected, byte lane state LOW/LOW (!). |
---|
| 92 | */ |
---|
| 93 | numonyx.cfg = 0x81; |
---|
| 94 | |
---|
| 95 | /* 1 clock cycles delay from the chip select 1 to the write enable */ |
---|
| 96 | numonyx.waitwen = 0; |
---|
| 97 | |
---|
| 98 | /* |
---|
| 99 | * 0 clock cycles delay from the chip select 1 or address change |
---|
| 100 | * (whichever is later) to the output enable |
---|
| 101 | */ |
---|
| 102 | numonyx.waitoen = 0; |
---|
| 103 | |
---|
| 104 | /* 7 clock cycles delay from the chip select 1 to the read access */ |
---|
| 105 | numonyx.waitrd = 0x6; |
---|
| 106 | |
---|
| 107 | /* |
---|
| 108 | * 32 clock cycles delay for asynchronous page mode sequential accesses |
---|
| 109 | */ |
---|
| 110 | numonyx.waitpage = 0x1f; |
---|
| 111 | |
---|
| 112 | /* 5 clock cycles delay from the chip select 1 to the write access */ |
---|
| 113 | numonyx.waitwr = 0x3; |
---|
| 114 | |
---|
| 115 | /* 16 bus turnaround cycles */ |
---|
| 116 | numonyx.waitrun = 0xf; |
---|
| 117 | #endif |
---|
| 118 | |
---|
[22f107b6] | 119 | #ifdef LPC24XX_EMC_INIT |
---|
| 120 | /* Set pin functions for EMC */ |
---|
| 121 | PINSEL5 = (PINSEL5 & 0xf000f000) | 0x05550555; |
---|
| 122 | PINSEL6 = 0x55555555; |
---|
| 123 | PINSEL8 = 0x55555555; |
---|
| 124 | PINSEL9 = (PINSEL9 & 0x0f000000) | 0x50555555; |
---|
| 125 | #endif |
---|
[687e34b] | 126 | |
---|
| 127 | #ifdef LPC24XX_EMC_NUMONYX |
---|
| 128 | /* Static Memory 1 settings */ |
---|
[22f107b6] | 129 | bsp_start_memcpy( |
---|
[687e34b] | 130 | (int *) EMC_STA_BASE_1, |
---|
| 131 | (const int *) &numonyx, |
---|
| 132 | sizeof(numonyx) |
---|
| 133 | ); |
---|
| 134 | #endif |
---|
| 135 | } |
---|
| 136 | |
---|
| 137 | /** |
---|
| 138 | * @brief EMC initialization hook 1. |
---|
| 139 | */ |
---|
[c468f18b] | 140 | static void BSP_START_SECTION lpc24xx_init_emc_1(void) |
---|
[687e34b] | 141 | { |
---|
[22f107b6] | 142 | #ifdef LPC24XX_EMC_INIT |
---|
| 143 | /* Use normal memory map */ |
---|
[c3dd440] | 144 | EMC_CTRL &= ~0x2U; |
---|
[22f107b6] | 145 | #endif |
---|
[687e34b] | 146 | |
---|
| 147 | #ifdef LPC24XX_EMC_MICRON |
---|
| 148 | /* Check if we need to initialize it */ |
---|
[edf846e4] | 149 | if ((EMC_DYN_CFG0 & 0x00080000) == 0) { |
---|
[687e34b] | 150 | /* |
---|
| 151 | * The buffer enable bit is not set. Now we assume that the controller |
---|
| 152 | * is not properly initialized. |
---|
| 153 | */ |
---|
| 154 | |
---|
| 155 | /* Global dynamic settings */ |
---|
[32b8506] | 156 | |
---|
[687e34b] | 157 | /* FIXME */ |
---|
| 158 | EMC_DYN_APR = 2; |
---|
[32b8506] | 159 | |
---|
[687e34b] | 160 | /* Data-in to active command period tWR + tRP */ |
---|
| 161 | EMC_DYN_DAL = 4; |
---|
[32b8506] | 162 | |
---|
[687e34b] | 163 | /* Load mode register to active or refresh command period 2 tCK */ |
---|
| 164 | EMC_DYN_MRD = 1; |
---|
[32b8506] | 165 | |
---|
[687e34b] | 166 | /* Active to precharge command period 44 ns */ |
---|
| 167 | EMC_DYN_RAS = 3; |
---|
[32b8506] | 168 | |
---|
[687e34b] | 169 | /* Active to active command period 66 ns */ |
---|
| 170 | EMC_DYN_RC = 4; |
---|
[32b8506] | 171 | |
---|
[687e34b] | 172 | /* Use command delayed strategy */ |
---|
| 173 | EMC_DYN_RD_CFG = 1; |
---|
[32b8506] | 174 | |
---|
[687e34b] | 175 | /* Auto refresh period 66 ns */ |
---|
| 176 | EMC_DYN_RFC = 4; |
---|
[32b8506] | 177 | |
---|
[687e34b] | 178 | /* Precharge command period 20 ns */ |
---|
| 179 | EMC_DYN_RP = 1; |
---|
[32b8506] | 180 | |
---|
[687e34b] | 181 | /* Active bank a to active bank b command period 15 ns */ |
---|
| 182 | EMC_DYN_RRD = 1; |
---|
[32b8506] | 183 | |
---|
[687e34b] | 184 | /* FIXME */ |
---|
| 185 | EMC_DYN_SREX = 5; |
---|
[32b8506] | 186 | |
---|
[687e34b] | 187 | /* Write recovery time 15 ns */ |
---|
| 188 | EMC_DYN_WR = 1; |
---|
[32b8506] | 189 | |
---|
[687e34b] | 190 | /* Exit self refresh to active command period 75 ns */ |
---|
| 191 | EMC_DYN_XSR = 5; |
---|
[32b8506] | 192 | |
---|
[687e34b] | 193 | /* Dynamic Memory 0: Micron M T48LC 4M16 A2 P 75 IT */ |
---|
[32b8506] | 194 | |
---|
[687e34b] | 195 | /* |
---|
| 196 | * Use SDRAM, 0 0 001 01 address mapping, disabled buffer, unprotected writes |
---|
| 197 | */ |
---|
| 198 | EMC_DYN_CFG0 = 0x0280; |
---|
[32b8506] | 199 | |
---|
[687e34b] | 200 | /* CAS and RAS latency */ |
---|
| 201 | EMC_DYN_RASCAS0 = 0x0202; |
---|
[32b8506] | 202 | |
---|
[687e34b] | 203 | /* Wait 50 micro seconds */ |
---|
| 204 | lpc24xx_cpu_delay(3600); |
---|
[32b8506] | 205 | |
---|
[687e34b] | 206 | /* Send command: NOP */ |
---|
| 207 | EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_NOP; |
---|
[32b8506] | 208 | |
---|
[687e34b] | 209 | /* Wait 50 micro seconds */ |
---|
| 210 | lpc24xx_cpu_delay(3600); |
---|
[32b8506] | 211 | |
---|
[687e34b] | 212 | /* Send command: PRECHARGE ALL */ |
---|
| 213 | EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_PALL; |
---|
[32b8506] | 214 | |
---|
[687e34b] | 215 | /* Shortest possible refresh period */ |
---|
| 216 | EMC_DYN_RFSH = 0x01; |
---|
[32b8506] | 217 | |
---|
[687e34b] | 218 | /* Wait at least 128 AHB clock cycles */ |
---|
| 219 | lpc24xx_cpu_delay(128); |
---|
[32b8506] | 220 | |
---|
[687e34b] | 221 | /* Wait 1 micro second */ |
---|
| 222 | lpc24xx_cpu_delay(72); |
---|
[32b8506] | 223 | |
---|
[687e34b] | 224 | /* Set refresh period */ |
---|
| 225 | EMC_DYN_RFSH = 0x46; |
---|
[32b8506] | 226 | |
---|
[687e34b] | 227 | /* Send command: MODE */ |
---|
| 228 | EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_MODE; |
---|
[32b8506] | 229 | |
---|
[687e34b] | 230 | /* Set mode register in SDRAM */ |
---|
| 231 | *((volatile uint32_t *) (0xa0000000 | (0x23 << (1 + 2 + 8)))); |
---|
[32b8506] | 232 | |
---|
[687e34b] | 233 | /* Send command: NORMAL */ |
---|
| 234 | EMC_DYN_CTRL = 0; |
---|
[32b8506] | 235 | |
---|
[687e34b] | 236 | /* Enable buffer */ |
---|
| 237 | EMC_DYN_CFG0 |= 0x00080000; |
---|
[32b8506] | 238 | |
---|
[687e34b] | 239 | /* Test RAM */ |
---|
| 240 | lpc24xx_ram_test_32(); |
---|
| 241 | } |
---|
| 242 | #endif |
---|
| 243 | } |
---|
| 244 | |
---|
[c468f18b] | 245 | static void BSP_START_SECTION lpc24xx_pll_config( |
---|
[687e34b] | 246 | uint32_t val |
---|
| 247 | ) |
---|
| 248 | { |
---|
| 249 | PLLCON = val; |
---|
| 250 | PLLFEED = 0xaa; |
---|
| 251 | PLLFEED = 0x55; |
---|
| 252 | } |
---|
| 253 | |
---|
| 254 | /** |
---|
| 255 | * @brief Sets the Phase Locked Loop (PLL). |
---|
| 256 | * |
---|
| 257 | * All parameter values are the actual register field values. |
---|
| 258 | * |
---|
| 259 | * @param clksrc Selects the clock source for the PLL. |
---|
| 260 | * |
---|
| 261 | * @param nsel Selects PLL pre-divider value (sometimes named psel). |
---|
| 262 | * |
---|
| 263 | * @param msel Selects PLL multiplier value. |
---|
| 264 | * |
---|
| 265 | * @param cclksel Selects the divide value for creating the CPU clock (CCLK) |
---|
| 266 | * from the PLL output. |
---|
| 267 | */ |
---|
[c468f18b] | 268 | static void BSP_START_SECTION lpc24xx_set_pll( |
---|
[687e34b] | 269 | unsigned clksrc, |
---|
| 270 | unsigned nsel, |
---|
| 271 | unsigned msel, |
---|
| 272 | unsigned cclksel |
---|
| 273 | ) |
---|
| 274 | { |
---|
| 275 | uint32_t pllstat = PLLSTAT; |
---|
| 276 | uint32_t pllcfg = SET_PLLCFG_NSEL(0, nsel) | SET_PLLCFG_MSEL(0, msel); |
---|
| 277 | uint32_t clksrcsel = SET_CLKSRCSEL_CLKSRC(0, clksrc); |
---|
| 278 | uint32_t cclkcfg = SET_CCLKCFG_CCLKSEL(0, cclksel | 1); |
---|
[edf846e4] | 279 | bool pll_enabled = (pllstat & PLLSTAT_PLLE) != 0; |
---|
[687e34b] | 280 | |
---|
| 281 | /* Disconnect PLL if necessary */ |
---|
[edf846e4] | 282 | if ((pllstat & PLLSTAT_PLLC) != 0) { |
---|
[687e34b] | 283 | if (pll_enabled) { |
---|
| 284 | /* Check if we run already with the desired settings */ |
---|
| 285 | if (PLLCFG == pllcfg && CLKSRCSEL == clksrcsel && CCLKCFG == cclkcfg) { |
---|
| 286 | /* Nothing to do */ |
---|
| 287 | return; |
---|
| 288 | } |
---|
| 289 | lpc24xx_pll_config(PLLCON_PLLE); |
---|
| 290 | } else { |
---|
| 291 | lpc24xx_pll_config(0); |
---|
| 292 | } |
---|
| 293 | } |
---|
| 294 | |
---|
| 295 | /* Set CPU clock divider to a reasonable save value */ |
---|
| 296 | CCLKCFG = 0; |
---|
| 297 | |
---|
| 298 | /* Disable PLL if necessary */ |
---|
| 299 | if (pll_enabled) { |
---|
| 300 | lpc24xx_pll_config(0); |
---|
| 301 | } |
---|
| 302 | |
---|
| 303 | /* Select clock source */ |
---|
| 304 | CLKSRCSEL = clksrcsel; |
---|
| 305 | |
---|
| 306 | /* Set PLL Configuration Register */ |
---|
| 307 | PLLCFG = pllcfg; |
---|
| 308 | |
---|
| 309 | /* Enable PLL */ |
---|
| 310 | lpc24xx_pll_config(PLLCON_PLLE); |
---|
| 311 | |
---|
| 312 | /* Wait for lock */ |
---|
[edf846e4] | 313 | while ((PLLSTAT & PLLSTAT_PLOCK) == 0) { |
---|
[687e34b] | 314 | /* Wait */ |
---|
| 315 | } |
---|
| 316 | |
---|
| 317 | /* Set CPU clock divider and ensure that we have an odd value */ |
---|
| 318 | CCLKCFG = cclkcfg; |
---|
| 319 | |
---|
| 320 | /* Connect PLL */ |
---|
| 321 | lpc24xx_pll_config(PLLCON_PLLE | PLLCON_PLLC); |
---|
| 322 | } |
---|
| 323 | |
---|
[c468f18b] | 324 | static void BSP_START_SECTION lpc24xx_init_pll(void) |
---|
[687e34b] | 325 | { |
---|
| 326 | /* Enable main oscillator */ |
---|
[edf846e4] | 327 | if ((SCS & 0x40) == 0) { |
---|
| 328 | SCS |= 0x20; |
---|
| 329 | while ((SCS & 0x40) == 0) { |
---|
[687e34b] | 330 | /* Wait */ |
---|
| 331 | } |
---|
| 332 | } |
---|
| 333 | |
---|
| 334 | /* Set PLL */ |
---|
[22f107b6] | 335 | #if LPC24XX_OSCILLATOR_MAIN == 12000000U |
---|
| 336 | lpc24xx_set_pll(1, 0, 11, 3); |
---|
| 337 | #elif LPC24XX_OSCILLATOR_MAIN == 3686400U |
---|
| 338 | lpc24xx_set_pll(1, 0, 47, 5); |
---|
| 339 | #else |
---|
| 340 | #error "unexpected main oscillator frequency" |
---|
| 341 | #endif |
---|
[687e34b] | 342 | } |
---|
| 343 | |
---|
[c468f18b] | 344 | static void BSP_START_SECTION lpc24xx_clear_bss(void) |
---|
[687e34b] | 345 | { |
---|
| 346 | const int *end = (const int *) bsp_section_bss_end; |
---|
| 347 | int *out = (int *) bsp_section_bss_begin; |
---|
| 348 | |
---|
| 349 | /* Clear BSS */ |
---|
| 350 | while (out != end) { |
---|
| 351 | *out = 0; |
---|
| 352 | ++out; |
---|
| 353 | } |
---|
| 354 | } |
---|
| 355 | |
---|
[c468f18b] | 356 | void BSP_START_SECTION bsp_start_hook_0(void) |
---|
[687e34b] | 357 | { |
---|
| 358 | /* Initialize PLL */ |
---|
| 359 | lpc24xx_init_pll(); |
---|
| 360 | |
---|
| 361 | /* Initialize EMC hook 0 */ |
---|
| 362 | lpc24xx_init_emc_0(); |
---|
| 363 | } |
---|
| 364 | |
---|
[c468f18b] | 365 | void BSP_START_SECTION bsp_start_hook_1(void) |
---|
[687e34b] | 366 | { |
---|
| 367 | /* Re-map interrupt vectors to internal RAM */ |
---|
| 368 | MEMMAP = SET_MEMMAP_MAP(MEMMAP, 2); |
---|
| 369 | |
---|
[22f107b6] | 370 | /* Fully enable memory accelerator module functions (MAM) */ |
---|
[687e34b] | 371 | MAMCR = 0; |
---|
[22f107b6] | 372 | #if LPC24XX_CCLK <= 20000000U |
---|
| 373 | MAMTIM = 0x1; |
---|
| 374 | #elif LPC24XX_CCLK <= 40000000U |
---|
| 375 | MAMTIM = 0x2; |
---|
| 376 | #elif LPC24XX_CCLK <= 60000000U |
---|
| 377 | MAMTIM = 0x3; |
---|
| 378 | #else |
---|
| 379 | MAMTIM = 0x4; |
---|
| 380 | #endif |
---|
| 381 | MAMCR = 0x2; |
---|
[687e34b] | 382 | |
---|
| 383 | /* Enable fast IO for ports 0 and 1 */ |
---|
[edf846e4] | 384 | SCS |= 0x1; |
---|
[687e34b] | 385 | |
---|
| 386 | /* Set fast IO */ |
---|
| 387 | FIO0DIR = 0; |
---|
| 388 | FIO1DIR = 0; |
---|
| 389 | FIO2DIR = 0; |
---|
| 390 | FIO3DIR = 0; |
---|
| 391 | FIO4DIR = 0; |
---|
| 392 | FIO0CLR = 0xffffffff; |
---|
| 393 | FIO1CLR = 0xffffffff; |
---|
| 394 | FIO2CLR = 0xffffffff; |
---|
| 395 | FIO3CLR = 0xffffffff; |
---|
| 396 | FIO4CLR = 0xffffffff; |
---|
| 397 | |
---|
| 398 | /* Initialize EMC hook 1 */ |
---|
| 399 | lpc24xx_init_emc_1(); |
---|
| 400 | |
---|
[22f107b6] | 401 | #ifdef LPC24XX_STOP_GPDMA |
---|
| 402 | if ((PCONP & PCONP_GPDMA) != 0) { |
---|
| 403 | GPDMA_CONFIG = 0; |
---|
| 404 | PCONP &= ~PCONP_GPDMA; |
---|
| 405 | } |
---|
| 406 | #endif |
---|
| 407 | |
---|
| 408 | #ifdef LPC24XX_STOP_ETHERNET |
---|
| 409 | if ((PCONP & PCONP_ETHERNET) != 0) { |
---|
| 410 | MAC_COMMAND = 0x38; |
---|
| 411 | MAC_MAC1 = 0xcf00; |
---|
| 412 | MAC_MAC1 = 0; |
---|
| 413 | PCONP &= ~PCONP_ETHERNET; |
---|
| 414 | } |
---|
| 415 | #endif |
---|
| 416 | |
---|
| 417 | #ifdef LPC24XX_STOP_USB |
---|
| 418 | if ((PCONP & PCONP_USB) != 0) { |
---|
| 419 | OTG_CLK_CTRL = 0; |
---|
| 420 | PCONP &= ~PCONP_USB; |
---|
| 421 | } |
---|
| 422 | #endif |
---|
| 423 | |
---|
[687e34b] | 424 | /* Copy .text section */ |
---|
[22f107b6] | 425 | bsp_start_memcpy( |
---|
[687e34b] | 426 | (int *) bsp_section_text_begin, |
---|
| 427 | (const int *) bsp_section_text_load_begin, |
---|
| 428 | (size_t) bsp_section_text_size |
---|
| 429 | ); |
---|
| 430 | |
---|
| 431 | /* Copy .rodata section */ |
---|
[22f107b6] | 432 | bsp_start_memcpy( |
---|
[687e34b] | 433 | (int *) bsp_section_rodata_begin, |
---|
| 434 | (const int *) bsp_section_rodata_load_begin, |
---|
| 435 | (size_t) bsp_section_rodata_size |
---|
| 436 | ); |
---|
| 437 | |
---|
| 438 | /* Copy .data section */ |
---|
[22f107b6] | 439 | bsp_start_memcpy( |
---|
[687e34b] | 440 | (int *) bsp_section_data_begin, |
---|
| 441 | (const int *) bsp_section_data_load_begin, |
---|
| 442 | (size_t) bsp_section_data_size |
---|
| 443 | ); |
---|
| 444 | |
---|
| 445 | /* Copy .fast section */ |
---|
[22f107b6] | 446 | bsp_start_memcpy( |
---|
[687e34b] | 447 | (int *) bsp_section_fast_begin, |
---|
| 448 | (const int *) bsp_section_fast_load_begin, |
---|
| 449 | (size_t) bsp_section_fast_size |
---|
| 450 | ); |
---|
| 451 | |
---|
| 452 | /* Clear .bss section */ |
---|
| 453 | lpc24xx_clear_bss(); |
---|
| 454 | |
---|
| 455 | /* At this point we can use objects outside the .start section */ |
---|
| 456 | } |
---|