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