LPCOpen Platform for LPC18XX/43XX microcontrollers  18XX43XX
LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers
emc_18xx_43xx.c
Go to the documentation of this file.
1 /*
2  * @brief LPC18xx/43xx EMC driver
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products. This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights. NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers. This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /* DIV function with result rounded up */
39 #define EMC_DIV_ROUND_UP(x, y) ((x + y - 1) / y)
40 
41 /*****************************************************************************
42  * Public types/enumerations/variables
43  ****************************************************************************/
44 
45 /*****************************************************************************
46  * Private functions
47  ****************************************************************************/
48 
49 #ifndef EMC_SUPPORT_ONLY_PL172
50 /* Get ARM External Memory Controller Version */
51 STATIC uint32_t getARMPeripheralID(void)
52 {
53  uint32_t *RegAdd;
54  RegAdd = (uint32_t *) ((uint32_t) LPC_EMC + 0xFE0);
55  return (RegAdd[0] & 0xFF) | ((RegAdd[1] & 0xFF) << 8) |
56  ((RegAdd[2] & 0xFF) << 16) | (RegAdd[3] << 24);
57 }
58 
59 #endif
60 
61 /* Calculate Clock Count from Timing Unit(nanoseconds) */
62 STATIC uint32_t convertTimmingParam(uint32_t EMC_Clock, int32_t input_ns, uint32_t adjust)
63 {
64  uint32_t temp;
65  if (input_ns < 0) {
66  return (-input_ns) >> 8;
67  }
68  temp = EMC_Clock / 1000000; /* MHz calculation */
69  temp = temp * input_ns / 1000;
70 
71  /* round up */
72  temp += 0xFF;
73 
74  /* convert to simple integer number format */
75  temp >>= 8;
76  if (temp > adjust) {
77  return temp - adjust;
78  }
79 
80  return 0;
81 }
82 
83 /* Get Dynamic Memory Device Colum len */
84 STATIC uint32_t getColsLen(uint32_t DynConfig)
85 {
86  uint32_t DevBusWidth;
87  DevBusWidth = (DynConfig >> EMC_DYN_CONFIG_DEV_BUS_BIT) & 0x03;
88  if (DevBusWidth == 2) {
89  return 8;
90  }
91  else if (DevBusWidth == 1) {
92  return ((DynConfig >> (EMC_DYN_CONFIG_DEV_SIZE_BIT + 1)) & 0x03) + 8;
93  }
94  else if (DevBusWidth == 0) {
95  return ((DynConfig >> (EMC_DYN_CONFIG_DEV_SIZE_BIT + 1)) & 0x03) + 9;
96  }
97 
98  return 0;
99 }
100 
101 /* Initializes the Dynamic Controller according to the specified parameters
102  in the IP_EMC_DYN_CONFIG_T */
103 void initDynMem(LPC_EMC_T *pEMC, IP_EMC_DYN_CONFIG_T *Dynamic_Config, uint32_t EMC_Clock)
104 {
105  uint32_t ChipSelect, tmpclk;
106  volatile int i;
107 
108  for (ChipSelect = 0; ChipSelect < 4; ChipSelect++) {
109  LPC_EMC_T *EMC_Reg_add = (LPC_EMC_T *) ((uint32_t) pEMC + (ChipSelect << 5));
110 
111  EMC_Reg_add->DYNAMICRASCAS0 = Dynamic_Config->DevConfig[ChipSelect].RAS |
112  ((Dynamic_Config->DevConfig[ChipSelect].ModeRegister <<
113  (8 - EMC_DYN_MODE_CAS_BIT)) & 0xF00);
114  EMC_Reg_add->DYNAMICCONFIG0 = Dynamic_Config->DevConfig[ChipSelect].DynConfig;
115  }
116  pEMC->DYNAMICREADCONFIG = Dynamic_Config->ReadConfig; /* Read strategy */
117 
118  pEMC->DYNAMICRP = convertTimmingParam(EMC_Clock, Dynamic_Config->tRP, 1);
119  pEMC->DYNAMICRAS = convertTimmingParam(EMC_Clock, Dynamic_Config->tRAS, 1);
120  pEMC->DYNAMICSREX = convertTimmingParam(EMC_Clock, Dynamic_Config->tSREX, 1);
121  pEMC->DYNAMICAPR = convertTimmingParam(EMC_Clock, Dynamic_Config->tAPR, 1);
122  pEMC->DYNAMICDAL = convertTimmingParam(EMC_Clock, Dynamic_Config->tDAL, 0);
123  pEMC->DYNAMICWR = convertTimmingParam(EMC_Clock, Dynamic_Config->tWR, 1);
124  pEMC->DYNAMICRC = convertTimmingParam(EMC_Clock, Dynamic_Config->tRC, 1);
125  pEMC->DYNAMICRFC = convertTimmingParam(EMC_Clock, Dynamic_Config->tRFC, 1);
126  pEMC->DYNAMICXSR = convertTimmingParam(EMC_Clock, Dynamic_Config->tXSR, 1);
127  pEMC->DYNAMICRRD = convertTimmingParam(EMC_Clock, Dynamic_Config->tRRD, 1);
128  pEMC->DYNAMICMRD = convertTimmingParam(EMC_Clock, Dynamic_Config->tMRD, 1);
129 
130  for (i = 0; i < 1000; i++) { /* wait 100us */
131  }
132  pEMC->DYNAMICCONTROL = 0x00000183; /* Issue NOP command */
133 
134  for (i = 0; i < 1000; i++) {}
135  pEMC->DYNAMICCONTROL = 0x00000103; /* Issue PALL command */
136 
137  pEMC->DYNAMICREFRESH = 2; /* ( 2 * 16 ) -> 32 clock cycles */
138 
139  for (i = 0; i < 80; i++) {}
140 
141  tmpclk = EMC_DIV_ROUND_UP(convertTimmingParam(EMC_Clock, Dynamic_Config->RefreshPeriod, 0), 16);
142  pEMC->DYNAMICREFRESH = tmpclk;
143 
144  pEMC->DYNAMICCONTROL = 0x00000083; /* Issue MODE command */
145 
146  for (ChipSelect = 0; ChipSelect < 4; ChipSelect++) {
147  /*uint32_t burst_length;*/
148  uint32_t DynAddr;
149  uint8_t Col_len;
150 
151  Col_len = getColsLen(Dynamic_Config->DevConfig[ChipSelect].DynConfig);
152  /* get bus wide: if 32bit, len is 4 else if 16bit len is 2 */
153  /* burst_length = 1 << ((((Dynamic_Config->DynConfig[ChipSelect] >> 14) & 1)^1) +1); */
154  if (Dynamic_Config->DevConfig[ChipSelect].DynConfig & (1 << EMC_DYN_CONFIG_DATA_BUS_WIDTH_BIT)) {
155  /*32bit bus */
156  /*burst_length = 2;*/
157  Col_len += 2;
158  }
159  else {
160  /*burst_length = 4;*/
161  Col_len += 1;
162  }
163 
164  /* Check for RBC mode */
165  if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & EMC_DYN_CONFIG_LPSDRAM)) {
166  if (!(Dynamic_Config->DevConfig[ChipSelect].DynConfig & (0x7 << EMC_DYN_CONFIG_DEV_SIZE_BIT))) {
167  /* 2 banks => 1 bank select bit */
168  Col_len += 1;
169  }
170  else {
171  /* 4 banks => 2 bank select bits */
172  Col_len += 2;
173  }
174  }
175 
176  DynAddr = Dynamic_Config->DevConfig[ChipSelect].BaseAddr;
177 
178 
179  if (DynAddr != 0) {
180  uint32_t temp;
181  uint32_t ModeRegister;
182  ModeRegister = Dynamic_Config->DevConfig[ChipSelect].ModeRegister;
183  temp = *((volatile uint32_t *) (DynAddr | (ModeRegister << Col_len)));
184  temp = temp;
185  }
186  }
187  pEMC->DYNAMICCONTROL = 0x00000000; /* Issue NORMAL command */
188 
189  /* enable buffers */
190  pEMC->DYNAMICCONFIG0 |= 1 << 19;
191  pEMC->DYNAMICCONFIG1 |= 1 << 19;
192  pEMC->DYNAMICCONFIG2 |= 1 << 19;
193  pEMC->DYNAMICCONFIG3 |= 1 << 19;
194 }
195 
196 /* Initializes the Static Controller according to the specified parameters
197  * in the IP_EMC_STATIC_CONFIG_T
198  */
199 void initStaticMem(LPC_EMC_T *pEMC, IP_EMC_STATIC_CONFIG_T *Static_Config, uint32_t EMC_Clock)
200 {
201  LPC_EMC_T *EMC_Reg_add = (LPC_EMC_T *) ((uint32_t) pEMC + ((Static_Config->ChipSelect) << 5));
202  EMC_Reg_add->STATICCONFIG0 = Static_Config->Config;
203  EMC_Reg_add->STATICWAITWEN0 = convertTimmingParam(EMC_Clock, Static_Config->WaitWen, 1);
204  EMC_Reg_add->STATICWAITOEN0 = convertTimmingParam(EMC_Clock, Static_Config->WaitOen, 0);
205  EMC_Reg_add->STATICWAITRD0 = convertTimmingParam(EMC_Clock, Static_Config->WaitRd, 1);
206  EMC_Reg_add->STATICWAITPAG0 = convertTimmingParam(EMC_Clock, Static_Config->WaitPage, 1);
207  EMC_Reg_add->STATICWAITWR0 = convertTimmingParam(EMC_Clock, Static_Config->WaitWr, 2);
208  EMC_Reg_add->STATICWAITTURN0 = convertTimmingParam(EMC_Clock, Static_Config->WaitTurn, 1);
209 }
210 
211 /*****************************************************************************
212  * Public functions
213  ****************************************************************************/
214 
215 /* Dyanmic memory setup */
217 {
218  uint32_t ClkFreq;
219 
220  /* Note clocks must be enabled prior to this call */
221  ClkFreq = Chip_Clock_GetEMCRate();
222 
223  initDynMem(LPC_EMC, Dynamic_Config, ClkFreq);
224 }
225 
226 /* Enable Dynamic Memory Controller */
227 void Chip_EMC_Dynamic_Enable(uint8_t Enable)
228 {
229  if (Enable) {
230  LPC_EMC->DYNAMICCONTROL |= EMC_DYN_CONTROL_ENABLE;
231  }
232  else {
233  LPC_EMC->DYNAMICCONTROL &= ~EMC_DYN_CONTROL_ENABLE;
234  }
235 }
236 
237 /* Static memory setup */
239 {
240  uint32_t ClkFreq;
241 
242  /* Note clocks must be enabled prior to this call */
243  ClkFreq = Chip_Clock_GetEMCRate();
244 
245  initStaticMem(LPC_EMC, Static_Config, ClkFreq);
246 }
247 
248 /* Mirror CS1 to CS0 and DYCS0 */
249 void Chip_EMC_Mirror(uint8_t Enable)
250 {
251  if (Enable) {
252  LPC_EMC->CONTROL |= 1 << 1;
253  }
254  else {
255  LPC_EMC->CONTROL &= ~(1 << 1);
256  }
257 }
258 
259 /* Enable EMC */
260 void Chip_EMC_Enable(uint8_t Enable)
261 {
262  if (Enable) {
263  LPC_EMC->CONTROL |= 1;
264  }
265  else {
266  LPC_EMC->CONTROL &= ~(1);
267  }
268 }
269 
270 /* Set EMC LowPower Mode */
271 void Chip_EMC_LowPowerMode(uint8_t Enable)
272 {
273  if (Enable) {
274  LPC_EMC->CONTROL |= 1 << 2;
275  }
276  else {
277  LPC_EMC->CONTROL &= ~(1 << 2);
278  }
279 }
280 
281 /* Initialize EMC */
282 void Chip_EMC_Init(uint32_t Enable, uint32_t ClockRatio, uint32_t EndianMode)
283 {
284  LPC_EMC->CONFIG = (EndianMode ? 1 : 0) | ((ClockRatio ? 1 : 0) << 8);
285 
286  /* Enable EMC 001 Normal Memory Map, No low power mode */
287  LPC_EMC->CONTROL = (Enable ? 1 : 0);
288 }
289