1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2015, Atmel Corporation
\r
6 * All rights reserved.
\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
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\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
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
31 #include "peripherals/mpddrc.h"
\r
32 #include "peripherals/sfrbu.h"
\r
33 #include "peripherals/pmc.h"
\r
36 #include "compiler.h"
\r
39 static void _set_ddr_timings(struct _mpddrc_desc* desc)
\r
41 MPDDRC->MPDDRC_TPR0 = desc->tpr0;
\r
42 MPDDRC->MPDDRC_TPR1 = desc->tpr1;
\r
43 MPDDRC->MPDDRC_TPR2 = desc->tpr2;
\r
46 static uint32_t _compute_ba_offset(void)
\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
53 offset += (MPDDRC->MPDDRC_MD & MPDDRC_MD_DBW) ? 1 : 2;
\r
59 * \brief Send a NOP command
\r
61 static void _send_nop_cmd(void)
\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
68 static void _send_lmr_cmd(void)
\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
75 static void _send_ext_lmr_cmd(uint32_t opcode, uint32_t ba_offset)
\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
82 static void _send_normal_cmd(void)
\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
89 static void _send_precharge_cmd(void)
\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
96 static void _send_refresh_cmd(void)
\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
103 #ifdef CONFIG_HAVE_DDR3
\r
105 static void _send_calib_cmd(void)
\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
112 static void _configure_ddr3(struct _mpddrc_desc* desc)
\r
115 _set_ddr_timings(desc);
\r
116 uint32_t ba_offset = _compute_ba_offset();
\r
119 * Step 3: Issue a NOP command to the memory controller using
\r
120 * its mode register (MPDDRC_MR).
\r
125 * Step 4: A pause of at least 500us must be observed before a
\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
136 * Step 6: Issue Extended Mode Register Set 2 (EMRS2) cycle to
\r
137 * choose between commercial or high temperature
\r
140 _send_ext_lmr_cmd(0x2, ba_offset);
\r
143 * Step 7: Issue Extended Mode Register Set 3 (EMRS3) cycle to set
\r
144 * the Extended Mode Register to 0.
\r
146 _send_ext_lmr_cmd(0x3, ba_offset);
\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
152 _send_ext_lmr_cmd(0x1, ba_offset);
\r
155 * Step 9: Write a one to the DLL bit (enable DLL reset) in the MPDDRC
\r
156 * Configuration Register (MPDDRC_CR)
\r
158 /* Not done for DDR3 */
\r
161 * Step 10: Issue a Mode Register Set (MRS) cycle to reset DLL.
\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
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
177 _send_normal_cmd();
\r
179 * Step 13: Perform a write access to any DDR3-SDRAM address.
\r
181 *((uint32_t *)(DDR_CS_ADDR)) = 0;
\r
186 static void _configure_ddr2(struct _mpddrc_desc* desc)
\r
189 _set_ddr_timings(desc);
\r
190 uint32_t ba_offset = _compute_ba_offset();
\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
198 /* Step 4: Issue a NOP command. */
\r
202 /* Step 5: Issue all banks precharge command. */
\r
203 _send_precharge_cmd();
\r
206 /* Step 6: Issue an Extended Mode Register set (EMRS2) cycle
\r
207 * to chose between commercialor high temperature
\r
209 _send_ext_lmr_cmd(0x2, ba_offset);
\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
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
222 /* Step 9: Program DLL field into the Configuration Register. */
\r
223 MPDDRC->MPDDRC_CR |= MPDDRC_CR_DLL_RESET_ENABLED;
\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
232 /* Step 11: Issue all banks precharge command to the DDR2-SDRAM. */
\r
233 _send_precharge_cmd();
\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
241 _send_refresh_cmd();
\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
248 /* Step 14: Issue a Mode Register set (MRS) cycle to program
\r
249 * the parameters of the DDR2-SDRAM devices. */
\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
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
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
268 extern void mpddrc_configure(struct _mpddrc_desc* desc)
\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
275 /* controller and DDR clock */
\r
276 pmc_enable_peripheral(ID_MPDDRC);
\r
277 pmc_enable_system_clock(PMC_SYSTEM_CLOCK_DDR);
\r
279 /* Step1: Program memory device type */
\r
280 MPDDRC->MPDDRC_MD = desc->mode;
\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
291 MPDDRC->MPDDRC_RD_DATA_PATH = desc->data_path;
\r
293 /* Step 2: Program features of the DDR3-SDRAM device in the
\r
294 * configuration register and timing parameter registers (TPR0
\r
297 /* Configurations */
\r
298 MPDDRC->MPDDRC_CR = desc->control;
\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
308 MPDDRC_LPR_TIMEOUT_NONE |
\r
309 MPDDRC_LPR_APDE_DDR2_FAST_EXIT |
\r
310 MPDDRC_LPR_UPD_MR(0);
\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
318 MPDDRC_LPR_TIMEOUT_DELAY_128_CLK |
\r
319 MPDDRC_LPR_APDE_DDR2_SLOW_EXIT |
\r
320 MPDDRC_LPR_UPD_MR(0);
\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
331 _configure_ddr3(desc);
\r
334 case MPDDRC_TYPE_DDR2:
\r
335 _configure_ddr2(desc);
\r
338 trace_error("Device not handled\r\n");
\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
347 /* wait for end of calibration */
\r
350 /* Restore resolution or put the default one if not already set */
\r
351 timer_configure(resolution);
\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