source: rtems/c/src/lib/libbsp/arm/lpc24xx/startup/bspstarthooks.c @ fb0584f

4.115
Last change on this file since fb0584f was fb0584f, checked in by Sebastian Huber <sebastian.huber@…>, on 05/03/13 at 08:39:26

bsps/arm: Move implementation to inline functions

  • Property mode set to 100644
File size: 13.3 KB
RevLine 
[687e34b]1/**
2 * @file
3 *
4 * @ingroup lpc24xx
5 *
6 * @brief Startup code.
7 */
8
9/*
[14ee5a1e]10 * Copyright (c) 2008-2012 embedded brains GmbH.  All rights reserved.
[d74ed4a]11 *
12 *  embedded brains GmbH
13 *  Obere Lagerstr. 30
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
[687e34b]17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.com/license/LICENSE.
21 */
22
[14ee5a1e]23#include <bsp.h>
[4a6cc2a]24#include <bsp/io.h>
[687e34b]25#include <bsp/start.h>
[d74ed4a]26#include <bsp/lpc24xx.h>
27#include <bsp/lpc-emc.h>
[4f609eec]28#include <bsp/start-config.h>
[687e34b]29
[4a6cc2a]30static BSP_START_TEXT_SECTION void lpc24xx_cpu_delay(unsigned ticks)
[4f609eec]31{
32  unsigned i = 0;
[687e34b]33
[4f609eec]34  /* One loop execution needs four instructions */
35  ticks /= 4;
[687e34b]36
[4f609eec]37  for (i = 0; i <= ticks; ++i) {
38    __asm__ volatile ("nop");
[687e34b]39  }
[4f609eec]40}
[d74ed4a]41
[4a6cc2a]42static BSP_START_TEXT_SECTION void lpc24xx_udelay(unsigned us)
[4f609eec]43{
44  lpc24xx_cpu_delay(us * (LPC24XX_CCLK / 1000000));
45}
[687e34b]46
[4a6cc2a]47static BSP_START_TEXT_SECTION void lpc24xx_init_pinsel(void)
[d74ed4a]48{
[4a6cc2a]49  lpc24xx_pin_config(
50    &lpc24xx_start_config_pinsel [0],
51    LPC24XX_PIN_SET_FUNCTION
[4f609eec]52  );
[d74ed4a]53}
54
[4a6cc2a]55static BSP_START_TEXT_SECTION void lpc24xx_init_emc_static(void)
[687e34b]56{
[4f609eec]57  size_t i = 0;
58  size_t chip_count = lpc24xx_start_config_emc_static_chip_count;
[687e34b]59
[4f609eec]60  for (i = 0; i < chip_count; ++i) {
61    const lpc24xx_emc_static_chip_config *chip_config =
62      &lpc24xx_start_config_emc_static_chip [i];
[d74ed4a]63    lpc24xx_emc_static_chip_config chip_config_on_stack;
[4f609eec]64    size_t config_size = sizeof(chip_config_on_stack.config);
[687e34b]65
[d74ed4a]66    bsp_start_memcpy(
[4f609eec]67      (int *) &chip_config_on_stack.config,
68      (const int *) &chip_config->config,
69      config_size
[d74ed4a]70    );
[22f107b6]71    bsp_start_memcpy(
[4f609eec]72      (int *) chip_config->chip_select,
73      (const int *) &chip_config_on_stack.config,
74      config_size
[687e34b]75    );
[4f609eec]76  }
[687e34b]77}
78
[4a6cc2a]79static BSP_START_TEXT_SECTION void lpc24xx_init_emc_dynamic(void)
[d74ed4a]80{
[4f609eec]81  size_t chip_count = lpc24xx_start_config_emc_dynamic_chip_count;
[32b8506]82
[4f609eec]83  if (chip_count > 0) {
84    bool do_initialization = true;
85    size_t i = 0;
[32b8506]86
[4f609eec]87    for (i = 0; do_initialization && i < chip_count; ++i) {
88      const lpc24xx_emc_dynamic_chip_config *chip_cfg =
89        &lpc24xx_start_config_emc_dynamic_chip [i];
90      volatile lpc_emc_dynamic *chip_select = chip_cfg->chip_select;
[32b8506]91
[4f609eec]92      do_initialization = (chip_select->config & EMC_DYN_CFG_B) == 0;
93    }
[32b8506]94
[4f609eec]95    if (do_initialization) {
96      volatile lpc_emc *emc = (volatile lpc_emc *) EMC_BASE_ADDR;
97      const lpc24xx_emc_dynamic_config *cfg =
98        &lpc24xx_start_config_emc_dynamic [0];
99      uint32_t dynamiccontrol = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS;
100
[14ee5a1e]101      #ifdef ARM_MULTILIB_ARCH_V7M
102        volatile lpc17xx_scb *scb = &LPC17XX_SCB;
103
104        /* Delay control */
105        scb->emcdlyctl = cfg->emcdlyctl;
106      #endif
107
[4f609eec]108      emc->dynamicreadconfig = cfg->readconfig;
109
110      /* Timings */
111      emc->dynamictrp = cfg->trp;
112      emc->dynamictras = cfg->tras;
113      emc->dynamictsrex = cfg->tsrex;
114      emc->dynamictapr = cfg->tapr;
115      emc->dynamictdal = cfg->tdal;
116      emc->dynamictwr = cfg->twr;
117      emc->dynamictrc = cfg->trc;
118      emc->dynamictrfc = cfg->trfc;
119      emc->dynamictxsr = cfg->txsr;
120      emc->dynamictrrd = cfg->trrd;
121      emc->dynamictmrd = cfg->tmrd;
122
123      /* NOP period */
[d74ed4a]124      emc->dynamiccontrol = dynamiccontrol | EMC_DYN_CTRL_I_NOP;
125      lpc24xx_udelay(200);
126
[4f609eec]127      /* Precharge */
[d74ed4a]128      emc->dynamiccontrol = dynamiccontrol | EMC_DYN_CTRL_I_PALL;
[4f609eec]129      emc->dynamicrefresh = 1;
[32b8506]130
[d74ed4a]131      /*
132       * Perform several refresh cycles with a memory refresh every 16 AHB
133       * clock cycles.  Wait until eight SDRAM refresh cycles have occurred
134       * (128 AHB clock cycles).
135       */
[687e34b]136      lpc24xx_cpu_delay(128);
[32b8506]137
[4f609eec]138      /* Refresh timing */
139      emc->dynamicrefresh = cfg->refresh;
140      lpc24xx_cpu_delay(128);
[32b8506]141
[4f609eec]142      for (i = 0; i < chip_count; ++i) {
143        const lpc24xx_emc_dynamic_chip_config *chip_cfg =
144          &lpc24xx_start_config_emc_dynamic_chip [i];
145        volatile lpc_emc_dynamic *chip_select = chip_cfg->chip_select;
146        uint32_t config = chip_cfg->config;
[32b8506]147
[4f609eec]148        /* Chip select */
149        chip_select->config = config;
150        chip_select->rascas = chip_cfg->rascas;
[32b8506]151
[4f609eec]152        /* Set modes */
153        emc->dynamiccontrol = dynamiccontrol | EMC_DYN_CTRL_I_MODE;
154        *(volatile uint32_t *)(chip_cfg->address + chip_cfg->mode);
[32b8506]155
[4f609eec]156        /* Enable buffer */
157        chip_select->config = config | EMC_DYN_CFG_B;
158      }
[32b8506]159
[4a6cc2a]160      emc->dynamiccontrol = 0;
[687e34b]161    }
[4f609eec]162  }
[687e34b]163}
164
[4a6cc2a]165static BSP_START_TEXT_SECTION void lpc24xx_init_main_oscillator(void)
166{
167  #ifdef ARM_MULTILIB_ARCH_V4
168    if ((SCS & 0x40) == 0) {
169      SCS |= 0x20;
170      while ((SCS & 0x40) == 0) {
171        /* Wait */
172      }
173    }
[14ee5a1e]174  #else
175    volatile lpc17xx_scb *scb = &LPC17XX_SCB;
176
177    if ((scb->scs & LPC17XX_SCB_SCS_OSC_STATUS) == 0) {
178      scb->scs |= LPC17XX_SCB_SCS_OSC_ENABLE;
179      while ((scb->scs & LPC17XX_SCB_SCS_OSC_STATUS) == 0) {
180        /* Wait */
181      }
182    }
[4a6cc2a]183  #endif
184}
185
186#ifdef ARM_MULTILIB_ARCH_V4
187
188static BSP_START_TEXT_SECTION void lpc24xx_pll_config(
[687e34b]189  uint32_t val
190)
191{
192  PLLCON = val;
193  PLLFEED = 0xaa;
194  PLLFEED = 0x55;
195}
196
197/**
198 * @brief Sets the Phase Locked Loop (PLL).
199 *
200 * All parameter values are the actual register field values.
201 *
202 * @param clksrc Selects the clock source for the PLL.
203 *
204 * @param nsel Selects PLL pre-divider value (sometimes named psel).
205 *
206 * @param msel Selects PLL multiplier value.
207 *
208 * @param cclksel Selects the divide value for creating the CPU clock (CCLK)
209 * from the PLL output.
210 */
[4a6cc2a]211static BSP_START_TEXT_SECTION void lpc24xx_set_pll(
[687e34b]212  unsigned clksrc,
213  unsigned nsel,
214  unsigned msel,
215  unsigned cclksel
216)
217{
218  uint32_t pllstat = PLLSTAT;
219  uint32_t pllcfg = SET_PLLCFG_NSEL(0, nsel) | SET_PLLCFG_MSEL(0, msel);
220  uint32_t clksrcsel = SET_CLKSRCSEL_CLKSRC(0, clksrc);
221  uint32_t cclkcfg = SET_CCLKCFG_CCLKSEL(0, cclksel | 1);
[edf846e4]222  bool pll_enabled = (pllstat & PLLSTAT_PLLE) != 0;
[687e34b]223
224  /* Disconnect PLL if necessary */
[edf846e4]225  if ((pllstat & PLLSTAT_PLLC) != 0) {
[687e34b]226    if (pll_enabled) {
227      /* Check if we run already with the desired settings */
228      if (PLLCFG == pllcfg && CLKSRCSEL == clksrcsel && CCLKCFG == cclkcfg) {
229        /* Nothing to do */
230        return;
231      }
232      lpc24xx_pll_config(PLLCON_PLLE);
233    } else {
234      lpc24xx_pll_config(0);
235    }
236  }
237
238  /* Set CPU clock divider to a reasonable save value */
239  CCLKCFG = 0;
240
241  /* Disable PLL if necessary */
242  if (pll_enabled) {
243    lpc24xx_pll_config(0);
244  }
245
246  /* Select clock source */
247  CLKSRCSEL = clksrcsel;
248
249  /* Set PLL Configuration Register */
250  PLLCFG = pllcfg;
251
252  /* Enable PLL */
253  lpc24xx_pll_config(PLLCON_PLLE);
254
255  /* Wait for lock */
[edf846e4]256  while ((PLLSTAT & PLLSTAT_PLOCK) == 0) {
[687e34b]257    /* Wait */
258  }
259
260  /* Set CPU clock divider and ensure that we have an odd value */
261  CCLKCFG = cclkcfg;
262
263  /* Connect PLL */
264  lpc24xx_pll_config(PLLCON_PLLE | PLLCON_PLLC);
265}
266
[14ee5a1e]267#else /* ARM_MULTILIB_ARCH_V4 */
268
269static BSP_START_TEXT_SECTION void lpc17xx_pll_config(
270  volatile lpc17xx_pll *pll,
271  uint32_t val
272)
273{
274  pll->con = val;
275  pll->feed = 0xaa;
276  pll->feed = 0x55;
277}
278
279static BSP_START_TEXT_SECTION void lpc17xx_set_pll(
280  unsigned msel,
281  unsigned psel,
282  unsigned cclkdiv
283)
284{
285  volatile lpc17xx_scb *scb = &LPC17XX_SCB;
286  volatile lpc17xx_pll *pll = &scb->pll_0;
287  uint32_t pllcfg = LPC17XX_PLL_SEL_MSEL(msel)
288    | LPC17XX_PLL_SEL_PSEL(psel);
289  uint32_t pllstat = LPC17XX_PLL_STAT_PLLE
290    | LPC17XX_PLL_STAT_PLOCK | pllcfg;
291  uint32_t cclksel_cclkdiv = LPC17XX_SCB_CCLKSEL_CCLKDIV(cclkdiv);
292  uint32_t cclksel = LPC17XX_SCB_CCLKSEL_CCLKSEL | cclksel_cclkdiv;
293
294  if (
295    pll->stat != pllstat
296      || scb->cclksel != cclksel
297      || scb->clksrcsel != LPC17XX_SCB_CLKSRCSEL_CLKSRC
298  ) {
299    /* Use SYSCLK for CCLK */
300    scb->cclksel = LPC17XX_SCB_CCLKSEL_CCLKDIV(1);
301
302    /* Turn off USB */
303    scb->usbclksel = 0;
304
305    /* Disable PLL */
306    lpc17xx_pll_config(pll, 0);
307
308    /* Select main oscillator as clock source */
309    scb->clksrcsel = LPC17XX_SCB_CLKSRCSEL_CLKSRC;
310
311    /* Set PLL configuration */
312    pll->cfg = pllcfg;
313
314    /* Set the CCLK, PCLK and EMCCLK divider */
315    scb->cclksel = cclksel_cclkdiv;
[f72b2de]316    scb->pclksel = LPC17XX_SCB_PCLKSEL_PCLKDIV(cclkdiv * LPC24XX_PCLKDIV);
[14ee5a1e]317    scb->emcclksel = LPC24XX_EMCCLKDIV == 1 ? 0 : LPC17XX_SCB_EMCCLKSEL_EMCDIV;
318
319    /* Enable PLL */
320    lpc17xx_pll_config(pll, LPC17XX_PLL_CON_PLLE);
321
322    /* Wait for lock */
323    while ((pll->stat & LPC17XX_PLL_STAT_PLOCK) == 0) {
324      /* Wait */
325    }
326
327    /* Use the PLL clock */
328    scb->cclksel = cclksel;
329  }
330}
331
[4a6cc2a]332#endif /* ARM_MULTILIB_ARCH_V4 */
[687e34b]333
[4a6cc2a]334static BSP_START_TEXT_SECTION void lpc24xx_init_pll(void)
335{
336  #ifdef ARM_MULTILIB_ARCH_V4
337    #if LPC24XX_OSCILLATOR_MAIN == 12000000U
338      #if LPC24XX_CCLK == 72000000U
339        lpc24xx_set_pll(1, 0, 11, 3);
340      #elif LPC24XX_CCLK == 51612800U
341        lpc24xx_set_pll(1, 30, 399, 5);
342      #else
343        #error "unexpected CCLK"
344      #endif
345    #elif LPC24XX_OSCILLATOR_MAIN == 3686400U
346      #if LPC24XX_CCLK == 58982400U
347        lpc24xx_set_pll(1, 0, 47, 5);
348      #else
349        #error "unexpected CCLK"
350      #endif
[4f609eec]351    #else
[4a6cc2a]352      #error "unexpected main oscillator frequency"
[4f609eec]353    #endif
[14ee5a1e]354  #else
355    #if LPC24XX_OSCILLATOR_MAIN == 12000000U
356      #if LPC24XX_CCLK == 120000000U
357        lpc17xx_set_pll(9, 0, 1);
358      #elif LPC24XX_CCLK == 96000000U
359        lpc17xx_set_pll(7, 0, 1);
360      #elif LPC24XX_CCLK == 72000000U
361        lpc17xx_set_pll(5, 1, 1);
362      #elif LPC24XX_CCLK == 48000000U
363        lpc17xx_set_pll(3, 1, 1);
364      #else
365        #error "unexpected CCLK"
366      #endif
367    #else
368      #error "unexpected main oscillator frequency"
369    #endif
[22f107b6]370  #endif
[687e34b]371}
372
[4a6cc2a]373static BSP_START_TEXT_SECTION void lpc24xx_init_memory_map(void)
[687e34b]374{
[4a6cc2a]375  #ifdef ARM_MULTILIB_ARCH_V4
376    /* Re-map interrupt vectors to internal RAM */
377    MEMMAP = SET_MEMMAP_MAP(MEMMAP, 2);
[14ee5a1e]378  #else
379    volatile lpc17xx_scb *scb = &LPC17XX_SCB;
380
381    scb->memmap = LPC17XX_SCB_MEMMAP_MAP;
[4a6cc2a]382  #endif
[687e34b]383
[4a6cc2a]384  /* Use normal memory map */
385  EMC_CTRL &= ~0x2U;
[687e34b]386}
387
[4a6cc2a]388static BSP_START_TEXT_SECTION void lpc24xx_init_memory_accelerator(void)
[687e34b]389{
[4a6cc2a]390  #ifdef ARM_MULTILIB_ARCH_V4
391    /* Fully enable memory accelerator module functions (MAM) */
392    MAMCR = 0;
393    #if LPC24XX_CCLK <= 20000000U
394      MAMTIM = 0x1;
395    #elif LPC24XX_CCLK <= 40000000U
396      MAMTIM = 0x2;
397    #elif LPC24XX_CCLK <= 60000000U
398      MAMTIM = 0x3;
399    #else
400      MAMTIM = 0x4;
401    #endif
402    MAMCR = 0x2;
[687e34b]403
[4a6cc2a]404    /* Enable fast IO for ports 0 and 1 */
405    SCS |= 0x1;
[14ee5a1e]406  #else
407    volatile lpc17xx_scb *scb = &LPC17XX_SCB;
408
409    #if LPC24XX_CCLK <= 20000000U
410      scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x0);
411    #elif LPC24XX_CCLK <= 40000000U
412      scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x1);
413    #elif LPC24XX_CCLK <= 60000000U
414      scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x2);
415    #elif LPC24XX_CCLK <= 80000000U
416      scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x3);
417    #elif LPC24XX_CCLK <= 100000000U
418      scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x4);
419    #else
420      scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x5);
421    #endif
[22f107b6]422  #endif
[4a6cc2a]423}
[687e34b]424
[4a6cc2a]425static BSP_START_TEXT_SECTION void lpc24xx_stop_gpdma(void)
426{
[22f107b6]427  #ifdef LPC24XX_STOP_GPDMA
[4a6cc2a]428    #ifdef ARM_MULTILIB_ARCH_V4
429      bool has_power = (PCONP & PCONP_GPDMA) != 0;
[14ee5a1e]430    #else
431      volatile lpc17xx_scb *scb = &LPC17XX_SCB;
432      bool has_power = (scb->pconp & LPC17XX_SCB_PCONP_GPDMA) != 0;
[4a6cc2a]433    #endif
434
435    if (has_power) {
[22f107b6]436      GPDMA_CONFIG = 0;
[4a6cc2a]437
438      #ifdef ARM_MULTILIB_ARCH_V4
439        PCONP &= ~PCONP_GPDMA;
[14ee5a1e]440      #else
441        scb->pconp &= ~LPC17XX_SCB_PCONP_GPDMA;
[4a6cc2a]442      #endif
[22f107b6]443    }
444  #endif
[4a6cc2a]445}
[22f107b6]446
[4a6cc2a]447static BSP_START_TEXT_SECTION void lpc24xx_stop_ethernet(void)
448{
[22f107b6]449  #ifdef LPC24XX_STOP_ETHERNET
[4a6cc2a]450    #ifdef ARM_MULTILIB_ARCH_V4
451      bool has_power = (PCONP & PCONP_ETHERNET) != 0;
[14ee5a1e]452    #else
453      volatile lpc17xx_scb *scb = &LPC17XX_SCB;
454      bool has_power = (scb->pconp & LPC17XX_SCB_PCONP_ENET) != 0;
[4a6cc2a]455    #endif
456
457    if (has_power) {
[22f107b6]458      MAC_COMMAND = 0x38;
459      MAC_MAC1 = 0xcf00;
460      MAC_MAC1 = 0;
[4a6cc2a]461
462      #ifdef ARM_MULTILIB_ARCH_V4
463        PCONP &= ~PCONP_ETHERNET;
[14ee5a1e]464      #else
465        scb->pconp &= ~LPC17XX_SCB_PCONP_ENET;
[4a6cc2a]466      #endif
[22f107b6]467    }
468  #endif
[4a6cc2a]469}
[22f107b6]470
[4a6cc2a]471static BSP_START_TEXT_SECTION void lpc24xx_stop_usb(void)
472{
[22f107b6]473  #ifdef LPC24XX_STOP_USB
[4a6cc2a]474    #ifdef ARM_MULTILIB_ARCH_V4
475      bool has_power = (PCONP & PCONP_USB) != 0;
[14ee5a1e]476    #else
477      volatile lpc17xx_scb *scb = &LPC17XX_SCB;
478      bool has_power = (scb->pconp & LPC17XX_SCB_PCONP_USB) != 0;
[4a6cc2a]479    #endif
480
481    if (has_power) {
[22f107b6]482      OTG_CLK_CTRL = 0;
[4a6cc2a]483
484      #ifdef ARM_MULTILIB_ARCH_V4
485        PCONP &= ~PCONP_USB;
[14ee5a1e]486      #else
487        scb->pconp &= ~LPC17XX_SCB_PCONP_USB;
488        scb->usbclksel = 0;
[4a6cc2a]489      #endif
[22f107b6]490    }
491  #endif
[4a6cc2a]492}
[22f107b6]493
[14ee5a1e]494static BSP_START_TEXT_SECTION void lpc24xx_init_mpu(void)
495{
496  #ifdef ARM_MULTILIB_ARCH_V7M
497    volatile ARMV7M_MPU *mpu = _ARMV7M_MPU;
[a94bcc5a]498    size_t region_count = lpc24xx_start_config_mpu_region_count;
[14ee5a1e]499    size_t i = 0;
500
[a94bcc5a]501    for (i = 0; i < region_count; ++i) {
502      mpu->rbar = lpc24xx_start_config_mpu_region [i].rbar;
503      mpu->rasr = lpc24xx_start_config_mpu_region [i].rasr;
[14ee5a1e]504    }
505
[a94bcc5a]506    if (region_count > 0) {
[14ee5a1e]507      mpu->ctrl = ARMV7M_MPU_CTRL_ENABLE;
508    }
509  #endif
510}
511
[4a6cc2a]512BSP_START_TEXT_SECTION void bsp_start_hook_0(void)
513{
514  lpc24xx_init_main_oscillator();
515  lpc24xx_init_pll();
516  lpc24xx_init_pinsel();
517  lpc24xx_init_emc_static();
518}
[687e34b]519
[4a6cc2a]520BSP_START_TEXT_SECTION void bsp_start_hook_1(void)
521{
522  lpc24xx_init_memory_map();
523  lpc24xx_init_memory_accelerator();
524  lpc24xx_init_emc_dynamic();
[14ee5a1e]525  lpc24xx_init_mpu();
[4a6cc2a]526  lpc24xx_stop_gpdma();
527  lpc24xx_stop_ethernet();
528  lpc24xx_stop_usb();
529  bsp_start_copy_sections();
[fb0584f]530  bsp_start_clear_bss();
[687e34b]531
532  /* At this point we can use objects outside the .start section */
533}
Note: See TracBrowser for help on using the repository browser.