]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/mpddrc.c
Add SAMA5D2 Xplained IAR demo.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / drivers / peripherals / mpddrc.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2015, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 #include "chip.h"\r
31 #include "peripherals/mpddrc.h"\r
32 #include "peripherals/sfrbu.h"\r
33 #include "peripherals/pmc.h"\r
34 #include "trace.h"\r
35 #include "timer.h"\r
36 #include "compiler.h"\r
37 #include <stdlib.h>\r
38 \r
39 static void _set_ddr_timings(struct _mpddrc_desc* desc)\r
40 {\r
41         MPDDRC->MPDDRC_TPR0 = desc->tpr0;\r
42         MPDDRC->MPDDRC_TPR1 = desc->tpr1;\r
43         MPDDRC->MPDDRC_TPR2 = desc->tpr2;\r
44 }\r
45 \r
46 static uint32_t _compute_ba_offset(void)\r
47 {\r
48         /* Compute BA[] offset according to CR configuration */\r
49         uint32_t offset = (MPDDRC->MPDDRC_CR & MPDDRC_CR_NC_Msk) + 9;\r
50         if (!(MPDDRC->MPDDRC_CR & MPDDRC_CR_DECOD_INTERLEAVED))\r
51                 offset += ((MPDDRC->MPDDRC_CR & MPDDRC_CR_NR_Msk) >> 2) + 11;\r
52 \r
53         offset += (MPDDRC->MPDDRC_MD & MPDDRC_MD_DBW) ? 1 : 2;\r
54 \r
55         return offset;\r
56 }\r
57 \r
58 /**\r
59  * \brief Send a NOP command\r
60  */\r
61 static void _send_nop_cmd(void)\r
62 {\r
63         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_NOP_CMD;\r
64         /* Perform a write to a DDR memory access to acknoledge the command */\r
65         *((uint32_t *)DDR_CS_ADDR) = 0;\r
66 }\r
67 \r
68 static void _send_lmr_cmd(void)\r
69 {\r
70         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_LMR_CMD;\r
71         /* Perform a write to a DDR memory access to acknoledge the command */\r
72         *((uint32_t *)DDR_CS_ADDR) = 0u;\r
73 }\r
74 \r
75 static void _send_ext_lmr_cmd(uint32_t opcode, uint32_t ba_offset)\r
76 {\r
77         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_EXT_LMR_CMD;\r
78         /* Perform a write to a DDR memory access to acknoledge the command */\r
79         *((uint32_t *)(DDR_CS_ADDR + (opcode << ba_offset))) = 0u;\r
80 }\r
81 \r
82 static void _send_normal_cmd(void)\r
83 {\r
84         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_NORMAL_CMD;\r
85         /* Perform a write to a DDR memory access to acknoledge the command */\r
86         *((uint32_t *)DDR_CS_ADDR) = 0;\r
87 }\r
88 \r
89 static void _send_precharge_cmd(void)\r
90 {\r
91         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_PRCGALL_CMD;\r
92         /* Perform a write to a DDR memory access to acknoledge the command */\r
93         *((uint32_t *)DDR_CS_ADDR) = 0;\r
94 }\r
95 \r
96 static void _send_refresh_cmd(void)\r
97 {\r
98         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_RFSH_CMD;\r
99         /* Perform a write to a DDR memory access to acknoledge the command */\r
100         *((uint32_t *)DDR_CS_ADDR) = 0;\r
101 }\r
102 \r
103 #ifdef CONFIG_HAVE_DDR3\r
104 \r
105 static void _send_calib_cmd(void)\r
106 {\r
107         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_DEEP_CALIB_MD;\r
108         /* Perform a write to a DDR memory access to acknoledge the command */\r
109         *((uint32_t *)DDR_CS_ADDR) = 0;\r
110 }\r
111 \r
112 static void _configure_ddr3(struct _mpddrc_desc* desc)\r
113 {\r
114         /* Timings */\r
115         _set_ddr_timings(desc);\r
116         uint32_t ba_offset = _compute_ba_offset();\r
117 \r
118         /*\r
119          * Step 3: Issue a NOP command to the memory controller using\r
120          * its mode register (MPDDRC_MR).\r
121          */\r
122         _send_nop_cmd();\r
123 \r
124         /*\r
125          * Step 4: A pause of at least 500us must be observed before a\r
126          * single toggle.\r
127          */\r
128         timer_sleep(50);\r
129         /*\r
130          * Step 5: Issue a NOP command to the memory controller using\r
131          * its mode register (MPDDRC_MR). CKE is now driven high.\r
132          */\r
133         _send_nop_cmd();\r
134         timer_sleep(1);\r
135         /*\r
136          * Step 6: Issue Extended Mode Register Set 2 (EMRS2) cycle to\r
137          * choose between commercial or high temperature\r
138          * operations.\r
139          */\r
140         _send_ext_lmr_cmd(0x2, ba_offset);\r
141         timer_sleep(1);\r
142         /*\r
143          * Step 7: Issue Extended Mode Register Set 3 (EMRS3) cycle to set\r
144          * the Extended Mode Register to 0.\r
145          */\r
146         _send_ext_lmr_cmd(0x3, ba_offset);\r
147         timer_sleep(1);\r
148         /*\r
149          * Step 8: Issue Extended Mode Register Set 1 (EMRS1) cycle to\r
150          * disable and to program O.D.S. (Output Driver Strength).\r
151          */\r
152         _send_ext_lmr_cmd(0x1, ba_offset);\r
153         timer_sleep(1);\r
154         /*\r
155          * Step 9: Write a one to the DLL bit (enable DLL reset) in the MPDDRC\r
156          * Configuration Register (MPDDRC_CR)\r
157          */\r
158         /* Not done for DDR3 */\r
159 \r
160         /*\r
161          * Step 10: Issue a Mode Register Set (MRS) cycle to reset DLL.\r
162          */\r
163         _send_lmr_cmd();\r
164         timer_sleep(5);\r
165         /*\r
166          * Step 11: Issue a Calibration command (MRS) cycle to calibrate RTT and\r
167          * RON values for the Process Voltage Temperature (PVT).\r
168          */\r
169         _send_calib_cmd();\r
170         timer_sleep(1);\r
171 \r
172         /*\r
173          * Step 12: A Normal Mode command is provided.\r
174          * Program the Normal mode in the MPDDRC_MR and perform a write access\r
175          * to any DDR3-SDRAM address to acknowledge this command.\r
176          */\r
177         _send_normal_cmd();\r
178         /*\r
179          * Step 13: Perform a write access to any DDR3-SDRAM address.\r
180          */\r
181         *((uint32_t *)(DDR_CS_ADDR)) = 0;\r
182 }\r
183 \r
184 #endif\r
185 \r
186 static void _configure_ddr2(struct _mpddrc_desc* desc)\r
187 {\r
188         /* Timings */\r
189         _set_ddr_timings(desc);\r
190         uint32_t ba_offset = _compute_ba_offset();\r
191 \r
192         /* Step 3: An NOP command is issued to the DDR2-SDRAM. Program\r
193          * the NOP command into the Mode Register and wait minimum 200\r
194          * us */\r
195         _send_nop_cmd();\r
196         timer_sleep(20);\r
197 \r
198         /* Step 4:  Issue a NOP command. */\r
199         _send_nop_cmd();\r
200         timer_sleep(1);\r
201 \r
202         /* Step 5: Issue all banks precharge command. */\r
203         _send_precharge_cmd();\r
204         timer_sleep(1);\r
205 \r
206         /* Step 6: Issue an Extended Mode Register set (EMRS2) cycle\r
207          * to chose between commercialor high  temperature\r
208          * operations. */\r
209         _send_ext_lmr_cmd(0x2, ba_offset);\r
210         timer_sleep(1);\r
211 \r
212         /* Step 7: Issue an Extended Mode Register set (EMRS3) cycle\r
213          * to set all registers to 0. */\r
214         _send_ext_lmr_cmd(0x3, ba_offset);\r
215         timer_sleep(1);\r
216 \r
217         /* Step 8:  Issue an Extended Mode Register set (EMRS1) cycle\r
218          * to enable DLL. */\r
219         _send_ext_lmr_cmd(0x1, ba_offset);\r
220         timer_sleep(1);\r
221 \r
222         /* Step 9:  Program DLL field into the Configuration Register. */\r
223         MPDDRC->MPDDRC_CR |= MPDDRC_CR_DLL_RESET_ENABLED;\r
224 \r
225         /* Step 10: A Mode Register set (MRS) cycle is issued to reset DLL. */\r
226         MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_LMR_CMD;\r
227         /* Perform a write to a DDR memory access to acknoledge the command */\r
228         *((uint32_t *)DDR_CS_ADDR) = 0;\r
229 \r
230         timer_sleep(1);\r
231 \r
232         /* Step 11: Issue all banks precharge command to the DDR2-SDRAM. */\r
233         _send_precharge_cmd();\r
234         timer_sleep(1);\r
235 \r
236         /* Step 12: Two auto-refresh (CBR) cycles are\r
237          * provided. Program the auto refresh command (CBR) into the\r
238          * Mode Register. */\r
239         _send_refresh_cmd();\r
240         timer_sleep(1);\r
241         _send_refresh_cmd();\r
242         timer_sleep(1);\r
243 \r
244         /* Step 13: Program DLL field into the Configuration Register\r
245          * to low(Disable DLL reset). */\r
246         MPDDRC->MPDDRC_CR &= ~MPDDRC_CR_DLL_RESET_ENABLED;\r
247 \r
248         /* Step 14: Issue a Mode Register set (MRS) cycle to program\r
249          * the parameters of the DDR2-SDRAM devices. */\r
250         _send_lmr_cmd();\r
251         timer_sleep(1);\r
252 \r
253         /* Step 15: Program OCD field into the Configuration Register\r
254          * to high (OCD calibration default). */\r
255         MPDDRC->MPDDRC_CR |= MPDDRC_CR_OCD_DDR2_DEFAULT_CALIB;\r
256 \r
257         /* Step 16: An Extended Mode Register set (EMRS1) cycle is\r
258          * issued to OCD default value. */\r
259         _send_ext_lmr_cmd(0x1, ba_offset);\r
260         timer_sleep(1);\r
261 \r
262         /* Step 19,20: A mode Normal command is provided. Program the\r
263          * Normal mode into Mode Register. */\r
264         _send_normal_cmd();\r
265         timer_sleep(1);\r
266 }\r
267 \r
268 extern void mpddrc_configure(struct _mpddrc_desc* desc)\r
269 {\r
270         /* Retrieve the current resolution to put it back later */\r
271         uint32_t resolution = timer_get_resolution();\r
272         /* Configure time to have 10 microseconds resolution */\r
273         timer_configure(10);\r
274 \r
275         /* controller and DDR clock */\r
276         pmc_enable_peripheral(ID_MPDDRC);\r
277         pmc_enable_system_clock(PMC_SYSTEM_CLOCK_DDR);\r
278 \r
279         /* Step1: Program memory device type */\r
280         MPDDRC->MPDDRC_MD = desc->mode;\r
281 \r
282         /* set driver impedance */\r
283         uint32_t value = MPDDRC->MPDDRC_IO_CALIBR;\r
284         value &= ~MPDDRC_IO_CALIBR_RDIV_Msk;\r
285         value &= ~MPDDRC_IO_CALIBR_TZQIO_Msk;\r
286         value &= ~MPDDRC_IO_CALIBR_CALCODEP_Msk;\r
287         value &= ~MPDDRC_IO_CALIBR_CALCODEN_Msk;\r
288         value |= desc->io_calibr;\r
289         MPDDRC->MPDDRC_IO_CALIBR = value;\r
290 \r
291         MPDDRC->MPDDRC_RD_DATA_PATH = desc->data_path;\r
292 \r
293         /* Step 2: Program features of the DDR3-SDRAM device in the\r
294          * configuration register and timing parameter registers (TPR0\r
295          * ans TPR1) */\r
296 \r
297         /* Configurations */\r
298         MPDDRC->MPDDRC_CR = desc->control;\r
299 \r
300 #ifdef CONFIG_HAVE_DDR3_SELFREFRESH\r
301         if (sfrbu_is_ddr_backup_enabled())\r
302                 /* DDR memory had been initilized and in backup mode */\r
303                 MPDDRC->MPDDRC_LPR =\r
304                         MPDDRC_LPR_LPCB_SELFREFRESH |\r
305                         MPDDRC_LPR_CLK_FR_ENABLED |\r
306                         MPDDRC_LPR_PASR(0) |\r
307                         MPDDRC_LPR_DS(2) |\r
308                         MPDDRC_LPR_TIMEOUT_NONE |\r
309                         MPDDRC_LPR_APDE_DDR2_FAST_EXIT |\r
310                         MPDDRC_LPR_UPD_MR(0);\r
311         else\r
312                 /* DDR memory is not in backup mode */\r
313                 MPDDRC->MPDDRC_LPR =\r
314                         MPDDRC_LPR_LPCB_SELFREFRESH |\r
315                         MPDDRC_LPR_CLK_FR_ENABLED |\r
316                         MPDDRC_LPR_PASR(0) |\r
317                         MPDDRC_LPR_DS(2) |\r
318                         MPDDRC_LPR_TIMEOUT_DELAY_128_CLK |\r
319                         MPDDRC_LPR_APDE_DDR2_SLOW_EXIT |\r
320                         MPDDRC_LPR_UPD_MR(0);\r
321 #endif\r
322 \r
323         switch(desc->type) {\r
324 #ifdef CONFIG_HAVE_DDR3\r
325         case MPDDRC_TYPE_DDR3:\r
326 #ifdef CONFIG_HAVE_DDR3_SELFREFRESH\r
327                 _set_ddr_timings(desc);\r
328                 /* Initialize DDR chip when needed */\r
329                 if (!sfrbu_is_ddr_backup_enabled())\r
330 #endif\r
331                 _configure_ddr3(desc);\r
332                 break;\r
333 #endif\r
334         case MPDDRC_TYPE_DDR2:\r
335                 _configure_ddr2(desc);\r
336                 break;\r
337         default:\r
338                 trace_error("Device not handled\r\n");\r
339                 abort();\r
340         }\r
341 \r
342         /* Last step: Write the refresh rate */\r
343         /* Refresh Timer is (64ms / (bank_size)) * master_clock */\r
344         uint32_t master_clock = pmc_get_master_clock()/1000000;\r
345         MPDDRC->MPDDRC_RTR = MPDDRC_RTR_COUNT(64000*master_clock/desc->bank);\r
346 \r
347         /* wait for end of calibration */\r
348         timer_sleep(1);\r
349 \r
350         /* Restore resolution or put the default one if not already set */\r
351         timer_configure(resolution);\r
352 \r
353 #ifdef CONFIG_HAVE_DDR3_SELFREFRESH\r
354         if (sfrbu_is_ddr_backup_enabled()) {\r
355                 MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_NORMAL_CMD;\r
356                 sfrbu_disable_ddr_backup();\r
357         }\r
358 #endif\r
359 }\r