Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:03

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsARMLPC24XX
0007  *
0008  * @brief Startup code.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2008, 2012 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp.h>
0037 #include <bsp/io.h>
0038 #include <bsp/start.h>
0039 #include <bsp/lpc24xx.h>
0040 #include <bsp/lpc-emc.h>
0041 #include <bsp/start-config.h>
0042 
0043 static BSP_START_TEXT_SECTION void lpc24xx_cpu_delay(unsigned ticks)
0044 {
0045   unsigned i = 0;
0046 
0047   /* One loop execution needs four instructions */
0048   ticks /= 4;
0049 
0050   for (i = 0; i <= ticks; ++i) {
0051     __asm__ volatile ("nop");
0052   }
0053 }
0054 
0055 static BSP_START_TEXT_SECTION void lpc24xx_udelay(unsigned us)
0056 {
0057   lpc24xx_cpu_delay(us * (LPC24XX_CCLK / 1000000));
0058 }
0059 
0060 static BSP_START_TEXT_SECTION void lpc24xx_init_pinsel(void)
0061 {
0062   lpc24xx_pin_config(
0063     &lpc24xx_start_config_pinsel [0],
0064     LPC24XX_PIN_SET_FUNCTION
0065   );
0066 }
0067 
0068 static BSP_START_TEXT_SECTION void lpc24xx_init_emc_static(void)
0069 {
0070   size_t i = 0;
0071   size_t chip_count = lpc24xx_start_config_emc_static_chip_count;
0072 
0073   for (i = 0; i < chip_count; ++i) {
0074     const lpc24xx_emc_static_chip_config *chip_config =
0075       &lpc24xx_start_config_emc_static_chip [i];
0076     lpc24xx_emc_static_chip_config chip_config_on_stack;
0077     size_t config_size = sizeof(chip_config_on_stack.config);
0078 
0079     bsp_start_memcpy(
0080       (int *) &chip_config_on_stack.config,
0081       (const int *) &chip_config->config,
0082       config_size
0083     );
0084     bsp_start_memcpy(
0085       (int *) chip_config->chip_select,
0086       (const int *) &chip_config_on_stack.config,
0087       config_size
0088     );
0089   }
0090 }
0091 
0092 static BSP_START_TEXT_SECTION void lpc24xx_init_emc_dynamic(void)
0093 {
0094   size_t chip_count = lpc24xx_start_config_emc_dynamic_chip_count;
0095 
0096   if (chip_count > 0) {
0097     bool do_initialization = true;
0098     size_t i = 0;
0099 
0100     for (i = 0; do_initialization && i < chip_count; ++i) {
0101       const lpc24xx_emc_dynamic_chip_config *chip_cfg =
0102         &lpc24xx_start_config_emc_dynamic_chip [i];
0103       volatile lpc_emc_dynamic *chip_select = chip_cfg->chip_select;
0104 
0105       do_initialization = (chip_select->config & EMC_DYN_CFG_B) == 0;
0106     }
0107 
0108     if (do_initialization) {
0109       volatile lpc_emc *emc = (volatile lpc_emc *) EMC_BASE_ADDR;
0110       const lpc24xx_emc_dynamic_config *cfg =
0111         &lpc24xx_start_config_emc_dynamic [0];
0112       uint32_t dynamiccontrol = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS;
0113 
0114       #ifdef ARM_MULTILIB_ARCH_V7M
0115         volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0116 
0117         /* Delay control */
0118         scb->emcdlyctl = cfg->emcdlyctl;
0119       #endif
0120 
0121       emc->dynamicreadconfig = cfg->readconfig;
0122 
0123       /* Timings */
0124       emc->dynamictrp = cfg->trp;
0125       emc->dynamictras = cfg->tras;
0126       emc->dynamictsrex = cfg->tsrex;
0127       emc->dynamictapr = cfg->tapr;
0128       emc->dynamictdal = cfg->tdal;
0129       emc->dynamictwr = cfg->twr;
0130       emc->dynamictrc = cfg->trc;
0131       emc->dynamictrfc = cfg->trfc;
0132       emc->dynamictxsr = cfg->txsr;
0133       emc->dynamictrrd = cfg->trrd;
0134       emc->dynamictmrd = cfg->tmrd;
0135 
0136       /* NOP period */
0137       emc->dynamiccontrol = dynamiccontrol | EMC_DYN_CTRL_I_NOP;
0138       lpc24xx_udelay(200);
0139 
0140       /* Precharge */
0141       emc->dynamiccontrol = dynamiccontrol | EMC_DYN_CTRL_I_PALL;
0142       emc->dynamicrefresh = 1;
0143 
0144       /*
0145        * Perform several refresh cycles with a memory refresh every 16 AHB
0146        * clock cycles.  Wait until eight SDRAM refresh cycles have occurred
0147        * (128 AHB clock cycles).
0148        */
0149       lpc24xx_cpu_delay(128);
0150 
0151       /* Refresh timing */
0152       emc->dynamicrefresh = cfg->refresh;
0153       lpc24xx_cpu_delay(128);
0154 
0155       for (i = 0; i < chip_count; ++i) {
0156         const lpc24xx_emc_dynamic_chip_config *chip_cfg =
0157           &lpc24xx_start_config_emc_dynamic_chip [i];
0158         volatile lpc_emc_dynamic *chip_select = chip_cfg->chip_select;
0159         uint32_t config = chip_cfg->config;
0160 
0161         /* Chip select */
0162         chip_select->config = config;
0163         chip_select->rascas = chip_cfg->rascas;
0164 
0165         /* Set modes */
0166         emc->dynamiccontrol = dynamiccontrol | EMC_DYN_CTRL_I_MODE;
0167         *(volatile uint32_t *)(chip_cfg->address + chip_cfg->mode);
0168 
0169         /* Enable buffer */
0170         chip_select->config = config | EMC_DYN_CFG_B;
0171       }
0172 
0173       emc->dynamiccontrol = 0;
0174     }
0175   }
0176 }
0177 
0178 static BSP_START_TEXT_SECTION void lpc24xx_init_main_oscillator(void)
0179 {
0180   #ifdef ARM_MULTILIB_ARCH_V4
0181     if ((SCS & 0x40) == 0) {
0182       SCS |= 0x20;
0183       while ((SCS & 0x40) == 0) {
0184         /* Wait */
0185       }
0186     }
0187   #else
0188     volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0189 
0190     if ((scb->scs & LPC17XX_SCB_SCS_OSC_STATUS) == 0) {
0191       scb->scs |= LPC17XX_SCB_SCS_OSC_ENABLE;
0192       while ((scb->scs & LPC17XX_SCB_SCS_OSC_STATUS) == 0) {
0193         /* Wait */
0194       }
0195     }
0196   #endif
0197 }
0198 
0199 #ifdef ARM_MULTILIB_ARCH_V4
0200 
0201 static BSP_START_TEXT_SECTION void lpc24xx_pll_config(
0202   uint32_t val
0203 )
0204 {
0205   PLLCON = val;
0206   PLLFEED = 0xaa;
0207   PLLFEED = 0x55;
0208 }
0209 
0210 /**
0211  * @brief Sets the Phase Locked Loop (PLL).
0212  *
0213  * All parameter values are the actual register field values.
0214  *
0215  * @param clksrc Selects the clock source for the PLL.
0216  *
0217  * @param nsel Selects PLL pre-divider value (sometimes named psel).
0218  *
0219  * @param msel Selects PLL multiplier value.
0220  *
0221  * @param cclksel Selects the divide value for creating the CPU clock (CCLK)
0222  * from the PLL output.
0223  */
0224 static BSP_START_TEXT_SECTION void lpc24xx_set_pll(
0225   unsigned clksrc,
0226   unsigned nsel,
0227   unsigned msel,
0228   unsigned cclksel
0229 )
0230 {
0231   uint32_t pllstat = PLLSTAT;
0232   uint32_t pllcfg = SET_PLLCFG_NSEL(0, nsel) | SET_PLLCFG_MSEL(0, msel);
0233   uint32_t clksrcsel = SET_CLKSRCSEL_CLKSRC(0, clksrc);
0234   uint32_t cclkcfg = SET_CCLKCFG_CCLKSEL(0, cclksel | 1);
0235   bool pll_enabled = (pllstat & PLLSTAT_PLLE) != 0;
0236 
0237   /* Disconnect PLL if necessary */
0238   if ((pllstat & PLLSTAT_PLLC) != 0) {
0239     if (pll_enabled) {
0240       /* Check if we run already with the desired settings */
0241       if (PLLCFG == pllcfg && CLKSRCSEL == clksrcsel && CCLKCFG == cclkcfg) {
0242         /* Nothing to do */
0243         return;
0244       }
0245       lpc24xx_pll_config(PLLCON_PLLE);
0246     } else {
0247       lpc24xx_pll_config(0);
0248     }
0249   }
0250 
0251   /* Set CPU clock divider to a reasonable save value */
0252   CCLKCFG = 0;
0253 
0254   /* Disable PLL if necessary */
0255   if (pll_enabled) {
0256     lpc24xx_pll_config(0);
0257   }
0258 
0259   /* Select clock source */
0260   CLKSRCSEL = clksrcsel;
0261 
0262   /* Set PLL Configuration Register */
0263   PLLCFG = pllcfg;
0264 
0265   /* Enable PLL */
0266   lpc24xx_pll_config(PLLCON_PLLE);
0267 
0268   /* Wait for lock */
0269   while ((PLLSTAT & PLLSTAT_PLOCK) == 0) {
0270     /* Wait */
0271   }
0272 
0273   /* Set CPU clock divider and ensure that we have an odd value */
0274   CCLKCFG = cclkcfg;
0275 
0276   /* Connect PLL */
0277   lpc24xx_pll_config(PLLCON_PLLE | PLLCON_PLLC);
0278 }
0279 
0280 #else /* ARM_MULTILIB_ARCH_V4 */
0281 
0282 static BSP_START_TEXT_SECTION void lpc17xx_pll_config(
0283   volatile lpc17xx_pll *pll,
0284   uint32_t val
0285 )
0286 {
0287   pll->con = val;
0288   pll->feed = 0xaa;
0289   pll->feed = 0x55;
0290 }
0291 
0292 static BSP_START_TEXT_SECTION void lpc17xx_set_pll(
0293   unsigned msel,
0294   unsigned psel,
0295   unsigned cclkdiv
0296 )
0297 {
0298   volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0299   volatile lpc17xx_pll *pll = &scb->pll_0;
0300   uint32_t pllcfg = LPC17XX_PLL_SEL_MSEL(msel)
0301     | LPC17XX_PLL_SEL_PSEL(psel);
0302   uint32_t pllstat = LPC17XX_PLL_STAT_PLLE
0303     | LPC17XX_PLL_STAT_PLOCK | pllcfg;
0304   uint32_t cclksel_cclkdiv = LPC17XX_SCB_CCLKSEL_CCLKDIV(cclkdiv);
0305   uint32_t cclksel = LPC17XX_SCB_CCLKSEL_CCLKSEL | cclksel_cclkdiv;
0306 
0307   if (
0308     pll->stat != pllstat
0309       || scb->cclksel != cclksel
0310       || scb->clksrcsel != LPC17XX_SCB_CLKSRCSEL_CLKSRC
0311   ) {
0312     /* Use SYSCLK for CCLK */
0313     scb->cclksel = LPC17XX_SCB_CCLKSEL_CCLKDIV(1);
0314 
0315     /* Turn off USB */
0316     scb->usbclksel = 0;
0317 
0318     /* Disable PLL */
0319     lpc17xx_pll_config(pll, 0);
0320 
0321     /* Select main oscillator as clock source */
0322     scb->clksrcsel = LPC17XX_SCB_CLKSRCSEL_CLKSRC;
0323 
0324     /* Set PLL configuration */
0325     pll->cfg = pllcfg;
0326 
0327     /* Set the CCLK, PCLK and EMCCLK divider */
0328     scb->cclksel = cclksel_cclkdiv;
0329     scb->pclksel = LPC17XX_SCB_PCLKSEL_PCLKDIV(cclkdiv * LPC24XX_PCLKDIV);
0330     scb->emcclksel = LPC24XX_EMCCLKDIV == 1 ? 0 : LPC17XX_SCB_EMCCLKSEL_EMCDIV;
0331 
0332     /* Enable PLL */
0333     lpc17xx_pll_config(pll, LPC17XX_PLL_CON_PLLE);
0334 
0335     /* Wait for lock */
0336     while ((pll->stat & LPC17XX_PLL_STAT_PLOCK) == 0) {
0337       /* Wait */
0338     }
0339 
0340     /* Use the PLL clock */
0341     scb->cclksel = cclksel;
0342   }
0343 }
0344 
0345 #endif /* ARM_MULTILIB_ARCH_V4 */
0346 
0347 static BSP_START_TEXT_SECTION void lpc24xx_init_pll(void)
0348 {
0349   #ifdef ARM_MULTILIB_ARCH_V4
0350     #if LPC24XX_OSCILLATOR_MAIN == 12000000U
0351       #if LPC24XX_CCLK == 72000000U
0352         lpc24xx_set_pll(1, 0, 11, 3);
0353       #elif LPC24XX_CCLK == 51612800U
0354         lpc24xx_set_pll(1, 30, 399, 5);
0355       #else
0356         #error "unexpected CCLK"
0357       #endif
0358     #elif LPC24XX_OSCILLATOR_MAIN == 3686400U
0359       #if LPC24XX_CCLK == 58982400U
0360         lpc24xx_set_pll(1, 0, 47, 5);
0361       #else
0362         #error "unexpected CCLK"
0363       #endif
0364     #else
0365       #error "unexpected main oscillator frequency"
0366     #endif
0367   #else
0368     #if LPC24XX_OSCILLATOR_MAIN == 12000000U
0369       #if LPC24XX_CCLK == 120000000U
0370         lpc17xx_set_pll(9, 0, 1);
0371       #elif LPC24XX_CCLK == 96000000U
0372         lpc17xx_set_pll(7, 0, 1);
0373       #elif LPC24XX_CCLK == 72000000U
0374         lpc17xx_set_pll(5, 1, 1);
0375       #elif LPC24XX_CCLK == 48000000U
0376         lpc17xx_set_pll(3, 1, 1);
0377       #else
0378         #error "unexpected CCLK"
0379       #endif
0380     #else
0381       #error "unexpected main oscillator frequency"
0382     #endif
0383   #endif
0384 }
0385 
0386 static BSP_START_TEXT_SECTION void lpc24xx_init_memory_map(void)
0387 {
0388   #ifdef ARM_MULTILIB_ARCH_V4
0389     /* Re-map interrupt vectors to internal RAM */
0390     MEMMAP = SET_MEMMAP_MAP(MEMMAP, 2);
0391   #else
0392     volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0393 
0394     scb->memmap = LPC17XX_SCB_MEMMAP_MAP;
0395   #endif
0396 
0397   /* Use normal memory map */
0398   EMC_CTRL &= ~0x2U;
0399 }
0400 
0401 static BSP_START_TEXT_SECTION void lpc24xx_init_memory_accelerator(void)
0402 {
0403   #ifdef ARM_MULTILIB_ARCH_V4
0404     /* Fully enable memory accelerator module functions (MAM) */
0405     MAMCR = 0;
0406     #if LPC24XX_CCLK <= 20000000U
0407       MAMTIM = 0x1;
0408     #elif LPC24XX_CCLK <= 40000000U
0409       MAMTIM = 0x2;
0410     #elif LPC24XX_CCLK <= 60000000U
0411       MAMTIM = 0x3;
0412     #else
0413       MAMTIM = 0x4;
0414     #endif
0415     MAMCR = 0x2;
0416 
0417     /* Enable fast IO for ports 0 and 1 */
0418     SCS |= 0x1;
0419   #else
0420     volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0421 
0422     #if LPC24XX_CCLK <= 20000000U
0423       scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x0);
0424     #elif LPC24XX_CCLK <= 40000000U
0425       scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x1);
0426     #elif LPC24XX_CCLK <= 60000000U
0427       scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x2);
0428     #elif LPC24XX_CCLK <= 80000000U
0429       scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x3);
0430     #elif LPC24XX_CCLK <= 100000000U
0431       scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x4);
0432     #else
0433       scb->flashcfg = LPC17XX_SCB_FLASHCFG_FLASHTIM(0x5);
0434     #endif
0435   #endif
0436 }
0437 
0438 static BSP_START_TEXT_SECTION void lpc24xx_stop_gpdma(void)
0439 {
0440   #ifdef LPC24XX_STOP_GPDMA
0441     #ifdef ARM_MULTILIB_ARCH_V4
0442       bool has_power = (PCONP & PCONP_GPDMA) != 0;
0443     #else
0444       volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0445       bool has_power = (scb->pconp & LPC17XX_SCB_PCONP_GPDMA) != 0;
0446     #endif
0447 
0448     if (has_power) {
0449       GPDMA_CONFIG = 0;
0450 
0451       #ifdef ARM_MULTILIB_ARCH_V4
0452         PCONP &= ~PCONP_GPDMA;
0453       #else
0454         scb->pconp &= ~LPC17XX_SCB_PCONP_GPDMA;
0455       #endif
0456     }
0457   #endif
0458 }
0459 
0460 static BSP_START_TEXT_SECTION void lpc24xx_stop_ethernet(void)
0461 {
0462   #ifdef LPC24XX_STOP_ETHERNET
0463     #ifdef ARM_MULTILIB_ARCH_V4
0464       bool has_power = (PCONP & PCONP_ETHERNET) != 0;
0465     #else
0466       volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0467       bool has_power = (scb->pconp & LPC17XX_SCB_PCONP_ENET) != 0;
0468     #endif
0469 
0470     if (has_power) {
0471       MAC_COMMAND = 0x38;
0472       MAC_MAC1 = 0xcf00;
0473       MAC_MAC1 = 0;
0474 
0475       #ifdef ARM_MULTILIB_ARCH_V4
0476         PCONP &= ~PCONP_ETHERNET;
0477       #else
0478         scb->pconp &= ~LPC17XX_SCB_PCONP_ENET;
0479       #endif
0480     }
0481   #endif
0482 }
0483 
0484 static BSP_START_TEXT_SECTION void lpc24xx_stop_usb(void)
0485 {
0486   #ifdef LPC24XX_STOP_USB
0487     #ifdef ARM_MULTILIB_ARCH_V4
0488       bool has_power = (PCONP & PCONP_USB) != 0;
0489     #else
0490       volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0491       bool has_power = (scb->pconp & LPC17XX_SCB_PCONP_USB) != 0;
0492     #endif
0493 
0494     if (has_power) {
0495       OTG_CLK_CTRL = 0;
0496 
0497       #ifdef ARM_MULTILIB_ARCH_V4
0498         PCONP &= ~PCONP_USB;
0499       #else
0500         scb->pconp &= ~LPC17XX_SCB_PCONP_USB;
0501         scb->usbclksel = 0;
0502       #endif
0503     }
0504   #endif
0505 }
0506 
0507 static BSP_START_TEXT_SECTION void lpc24xx_init_mpu(void)
0508 {
0509   #ifdef ARM_MULTILIB_ARCH_V7M
0510     volatile ARMV7M_MPU *mpu = _ARMV7M_MPU;
0511     size_t region_count = lpc24xx_start_config_mpu_region_count;
0512     size_t i = 0;
0513 
0514     for (i = 0; i < region_count; ++i) {
0515       mpu->rbar = lpc24xx_start_config_mpu_region [i].rbar;
0516       mpu->rasr = lpc24xx_start_config_mpu_region [i].rasr;
0517     }
0518 
0519     if (region_count > 0) {
0520       mpu->ctrl = ARMV7M_MPU_CTRL_ENABLE;
0521     }
0522   #endif
0523 }
0524 
0525 BSP_START_TEXT_SECTION void bsp_start_hook_0(void)
0526 {
0527   lpc24xx_init_main_oscillator();
0528   lpc24xx_init_pll();
0529   lpc24xx_init_pinsel();
0530   lpc24xx_init_emc_static();
0531 }
0532 
0533 BSP_START_TEXT_SECTION void bsp_start_hook_1(void)
0534 {
0535   lpc24xx_init_memory_map();
0536   lpc24xx_init_memory_accelerator();
0537   lpc24xx_init_emc_dynamic();
0538   lpc24xx_init_mpu();
0539   lpc24xx_stop_gpdma();
0540   lpc24xx_stop_ethernet();
0541   lpc24xx_stop_usb();
0542   bsp_start_copy_sections();
0543   bsp_start_clear_bss();
0544 
0545   /* At this point we can use objects outside the .start section */
0546 }