Tom Rini | 83d290c | 2018-05-06 17:58:06 -0400 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) 2013 Atmel Corporation |
| 4 | * Bo Shen <voice.shen@atmel.com> |
| 5 | * |
Wenyou Yang | c2ad76c | 2016-02-01 18:12:16 +0800 | [diff] [blame] | 6 | * Copyright (C) 2015 Atmel Corporation |
| 7 | * Wenyou Yang <wenyou.yang@atmel.com> |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 8 | */ |
| 9 | |
| 10 | #include <common.h> |
| 11 | #include <asm/io.h> |
| 12 | #include <asm/arch/atmel_mpddrc.h> |
Eugen Hristev | a34ae7c | 2019-08-08 07:48:34 +0000 | [diff] [blame] | 13 | #include <asm/arch/at91_common.h> |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 14 | |
Wenyou Yang | 4245701 | 2016-02-01 18:12:17 +0800 | [diff] [blame] | 15 | #define SAMA5D3_MPDDRC_VERSION 0x140 |
| 16 | |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 17 | static inline void atmel_mpddr_op(const struct atmel_mpddr *mpddr, |
| 18 | int mode, |
| 19 | u32 ram_address) |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 20 | { |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 21 | writel(mode, &mpddr->mr); |
Eugen Hristev | a34ae7c | 2019-08-08 07:48:34 +0000 | [diff] [blame] | 22 | dmb(); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 23 | writel(0, ram_address); |
| 24 | } |
| 25 | |
Wenyou Yang | 4245701 | 2016-02-01 18:12:17 +0800 | [diff] [blame] | 26 | static int ddr2_decodtype_is_seq(const unsigned int base, u32 cr) |
Heiko Schocher | 7dd5891 | 2014-10-31 08:30:58 +0100 | [diff] [blame] | 27 | { |
Wenyou Yang | 4245701 | 2016-02-01 18:12:17 +0800 | [diff] [blame] | 28 | struct atmel_mpddr *mpddr = (struct atmel_mpddr *)base; |
| 29 | u16 version = readl(&mpddr->version) & 0xffff; |
| 30 | |
| 31 | if ((version >= SAMA5D3_MPDDRC_VERSION) && |
| 32 | (cr & ATMEL_MPDDRC_CR_DECOD_INTERLEAVED)) |
Heiko Schocher | 7dd5891 | 2014-10-31 08:30:58 +0100 | [diff] [blame] | 33 | return 0; |
Wenyou Yang | 4245701 | 2016-02-01 18:12:17 +0800 | [diff] [blame] | 34 | |
Heiko Schocher | 7dd5891 | 2014-10-31 08:30:58 +0100 | [diff] [blame] | 35 | return 1; |
| 36 | } |
| 37 | |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 38 | |
| 39 | int ddr2_init(const unsigned int base, |
| 40 | const unsigned int ram_address, |
Wenyou Yang | 7e8702a | 2016-02-01 18:12:15 +0800 | [diff] [blame] | 41 | const struct atmel_mpddrc_config *mpddr_value) |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 42 | { |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 43 | const struct atmel_mpddr *mpddr = (struct atmel_mpddr *)base; |
| 44 | |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 45 | u32 ba_off, cr; |
| 46 | |
| 47 | /* Compute bank offset according to NC in configuration register */ |
| 48 | ba_off = (mpddr_value->cr & ATMEL_MPDDRC_CR_NC_MASK) + 9; |
Wenyou Yang | 4245701 | 2016-02-01 18:12:17 +0800 | [diff] [blame] | 49 | if (ddr2_decodtype_is_seq(base, mpddr_value->cr)) |
Heiko Schocher | 341f548 | 2014-10-31 08:30:57 +0100 | [diff] [blame] | 50 | ba_off += ((mpddr_value->cr & ATMEL_MPDDRC_CR_NR_MASK) >> 2) + 11; |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 51 | |
| 52 | ba_off += (mpddr_value->md & ATMEL_MPDDRC_MD_DBW_MASK) ? 1 : 2; |
| 53 | |
| 54 | /* Program the memory device type into the memory device register */ |
| 55 | writel(mpddr_value->md, &mpddr->md); |
| 56 | |
| 57 | /* Program the configuration register */ |
| 58 | writel(mpddr_value->cr, &mpddr->cr); |
| 59 | |
| 60 | /* Program the timing register */ |
| 61 | writel(mpddr_value->tpr0, &mpddr->tpr0); |
| 62 | writel(mpddr_value->tpr1, &mpddr->tpr1); |
| 63 | writel(mpddr_value->tpr2, &mpddr->tpr2); |
| 64 | |
| 65 | /* Issue a NOP command */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 66 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 67 | |
| 68 | /* A 200 us is provided to precede any signal toggle */ |
| 69 | udelay(200); |
| 70 | |
| 71 | /* Issue a NOP command */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 72 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 73 | |
| 74 | /* Issue an all banks precharge command */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 75 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_PRCGALL_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 76 | |
| 77 | /* Issue an extended mode register set(EMRS2) to choose operation */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 78 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 79 | ram_address + (0x2 << ba_off)); |
| 80 | |
| 81 | /* Issue an extended mode register set(EMRS3) to set EMSR to 0 */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 82 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 83 | ram_address + (0x3 << ba_off)); |
| 84 | |
| 85 | /* |
| 86 | * Issue an extended mode register set(EMRS1) to enable DLL and |
| 87 | * program D.I.C (output driver impedance control) |
| 88 | */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 89 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 90 | ram_address + (0x1 << ba_off)); |
| 91 | |
| 92 | /* Enable DLL reset */ |
| 93 | cr = readl(&mpddr->cr); |
| 94 | writel(cr | ATMEL_MPDDRC_CR_DLL_RESET_ENABLED, &mpddr->cr); |
| 95 | |
| 96 | /* A mode register set(MRS) cycle is issued to reset DLL */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 97 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LMR_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 98 | |
| 99 | /* Issue an all banks precharge command */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 100 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_PRCGALL_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 101 | |
| 102 | /* Two auto-refresh (CBR) cycles are provided */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 103 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_RFSH_CMD, ram_address); |
| 104 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_RFSH_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 105 | |
| 106 | /* Disable DLL reset */ |
| 107 | cr = readl(&mpddr->cr); |
| 108 | writel(cr & (~ATMEL_MPDDRC_CR_DLL_RESET_ENABLED), &mpddr->cr); |
| 109 | |
| 110 | /* A mode register set (MRS) cycle is issued to disable DLL reset */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 111 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LMR_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 112 | |
| 113 | /* Set OCD calibration in default state */ |
| 114 | cr = readl(&mpddr->cr); |
| 115 | writel(cr | ATMEL_MPDDRC_CR_OCD_DEFAULT, &mpddr->cr); |
| 116 | |
| 117 | /* |
| 118 | * An extended mode register set (EMRS1) cycle is issued |
| 119 | * to OCD default value |
| 120 | */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 121 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 122 | ram_address + (0x1 << ba_off)); |
| 123 | |
| 124 | /* OCD calibration mode exit */ |
| 125 | cr = readl(&mpddr->cr); |
| 126 | writel(cr & (~ATMEL_MPDDRC_CR_OCD_DEFAULT), &mpddr->cr); |
| 127 | |
| 128 | /* |
| 129 | * An extended mode register set (EMRS1) cycle is issued |
| 130 | * to enable OCD exit |
| 131 | */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 132 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 133 | ram_address + (0x1 << ba_off)); |
| 134 | |
| 135 | /* A nornal mode command is provided */ |
Erik van Luijk | 0c01c3e | 2015-08-13 15:43:18 +0200 | [diff] [blame] | 136 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NORMAL_CMD, ram_address); |
Bo Shen | 9d9289c | 2013-11-15 11:12:37 +0800 | [diff] [blame] | 137 | |
| 138 | /* Perform a write access to any DDR2-SDRAM address */ |
| 139 | writel(0, ram_address); |
| 140 | |
| 141 | /* Write the refresh rate */ |
| 142 | writel(mpddr_value->rtr, &mpddr->rtr); |
| 143 | |
| 144 | return 0; |
| 145 | } |
Wenyou Yang | c2ad76c | 2016-02-01 18:12:16 +0800 | [diff] [blame] | 146 | |
| 147 | int ddr3_init(const unsigned int base, |
| 148 | const unsigned int ram_address, |
| 149 | const struct atmel_mpddrc_config *mpddr_value) |
| 150 | { |
| 151 | struct atmel_mpddr *mpddr = (struct atmel_mpddr *)base; |
| 152 | u32 ba_off; |
| 153 | |
| 154 | /* Compute bank offset according to NC in configuration register */ |
| 155 | ba_off = (mpddr_value->cr & ATMEL_MPDDRC_CR_NC_MASK) + 9; |
Wenyou Yang | 4245701 | 2016-02-01 18:12:17 +0800 | [diff] [blame] | 156 | if (ddr2_decodtype_is_seq(base, mpddr_value->cr)) |
Wenyou Yang | c2ad76c | 2016-02-01 18:12:16 +0800 | [diff] [blame] | 157 | ba_off += ((mpddr_value->cr & |
| 158 | ATMEL_MPDDRC_CR_NR_MASK) >> 2) + 11; |
| 159 | |
| 160 | ba_off += (mpddr_value->md & ATMEL_MPDDRC_MD_DBW_MASK) ? 1 : 2; |
| 161 | |
| 162 | /* Program the memory device type */ |
| 163 | writel(mpddr_value->md, &mpddr->md); |
| 164 | |
| 165 | /* |
| 166 | * Program features of the DDR3-SDRAM device and timing parameters |
| 167 | */ |
| 168 | writel(mpddr_value->cr, &mpddr->cr); |
| 169 | |
| 170 | writel(mpddr_value->tpr0, &mpddr->tpr0); |
| 171 | writel(mpddr_value->tpr1, &mpddr->tpr1); |
| 172 | writel(mpddr_value->tpr2, &mpddr->tpr2); |
| 173 | |
| 174 | /* A NOP command is issued to the DDR3-SRAM */ |
| 175 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address); |
| 176 | |
| 177 | /* A pause of at least 500us must be observed before a single toggle. */ |
| 178 | udelay(500); |
| 179 | |
| 180 | /* A NOP command is issued to the DDR3-SDRAM */ |
| 181 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address); |
| 182 | |
| 183 | /* |
| 184 | * An Extended Mode Register Set (EMRS2) cycle is issued to choose |
| 185 | * between commercial or high temperature operations. |
| 186 | */ |
| 187 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
| 188 | ram_address + (0x2 << ba_off)); |
| 189 | /* |
| 190 | * Step 7: An Extended Mode Register Set (EMRS3) cycle is issued to set |
| 191 | * the Extended Mode Register to 0. |
| 192 | */ |
| 193 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
| 194 | ram_address + (0x3 << ba_off)); |
| 195 | /* |
| 196 | * An Extended Mode Register Set (EMRS1) cycle is issued to disable and |
| 197 | * to program O.D.S. (Output Driver Strength). |
| 198 | */ |
| 199 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_EXT_LMR_CMD, |
| 200 | ram_address + (0x1 << ba_off)); |
| 201 | |
| 202 | /* |
| 203 | * Write a one to the DLL bit (enable DLL reset) in the MPDDRC |
| 204 | * Configuration Register. |
| 205 | */ |
| 206 | |
| 207 | /* A Mode Register Set (MRS) cycle is issued to reset DLL. */ |
| 208 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LMR_CMD, ram_address); |
| 209 | |
| 210 | udelay(50); |
| 211 | |
| 212 | /* |
| 213 | * A Calibration command (MRS) is issued to calibrate RTT and RON |
| 214 | * values for the Process Voltage Temperature (PVT). |
| 215 | */ |
| 216 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_DEEP_CMD, ram_address); |
| 217 | |
| 218 | /* A Normal Mode command is provided. */ |
| 219 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NORMAL_CMD, ram_address); |
| 220 | |
| 221 | /* Perform a write access to any DDR3-SDRAM address. */ |
| 222 | writel(0, ram_address); |
| 223 | |
| 224 | /* |
| 225 | * Write the refresh rate into the COUNT field in the MPDDRC |
| 226 | * Refresh Timer Register (MPDDRC_RTR): |
| 227 | */ |
| 228 | writel(mpddr_value->rtr, &mpddr->rtr); |
| 229 | |
| 230 | return 0; |
| 231 | } |
Eugen Hristev | a34ae7c | 2019-08-08 07:48:34 +0000 | [diff] [blame] | 232 | |
| 233 | int lpddr2_init(const unsigned int base, |
| 234 | const unsigned int ram_address, |
| 235 | const struct atmel_mpddrc_config *mpddr_value) |
| 236 | { |
| 237 | struct atmel_mpddr *mpddr = (struct atmel_mpddr *)base; |
| 238 | u32 reg; |
| 239 | |
| 240 | writel(mpddr_value->lpddr23_lpr, &mpddr->lpddr23_lpr); |
| 241 | |
| 242 | writel(mpddr_value->tim_cal, &mpddr->tim_cal); |
| 243 | |
| 244 | /* 1. Program the memory device type */ |
| 245 | writel(mpddr_value->md, &mpddr->md); |
| 246 | |
| 247 | /* |
| 248 | * 2. Program features of the LPDDR2-SDRAM device and timing parameters |
| 249 | */ |
| 250 | writel(mpddr_value->cr, &mpddr->cr); |
| 251 | |
| 252 | writel(mpddr_value->tpr0, &mpddr->tpr0); |
| 253 | writel(mpddr_value->tpr1, &mpddr->tpr1); |
| 254 | writel(mpddr_value->tpr2, &mpddr->tpr2); |
| 255 | |
| 256 | /* 3. A NOP command is issued to the LPDDR2-SDRAM */ |
| 257 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address); |
| 258 | |
| 259 | /* |
| 260 | * 3bis. Add memory barrier then Perform a write access to |
| 261 | * any low-power DDR2-SDRAM address to acknowledge the command. |
| 262 | */ |
| 263 | |
| 264 | dmb(); |
| 265 | writel(0, ram_address); |
| 266 | |
| 267 | /* 4. A pause of at least 100 ns must be observed before a single toggle */ |
| 268 | udelay(1); |
| 269 | |
| 270 | /* 5. A NOP command is issued to the LPDDR2-SDRAM */ |
| 271 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address); |
| 272 | |
| 273 | /* 6. A pause of at least 200 us must be observed before a Reset Command */ |
| 274 | udelay(200); |
| 275 | |
| 276 | /* 7. A Reset command is issued to the low-power DDR2-SDRAM. */ |
| 277 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 278 | ATMEL_MPDDRC_MR_MRS(63), ram_address); |
| 279 | |
| 280 | /* |
| 281 | * 8. A pause of at least tINIT5 must be observed before issuing |
| 282 | * any commands |
| 283 | */ |
| 284 | udelay(1); |
| 285 | |
| 286 | /* 9. A Calibration command is issued to the low-power DDR2-SDRAM. */ |
| 287 | reg = readl(&mpddr->cr); |
| 288 | reg &= ~ATMEL_MPDDRC_CR_ZQ_RESET; |
| 289 | reg |= ATMEL_MPDDRC_CR_ZQ_RESET; |
| 290 | writel(reg, &mpddr->cr); |
| 291 | |
| 292 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 293 | ATMEL_MPDDRC_MR_MRS(10), ram_address); |
| 294 | |
| 295 | /* |
| 296 | * 9bis: The ZQ Calibration command is now issued. |
| 297 | * Program the type of calibration in the MPDDRC_CR: set the |
| 298 | * ZQ field to the SHORT value. |
| 299 | */ |
| 300 | reg = readl(&mpddr->cr); |
| 301 | reg &= ~ATMEL_MPDDRC_CR_ZQ_RESET; |
| 302 | reg |= ATMEL_MPDDRC_CR_ZQ_SHORT; |
| 303 | writel(reg, &mpddr->cr); |
| 304 | |
| 305 | /* |
| 306 | * 10: A Mode Register Write command with 1 to the MRS field |
| 307 | * is issued to the low-power DDR2-SDRAM. |
| 308 | */ |
| 309 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 310 | ATMEL_MPDDRC_MR_MRS(1), ram_address); |
| 311 | |
| 312 | /* |
| 313 | * 11: A Mode Register Write command with 2 to the MRS field |
| 314 | * is issued to the low-power DDR2-SDRAM. |
| 315 | */ |
| 316 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 317 | ATMEL_MPDDRC_MR_MRS(2), ram_address); |
| 318 | |
| 319 | /* |
| 320 | * 12: A Mode Register Write command with 3 to the MRS field |
| 321 | * is issued to the low-power DDR2-SDRAM. |
| 322 | */ |
| 323 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 324 | ATMEL_MPDDRC_MR_MRS(3), ram_address); |
| 325 | |
| 326 | /* |
| 327 | * 13: A Mode Register Write command with 16 to the MRS field |
| 328 | * is issued to the low-power DDR2-SDRAM. |
| 329 | */ |
| 330 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 331 | ATMEL_MPDDRC_MR_MRS(16), ram_address); |
| 332 | |
| 333 | /* |
| 334 | * 14: In the DDR Configuration Register, open the input buffers. |
| 335 | */ |
| 336 | #ifdef CONFIG_ATMEL_SFR |
| 337 | configure_ddrcfg_input_buffers(true); |
| 338 | #endif |
| 339 | |
| 340 | /* 15. A NOP command is issued to the LPDDR2-SDRAM */ |
| 341 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NOP_CMD, ram_address); |
| 342 | |
| 343 | /* |
| 344 | * 16: A Mode Register Write command with 5 to the MRS field |
| 345 | * is issued to the low-power DDR2-SDRAM. |
| 346 | */ |
| 347 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 348 | ATMEL_MPDDRC_MR_MRS(5), ram_address); |
| 349 | |
| 350 | /* |
| 351 | * 17: A Mode Register Write command with 6 to the MRS field |
| 352 | * is issued to the low-power DDR2-SDRAM. |
| 353 | */ |
| 354 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 355 | ATMEL_MPDDRC_MR_MRS(6), ram_address); |
| 356 | |
| 357 | /* |
| 358 | * 18: A Mode Register Write command with 8 to the MRS field |
| 359 | * is issued to the low-power DDR2-SDRAM. |
| 360 | */ |
| 361 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 362 | ATMEL_MPDDRC_MR_MRS(8), ram_address); |
| 363 | |
| 364 | /* |
| 365 | * 19: A Mode Register Write command with 0 to the MRS field |
| 366 | * is issued to the low-power DDR2-SDRAM. |
| 367 | */ |
| 368 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_LPDDR2_CMD | |
| 369 | ATMEL_MPDDRC_MR_MRS(0), ram_address); |
| 370 | |
| 371 | /* |
| 372 | * 20: A Normal Mode command is provided. |
| 373 | */ |
| 374 | atmel_mpddr_op(mpddr, ATMEL_MPDDRC_MR_MODE_NORMAL_CMD, ram_address); |
| 375 | |
| 376 | /* 21: In the DDR Configuration Register, close the input buffers. */ |
| 377 | #ifdef CONFIG_ATMEL_SFR |
| 378 | configure_ddrcfg_input_buffers(false); |
| 379 | #endif |
| 380 | |
| 381 | /* |
| 382 | * 22: Write the refresh rate into the COUNT field in the MPDDRC |
| 383 | * Refresh Timer Register. |
| 384 | */ |
| 385 | writel(mpddr_value->rtr, &mpddr->rtr); |
| 386 | |
| 387 | /* 23. Configre CAL MR4 register */ |
| 388 | writel(mpddr_value->cal_mr4, &mpddr->cal_mr4); |
| 389 | |
| 390 | return 0; |
| 391 | } |