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

4.104.115
Last change on this file since c3dd440 was c3dd440, checked in by Sebastian Huber <sebastian.huber@…>, on May 20, 2010 at 2:33:16 PM

2010-05-20 Sebastian Huber <sebastian.huber@…>

  • shared/include/start.h: Define start section attributes.
  • Property mode set to 100644
File size: 10.1 KB
Line 
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
29#if defined(LPC24XX_EMC_MICRON) || defined(LPC24XX_EMC_NUMONYX)
30  #define LPC24XX_EMC_INIT
31#endif
32
33#ifdef LPC24XX_EMC_MICRON
34  static void BSP_START_SECTION lpc24xx_ram_test_32(void)
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
58  static void BSP_START_SECTION lpc24xx_cpu_delay(
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 */
76static void BSP_START_SECTION lpc24xx_init_emc_0(void)
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
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
126
127  #ifdef LPC24XX_EMC_NUMONYX
128    /* Static Memory 1 settings */
129    bsp_start_memcpy(
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 */
140static void BSP_START_SECTION lpc24xx_init_emc_1(void)
141{
142  #ifdef LPC24XX_EMC_INIT
143    /* Use normal memory map */
144    EMC_CTRL &= ~0x2U;
145  #endif
146
147  #ifdef LPC24XX_EMC_MICRON
148    /* Check if we need to initialize it */
149    if ((EMC_DYN_CFG0 & 0x00080000) == 0) {
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 */
156
157      /* FIXME */
158      EMC_DYN_APR = 2;
159
160      /* Data-in to active command period tWR + tRP */
161      EMC_DYN_DAL = 4;
162
163      /* Load mode register to active or refresh command period 2 tCK */
164      EMC_DYN_MRD = 1;
165
166      /* Active to precharge command period 44 ns */
167      EMC_DYN_RAS = 3;
168
169      /* Active to active command period 66 ns */
170      EMC_DYN_RC = 4;
171
172      /* Use command delayed strategy */
173      EMC_DYN_RD_CFG = 1;
174
175      /* Auto refresh period 66 ns */
176      EMC_DYN_RFC = 4;
177
178      /* Precharge command period 20 ns */
179      EMC_DYN_RP = 1;
180
181      /* Active bank a to active bank b command period 15 ns */
182      EMC_DYN_RRD = 1;
183
184      /* FIXME */
185      EMC_DYN_SREX = 5;
186
187      /* Write recovery time 15 ns */
188      EMC_DYN_WR = 1;
189
190      /* Exit self refresh to active command period 75 ns */
191      EMC_DYN_XSR = 5;
192
193      /* Dynamic Memory 0: Micron M T48LC 4M16 A2 P 75 IT */
194
195      /*
196       * Use SDRAM, 0 0 001 01 address mapping, disabled buffer, unprotected writes
197       */
198      EMC_DYN_CFG0 = 0x0280;
199
200      /* CAS and RAS latency */
201      EMC_DYN_RASCAS0 = 0x0202;
202
203      /* Wait 50 micro seconds */
204      lpc24xx_cpu_delay(3600);
205
206      /* Send command: NOP */
207      EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_NOP;
208
209      /* Wait 50 micro seconds */
210      lpc24xx_cpu_delay(3600);
211
212      /* Send command: PRECHARGE ALL */
213      EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_PALL;
214
215      /* Shortest possible refresh period */
216      EMC_DYN_RFSH = 0x01;
217
218      /* Wait at least 128 AHB clock cycles */
219      lpc24xx_cpu_delay(128);
220
221      /* Wait 1 micro second */
222      lpc24xx_cpu_delay(72);
223
224      /* Set refresh period */
225      EMC_DYN_RFSH = 0x46;
226
227      /* Send command: MODE */
228      EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_MODE;
229
230      /* Set mode register in SDRAM */
231      *((volatile uint32_t *) (0xa0000000 | (0x23 << (1 + 2 + 8))));
232
233      /* Send command: NORMAL */
234      EMC_DYN_CTRL = 0;
235
236      /* Enable buffer */
237      EMC_DYN_CFG0 |= 0x00080000;
238
239      /* Test RAM */
240      lpc24xx_ram_test_32();
241    }
242  #endif
243}
244
245static void BSP_START_SECTION lpc24xx_pll_config(
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 */
268static void BSP_START_SECTION lpc24xx_set_pll(
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);
279  bool pll_enabled = (pllstat & PLLSTAT_PLLE) != 0;
280
281  /* Disconnect PLL if necessary */
282  if ((pllstat & PLLSTAT_PLLC) != 0) {
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 */
313  while ((PLLSTAT & PLLSTAT_PLOCK) == 0) {
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
324static void BSP_START_SECTION lpc24xx_init_pll(void)
325{
326  /* Enable main oscillator */
327  if ((SCS & 0x40) == 0) {
328    SCS |= 0x20;
329    while ((SCS & 0x40) == 0) {
330      /* Wait */
331    }
332  }
333
334  /* Set PLL */
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
342}
343
344static void BSP_START_SECTION lpc24xx_clear_bss(void)
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
356void BSP_START_SECTION bsp_start_hook_0(void)
357{
358  /* Initialize PLL */
359  lpc24xx_init_pll();
360
361  /* Initialize EMC hook 0 */
362  lpc24xx_init_emc_0();
363}
364
365void BSP_START_SECTION bsp_start_hook_1(void)
366{
367  /* Re-map interrupt vectors to internal RAM */
368  MEMMAP = SET_MEMMAP_MAP(MEMMAP, 2);
369
370  /* Fully enable memory accelerator module functions (MAM) */
371  MAMCR = 0;
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;
382
383  /* Enable fast IO for ports 0 and 1 */
384  SCS |= 0x1;
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
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
424  /* Copy .text section */
425  bsp_start_memcpy(
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 */
432  bsp_start_memcpy(
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 */
439  bsp_start_memcpy(
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 */
446  bsp_start_memcpy(
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}
Note: See TracBrowser for help on using the repository browser.