Andre Przywara | ffec940 | 2022-12-31 18:38:21 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Allwinner D1/D1s/R528/T113-sx DRAM initialisation |
| 4 | * |
| 5 | * As usual there is no documentation for the memory controller or PHY IP |
| 6 | * used here. The baseline of this code was lifted from awboot[1], which |
| 7 | * seems to be based on some form of de-compilation of some original Allwinner |
| 8 | * code bits (with a GPL2 license tag from the very beginning). |
| 9 | * This version here is a reworked version, to match the U-Boot coding style |
| 10 | * and style of the other Allwinner DRAM drivers. |
| 11 | * |
| 12 | * [1] https://github.com/szemzoa/awboot.git |
| 13 | */ |
| 14 | |
| 15 | #include <asm/io.h> |
| 16 | #include <common.h> |
| 17 | #ifdef CONFIG_RAM |
| 18 | #include <dm.h> |
| 19 | #include <ram.h> |
| 20 | #endif |
| 21 | #include <linux/delay.h> |
| 22 | |
| 23 | #include "dram_sun20i_d1.h" |
| 24 | |
| 25 | #ifndef SUNXI_SID_BASE |
| 26 | #define SUNXI_SID_BASE 0x3006200 |
| 27 | #endif |
| 28 | |
| 29 | #ifndef SUNXI_CCM_BASE |
| 30 | #define SUNXI_CCM_BASE 0x2001000 |
| 31 | #endif |
| 32 | |
| 33 | static void sid_read_ldoB_cal(const dram_para_t *para) |
| 34 | { |
| 35 | uint32_t reg; |
| 36 | |
| 37 | reg = (readl(SUNXI_SID_BASE + 0x1c) & 0xff00) >> 8; |
| 38 | |
| 39 | if (reg == 0) |
| 40 | return; |
| 41 | |
| 42 | switch (para->dram_type) { |
| 43 | case SUNXI_DRAM_TYPE_DDR2: |
| 44 | break; |
| 45 | case SUNXI_DRAM_TYPE_DDR3: |
| 46 | if (reg > 0x20) |
| 47 | reg -= 0x16; |
| 48 | break; |
| 49 | default: |
| 50 | reg = 0; |
| 51 | break; |
| 52 | } |
| 53 | |
| 54 | clrsetbits_le32(0x3000150, 0xff00, reg << 8); |
| 55 | } |
| 56 | |
| 57 | static void dram_voltage_set(const dram_para_t *para) |
| 58 | { |
| 59 | int vol; |
| 60 | |
| 61 | switch (para->dram_type) { |
| 62 | case SUNXI_DRAM_TYPE_DDR2: |
| 63 | vol = 47; |
| 64 | break; |
| 65 | case SUNXI_DRAM_TYPE_DDR3: |
| 66 | vol = 25; |
| 67 | break; |
| 68 | default: |
| 69 | vol = 0; |
| 70 | break; |
| 71 | } |
| 72 | |
| 73 | clrsetbits_le32(0x3000150, 0x20ff00, vol << 8); |
| 74 | |
| 75 | udelay(1); |
| 76 | |
| 77 | sid_read_ldoB_cal(para); |
| 78 | } |
| 79 | |
| 80 | static void dram_enable_all_master(void) |
| 81 | { |
| 82 | writel(~0, 0x3102020); |
| 83 | writel(0xff, 0x3102024); |
| 84 | writel(0xffff, 0x3102028); |
| 85 | udelay(10); |
| 86 | } |
| 87 | |
| 88 | static void dram_disable_all_master(void) |
| 89 | { |
| 90 | writel(1, 0x3102020); |
| 91 | writel(0, 0x3102024); |
| 92 | writel(0, 0x3102028); |
| 93 | udelay(10); |
| 94 | } |
| 95 | |
| 96 | static void eye_delay_compensation(const dram_para_t *para) |
| 97 | { |
| 98 | uint32_t delay; |
| 99 | unsigned long ptr; |
| 100 | |
| 101 | // DATn0IOCR, n = 0...7 |
| 102 | delay = (para->dram_tpr11 & 0xf) << 9; |
| 103 | delay |= (para->dram_tpr12 & 0xf) << 1; |
| 104 | for (ptr = 0x3103310; ptr < 0x3103334; ptr += 4) |
| 105 | setbits_le32(ptr, delay); |
| 106 | |
| 107 | // DATn1IOCR, n = 0...7 |
| 108 | delay = (para->dram_tpr11 & 0xf0) << 5; |
| 109 | delay |= (para->dram_tpr12 & 0xf0) >> 3; |
| 110 | for (ptr = 0x3103390; ptr != 0x31033b4; ptr += 4) |
| 111 | setbits_le32(ptr, delay); |
| 112 | |
| 113 | // PGCR0: assert AC loopback FIFO reset |
| 114 | clrbits_le32(0x3103100, 0x04000000); |
| 115 | |
| 116 | // ?? |
| 117 | |
| 118 | delay = (para->dram_tpr11 & 0xf0000) >> 7; |
| 119 | delay |= (para->dram_tpr12 & 0xf0000) >> 15; |
| 120 | setbits_le32(0x3103334, delay); |
| 121 | setbits_le32(0x3103338, delay); |
| 122 | |
| 123 | delay = (para->dram_tpr11 & 0xf00000) >> 11; |
| 124 | delay |= (para->dram_tpr12 & 0xf00000) >> 19; |
| 125 | setbits_le32(0x31033b4, delay); |
| 126 | setbits_le32(0x31033b8, delay); |
| 127 | |
| 128 | setbits_le32(0x310333c, (para->dram_tpr11 & 0xf0000) << 9); |
| 129 | setbits_le32(0x31033bc, (para->dram_tpr11 & 0xf00000) << 5); |
| 130 | |
| 131 | // PGCR0: release AC loopback FIFO reset |
| 132 | setbits_le32(0x3103100, BIT(26)); |
| 133 | |
| 134 | udelay(1); |
| 135 | |
| 136 | delay = (para->dram_tpr10 & 0xf0) << 4; |
| 137 | for (ptr = 0x3103240; ptr != 0x310327c; ptr += 4) |
| 138 | setbits_le32(ptr, delay); |
| 139 | for (ptr = 0x3103228; ptr != 0x3103240; ptr += 4) |
| 140 | setbits_le32(ptr, delay); |
| 141 | |
| 142 | setbits_le32(0x3103218, (para->dram_tpr10 & 0x0f) << 8); |
| 143 | setbits_le32(0x310321c, (para->dram_tpr10 & 0x0f) << 8); |
| 144 | |
| 145 | setbits_le32(0x3103280, (para->dram_tpr10 & 0xf00) >> 4); |
| 146 | } |
| 147 | |
| 148 | /* |
| 149 | * Main purpose of the auto_set_timing routine seems to be to calculate all |
| 150 | * timing settings for the specific type of sdram used. Read together with |
| 151 | * an sdram datasheet for context on the various variables. |
| 152 | */ |
| 153 | static void mctl_set_timing_params(const dram_para_t *para, |
| 154 | const dram_config_t *config) |
| 155 | { |
| 156 | /* DRAM_TPR0 */ |
| 157 | u8 tccd = 2; |
| 158 | u8 tfaw; |
| 159 | u8 trrd; |
| 160 | u8 trcd; |
| 161 | u8 trc; |
| 162 | |
| 163 | /* DRAM_TPR1 */ |
| 164 | u8 txp; |
| 165 | u8 twtr; |
| 166 | u8 trtp = 4; |
| 167 | u8 twr; |
| 168 | u8 trp; |
| 169 | u8 tras; |
| 170 | |
| 171 | /* DRAM_TPR2 */ |
| 172 | u16 trefi; |
| 173 | u16 trfc; |
| 174 | |
| 175 | u8 tcksrx; |
| 176 | u8 tckesr; |
| 177 | u8 trd2wr; |
| 178 | u8 twr2rd; |
| 179 | u8 trasmax; |
| 180 | u8 twtp; |
| 181 | u8 tcke; |
| 182 | u8 tmod; |
| 183 | u8 tmrd; |
| 184 | u8 tmrw; |
| 185 | |
| 186 | u8 tcl; |
| 187 | u8 tcwl; |
| 188 | u8 t_rdata_en; |
| 189 | u8 wr_latency; |
| 190 | |
| 191 | u32 mr0; |
| 192 | u32 mr1; |
| 193 | u32 mr2; |
| 194 | u32 mr3; |
| 195 | |
| 196 | u32 tdinit0; |
| 197 | u32 tdinit1; |
| 198 | u32 tdinit2; |
| 199 | u32 tdinit3; |
| 200 | |
| 201 | switch (para->dram_type) { |
| 202 | case SUNXI_DRAM_TYPE_DDR2: |
| 203 | /* DRAM_TPR0 */ |
| 204 | tfaw = ns_to_t(50); |
| 205 | trrd = ns_to_t(10); |
| 206 | trcd = ns_to_t(20); |
| 207 | trc = ns_to_t(65); |
| 208 | |
| 209 | /* DRAM_TPR1 */ |
| 210 | txp = 2; |
| 211 | twtr = ns_to_t(8); |
| 212 | twr = ns_to_t(15); |
| 213 | trp = ns_to_t(15); |
| 214 | tras = ns_to_t(45); |
| 215 | |
| 216 | /* DRAM_TRP2 */ |
| 217 | trfc = ns_to_t(328); |
| 218 | trefi = ns_to_t(7800) / 32; |
| 219 | |
| 220 | trasmax = CONFIG_DRAM_CLK / 30; |
| 221 | if (CONFIG_DRAM_CLK < 409) { |
| 222 | t_rdata_en = 1; |
| 223 | tcl = 3; |
| 224 | mr0 = 0x06a3; |
| 225 | } else { |
| 226 | t_rdata_en = 2; |
| 227 | tcl = 4; |
| 228 | mr0 = 0x0e73; |
| 229 | } |
| 230 | tmrd = 2; |
| 231 | twtp = twr + 5; |
| 232 | tcksrx = 5; |
| 233 | tckesr = 4; |
| 234 | trd2wr = 4; |
| 235 | tcke = 3; |
| 236 | tmod = 12; |
| 237 | wr_latency = 1; |
| 238 | tmrw = 0; |
| 239 | twr2rd = twtr + 5; |
| 240 | tcwl = 0; |
| 241 | |
| 242 | mr1 = para->dram_mr1; |
| 243 | mr2 = 0; |
| 244 | mr3 = 0; |
| 245 | |
| 246 | tdinit0 = 200 * CONFIG_DRAM_CLK + 1; |
| 247 | tdinit1 = 100 * CONFIG_DRAM_CLK / 1000 + 1; |
| 248 | tdinit2 = 200 * CONFIG_DRAM_CLK + 1; |
| 249 | tdinit3 = 1 * CONFIG_DRAM_CLK + 1; |
| 250 | |
| 251 | break; |
| 252 | case SUNXI_DRAM_TYPE_DDR3: |
| 253 | trfc = ns_to_t(350); |
| 254 | trefi = ns_to_t(7800) / 32 + 1; // XXX |
| 255 | |
| 256 | twtr = ns_to_t(8) + 2; // + 2 ? XXX |
| 257 | /* Only used by trd2wr calculation, which gets discard below */ |
| 258 | // twr = max(ns_to_t(15), 2); |
| 259 | trrd = max(ns_to_t(10), 2); |
| 260 | txp = max(ns_to_t(10), 2); |
| 261 | |
| 262 | if (CONFIG_DRAM_CLK <= 800) { |
| 263 | tfaw = ns_to_t(50); |
| 264 | trcd = ns_to_t(15); |
| 265 | trp = ns_to_t(15); |
| 266 | trc = ns_to_t(53); |
| 267 | tras = ns_to_t(38); |
| 268 | |
| 269 | mr0 = 0x1c70; |
| 270 | mr2 = 0x18; |
| 271 | tcl = 6; |
| 272 | wr_latency = 2; |
| 273 | tcwl = 4; |
| 274 | t_rdata_en = 4; |
| 275 | } else { |
| 276 | tfaw = ns_to_t(35); |
| 277 | trcd = ns_to_t(14); |
| 278 | trp = ns_to_t(14); |
| 279 | trc = ns_to_t(48); |
| 280 | tras = ns_to_t(34); |
| 281 | |
| 282 | mr0 = 0x1e14; |
| 283 | mr2 = 0x20; |
| 284 | tcl = 7; |
| 285 | wr_latency = 3; |
| 286 | tcwl = 5; |
| 287 | t_rdata_en = 5; |
| 288 | } |
| 289 | |
| 290 | trasmax = CONFIG_DRAM_CLK / 30; |
| 291 | twtp = tcwl + 2 + twtr; // WL+BL/2+tWTR |
| 292 | /* Gets overwritten below */ |
| 293 | // trd2wr = tcwl + 2 + twr; // WL+BL/2+tWR |
| 294 | twr2rd = tcwl + twtr; // WL+tWTR |
| 295 | |
| 296 | tdinit0 = 500 * CONFIG_DRAM_CLK + 1; // 500 us |
| 297 | tdinit1 = 360 * CONFIG_DRAM_CLK / 1000 + 1; // 360 ns |
| 298 | tdinit2 = 200 * CONFIG_DRAM_CLK + 1; // 200 us |
| 299 | tdinit3 = 1 * CONFIG_DRAM_CLK + 1; // 1 us |
| 300 | |
| 301 | mr1 = para->dram_mr1; |
| 302 | mr3 = 0; |
| 303 | tcke = 3; |
| 304 | tcksrx = 5; |
| 305 | tckesr = 4; |
| 306 | if (((config->dram_tpr13 & 0xc) == 0x04) || CONFIG_DRAM_CLK < 912) |
| 307 | trd2wr = 5; |
| 308 | else |
| 309 | trd2wr = 6; |
| 310 | |
| 311 | tmod = 12; |
| 312 | tmrd = 4; |
| 313 | tmrw = 0; |
| 314 | |
| 315 | break; |
| 316 | case SUNXI_DRAM_TYPE_LPDDR2: |
| 317 | tfaw = max(ns_to_t(50), 4); |
| 318 | trrd = max(ns_to_t(10), 1); |
| 319 | trcd = max(ns_to_t(24), 2); |
| 320 | trc = ns_to_t(70); |
| 321 | txp = ns_to_t(8); |
| 322 | if (txp < 2) { |
| 323 | txp++; |
| 324 | twtr = 2; |
| 325 | } else { |
| 326 | twtr = txp; |
| 327 | } |
| 328 | twr = max(ns_to_t(15), 2); |
| 329 | trp = ns_to_t(17); |
| 330 | tras = ns_to_t(42); |
| 331 | trefi = ns_to_t(3900) / 32; |
| 332 | trfc = ns_to_t(210); |
| 333 | |
| 334 | trasmax = CONFIG_DRAM_CLK / 60; |
| 335 | mr3 = para->dram_mr3; |
| 336 | twtp = twr + 5; |
| 337 | mr2 = 6; |
| 338 | mr1 = 5; |
| 339 | tcksrx = 5; |
| 340 | tckesr = 5; |
| 341 | trd2wr = 10; |
| 342 | tcke = 2; |
| 343 | tmod = 5; |
| 344 | tmrd = 5; |
| 345 | tmrw = 3; |
| 346 | tcl = 4; |
| 347 | wr_latency = 1; |
| 348 | t_rdata_en = 1; |
| 349 | |
| 350 | tdinit0 = 200 * CONFIG_DRAM_CLK + 1; |
| 351 | tdinit1 = 100 * CONFIG_DRAM_CLK / 1000 + 1; |
| 352 | tdinit2 = 11 * CONFIG_DRAM_CLK + 1; |
| 353 | tdinit3 = 1 * CONFIG_DRAM_CLK + 1; |
| 354 | twr2rd = twtr + 5; |
| 355 | tcwl = 2; |
| 356 | mr1 = 195; |
| 357 | mr0 = 0; |
| 358 | |
| 359 | break; |
| 360 | case SUNXI_DRAM_TYPE_LPDDR3: |
| 361 | tfaw = max(ns_to_t(50), 4); |
| 362 | trrd = max(ns_to_t(10), 1); |
| 363 | trcd = max(ns_to_t(24), 2); |
| 364 | trc = ns_to_t(70); |
| 365 | twtr = max(ns_to_t(8), 2); |
| 366 | twr = max(ns_to_t(15), 2); |
| 367 | trp = ns_to_t(17); |
| 368 | tras = ns_to_t(42); |
| 369 | trefi = ns_to_t(3900) / 32; |
| 370 | trfc = ns_to_t(210); |
| 371 | txp = twtr; |
| 372 | |
| 373 | trasmax = CONFIG_DRAM_CLK / 60; |
| 374 | if (CONFIG_DRAM_CLK < 800) { |
| 375 | tcwl = 4; |
| 376 | wr_latency = 3; |
| 377 | t_rdata_en = 6; |
| 378 | mr2 = 12; |
| 379 | } else { |
| 380 | tcwl = 3; |
| 381 | tcke = 6; |
| 382 | wr_latency = 2; |
| 383 | t_rdata_en = 5; |
| 384 | mr2 = 10; |
| 385 | } |
| 386 | twtp = tcwl + 5; |
| 387 | tcl = 7; |
| 388 | mr3 = para->dram_mr3; |
| 389 | tcksrx = 5; |
| 390 | tckesr = 5; |
| 391 | trd2wr = 13; |
| 392 | tcke = 3; |
| 393 | tmod = 12; |
| 394 | tdinit0 = 400 * CONFIG_DRAM_CLK + 1; |
| 395 | tdinit1 = 500 * CONFIG_DRAM_CLK / 1000 + 1; |
| 396 | tdinit2 = 11 * CONFIG_DRAM_CLK + 1; |
| 397 | tdinit3 = 1 * CONFIG_DRAM_CLK + 1; |
| 398 | tmrd = 5; |
| 399 | tmrw = 5; |
| 400 | twr2rd = tcwl + twtr + 5; |
| 401 | mr1 = 195; |
| 402 | mr0 = 0; |
| 403 | |
| 404 | break; |
| 405 | default: |
| 406 | trfc = 128; |
| 407 | trp = 6; |
| 408 | trefi = 98; |
| 409 | txp = 10; |
| 410 | twr = 8; |
| 411 | twtr = 3; |
| 412 | tras = 14; |
| 413 | tfaw = 16; |
| 414 | trc = 20; |
| 415 | trcd = 6; |
| 416 | trrd = 3; |
| 417 | |
| 418 | twr2rd = 8; |
| 419 | tcksrx = 4; |
| 420 | tckesr = 3; |
| 421 | trd2wr = 4; |
| 422 | trasmax = 27; |
| 423 | twtp = 12; |
| 424 | tcke = 2; |
| 425 | tmod = 6; |
| 426 | tmrd = 2; |
| 427 | tmrw = 0; |
| 428 | tcwl = 3; |
| 429 | tcl = 3; |
| 430 | wr_latency = 1; |
| 431 | t_rdata_en = 1; |
| 432 | mr3 = 0; |
| 433 | mr2 = 0; |
| 434 | mr1 = 0; |
| 435 | mr0 = 0; |
| 436 | tdinit3 = 0; |
| 437 | tdinit2 = 0; |
| 438 | tdinit1 = 0; |
| 439 | tdinit0 = 0; |
| 440 | |
| 441 | break; |
| 442 | } |
| 443 | |
| 444 | /* Set mode registers */ |
| 445 | writel(mr0, 0x3103030); |
| 446 | writel(mr1, 0x3103034); |
| 447 | writel(mr2, 0x3103038); |
| 448 | writel(mr3, 0x310303c); |
| 449 | /* TODO: dram_odt_en is either 0x0 or 0x1, so right shift looks weird */ |
| 450 | writel((para->dram_odt_en >> 4) & 0x3, 0x310302c); |
| 451 | |
| 452 | /* Set dram timing DRAMTMG0 - DRAMTMG5 */ |
| 453 | writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | (tras << 0), |
| 454 | 0x3103058); |
| 455 | writel((txp << 16) | (trtp << 8) | (trc << 0), |
| 456 | 0x310305c); |
| 457 | writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | (twr2rd << 0), |
| 458 | 0x3103060); |
| 459 | writel((tmrw << 16) | (tmrd << 12) | (tmod << 0), |
| 460 | 0x3103064); |
| 461 | writel((trcd << 24) | (tccd << 16) | (trrd << 8) | (trp << 0), |
| 462 | 0x3103068); |
| 463 | writel((tcksrx << 24) | (tcksrx << 16) | (tckesr << 8) | (tcke << 0), |
| 464 | 0x310306c); |
| 465 | |
| 466 | /* Set dual rank timing */ |
| 467 | clrsetbits_le32(0x3103078, 0xf000ffff, |
| 468 | (CONFIG_DRAM_CLK < 800) ? 0xf0006610 : 0xf0007610); |
| 469 | |
| 470 | /* Set phy interface time PITMG0, PTR3, PTR4 */ |
| 471 | writel((0x2 << 24) | (t_rdata_en << 16) | BIT(8) | (wr_latency << 0), |
| 472 | 0x3103080); |
| 473 | writel(((tdinit0 << 0) | (tdinit1 << 20)), 0x3103050); |
| 474 | writel(((tdinit2 << 0) | (tdinit3 << 20)), 0x3103054); |
| 475 | |
| 476 | /* Set refresh timing and mode */ |
| 477 | writel((trefi << 16) | (trfc << 0), 0x3103090); |
| 478 | writel((trefi << 15) & 0x0fff0000, 0x3103094); |
| 479 | } |
| 480 | |
| 481 | // Purpose of this routine seems to be to initialize the PLL driving |
| 482 | // the MBUS and sdram. |
| 483 | // |
| 484 | static int ccu_set_pll_ddr_clk(int index, const dram_para_t *para, |
| 485 | const dram_config_t *config) |
| 486 | { |
| 487 | unsigned int val, clk, n; |
| 488 | |
| 489 | if (config->dram_tpr13 & BIT(6)) |
| 490 | clk = para->dram_tpr9; |
| 491 | else |
| 492 | clk = para->dram_clk; |
| 493 | |
| 494 | // set VCO clock divider |
| 495 | n = (clk * 2) / 24; |
| 496 | |
| 497 | val = readl(SUNXI_CCM_BASE + 0x10); |
| 498 | val &= ~0x0007ff03; // clear dividers |
| 499 | val |= (n - 1) << 8; // set PLL division |
| 500 | val |= BIT(31) | BIT(30); // enable PLL and LDO |
| 501 | writel(val | BIT(29), SUNXI_CCM_BASE + 0x10); |
| 502 | |
| 503 | // wait for PLL to lock |
| 504 | while ((readl(SUNXI_CCM_BASE + 0x10) & BIT(28)) == 0) |
| 505 | ; |
| 506 | |
| 507 | udelay(20); |
| 508 | |
| 509 | // enable PLL output |
| 510 | setbits_le32(SUNXI_CCM_BASE + 0x0, BIT(27)); |
| 511 | |
| 512 | // turn clock gate on |
| 513 | val = readl(SUNXI_CCM_BASE + 0x800); |
| 514 | val &= ~0x03000303; // select DDR clk source, n=1, m=1 |
| 515 | val |= BIT(31); // turn clock on |
| 516 | writel(val, SUNXI_CCM_BASE + 0x800); |
| 517 | |
| 518 | return n * 24; |
| 519 | } |
| 520 | |
| 521 | /* Set up the PLL and clock gates for the DRAM controller and MBUS clocks. */ |
| 522 | static void mctl_sys_init(const dram_para_t *para, const dram_config_t *config) |
| 523 | { |
| 524 | // assert MBUS reset |
| 525 | clrbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30)); |
| 526 | |
| 527 | // turn off sdram clock gate, assert sdram reset |
| 528 | clrbits_le32(SUNXI_CCM_BASE + 0x80c, 0x10001); |
| 529 | clrsetbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(30), BIT(27)); |
| 530 | udelay(10); |
| 531 | |
| 532 | // set ddr pll clock |
| 533 | ccu_set_pll_ddr_clk(0, para, config); |
| 534 | udelay(100); |
| 535 | dram_disable_all_master(); |
| 536 | |
| 537 | // release sdram reset |
| 538 | setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(16)); |
| 539 | |
| 540 | // release MBUS reset |
| 541 | setbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30)); |
| 542 | setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(30)); |
| 543 | |
| 544 | udelay(5); |
| 545 | |
| 546 | // turn on sdram clock gate |
| 547 | setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(0)); |
| 548 | |
| 549 | // turn dram clock gate on, trigger sdr clock update |
| 550 | setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(27)); |
| 551 | udelay(5); |
| 552 | |
| 553 | // mCTL clock enable |
| 554 | writel(0x8000, 0x310300c); |
| 555 | udelay(10); |
| 556 | } |
| 557 | |
| 558 | // The main purpose of this routine seems to be to copy an address configuration |
| 559 | // from the dram_para1 and dram_para2 fields to the PHY configuration registers |
| 560 | // (0x3102000, 0x3102004). |
| 561 | // |
| 562 | static void mctl_com_init(const dram_para_t *para, const dram_config_t *config) |
| 563 | { |
| 564 | uint32_t val, width; |
| 565 | unsigned long ptr; |
| 566 | int i; |
| 567 | |
| 568 | // purpose ?? |
| 569 | clrsetbits_le32(0x3102008, 0x3f00, 0x2000); |
| 570 | |
| 571 | // set SDRAM type and word width |
| 572 | val = readl(0x3102000) & ~0x00fff000; |
| 573 | val |= (para->dram_type & 0x7) << 16; // DRAM type |
| 574 | val |= (~config->dram_para2 & 0x1) << 12; // DQ width |
| 575 | val |= BIT(22); // ?? |
| 576 | if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 || |
| 577 | para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) { |
| 578 | val |= BIT(19); // type 6 and 7 must use 1T |
| 579 | } else { |
| 580 | if (config->dram_tpr13 & BIT(5)) |
| 581 | val |= BIT(19); |
| 582 | } |
| 583 | writel(val, 0x3102000); |
| 584 | |
| 585 | // init rank / bank / row for single/dual or two different ranks |
| 586 | if ((config->dram_para2 & BIT(8)) && |
| 587 | ((config->dram_para2 & 0xf000) != 0x1000)) |
| 588 | width = 32; |
| 589 | else |
| 590 | width = 16; |
| 591 | |
| 592 | ptr = 0x3102000; |
| 593 | for (i = 0; i < width; i += 16) { |
| 594 | val = readl(ptr) & 0xfffff000; |
| 595 | |
| 596 | val |= (config->dram_para2 >> 12) & 0x3; // rank |
| 597 | val |= ((config->dram_para1 >> (i + 12)) << 2) & 0x4; // bank - 2 |
| 598 | val |= (((config->dram_para1 >> (i + 4)) - 1) << 4) & 0xff; // row - 1 |
| 599 | |
| 600 | // convert from page size to column addr width - 3 |
| 601 | switch ((config->dram_para1 >> i) & 0xf) { |
| 602 | case 8: val |= 0xa00; break; |
| 603 | case 4: val |= 0x900; break; |
| 604 | case 2: val |= 0x800; break; |
| 605 | case 1: val |= 0x700; break; |
| 606 | default: val |= 0x600; break; |
| 607 | } |
| 608 | writel(val, ptr); |
| 609 | ptr += 4; |
| 610 | } |
| 611 | |
| 612 | // set ODTMAP based on number of ranks in use |
| 613 | val = (readl(0x3102000) & 0x1) ? 0x303 : 0x201; |
| 614 | writel(val, 0x3103120); |
| 615 | |
| 616 | // set mctl reg 3c4 to zero when using half DQ |
| 617 | if (config->dram_para2 & BIT(0)) |
| 618 | writel(0, 0x31033c4); |
| 619 | |
| 620 | // purpose ?? |
| 621 | if (para->dram_tpr4) { |
| 622 | setbits_le32(0x3102000, (para->dram_tpr4 & 0x3) << 25); |
| 623 | setbits_le32(0x3102004, (para->dram_tpr4 & 0x7fc) << 10); |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | static const uint8_t ac_remapping_tables[][22] = { |
| 628 | [0] = { 0 }, |
| 629 | [1] = { 1, 9, 3, 7, 8, 18, 4, 13, 5, 6, 10, |
| 630 | 2, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 }, |
| 631 | [2] = { 4, 9, 3, 7, 8, 18, 1, 13, 2, 6, 10, |
| 632 | 5, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 }, |
| 633 | [3] = { 1, 7, 8, 12, 10, 18, 4, 13, 5, 6, 3, |
| 634 | 2, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 }, |
| 635 | [4] = { 4, 12, 10, 7, 8, 18, 1, 13, 2, 6, 3, |
| 636 | 5, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 }, |
| 637 | [5] = { 13, 2, 7, 9, 12, 19, 5, 1, 6, 3, 4, |
| 638 | 8, 10, 0, 0, 0, 21, 22, 18, 17, 11, 20 }, |
| 639 | [6] = { 3, 10, 7, 13, 9, 11, 1, 2, 4, 6, 8, |
| 640 | 5, 12, 0, 0, 0, 20, 1, 0, 21, 22, 17 }, |
| 641 | [7] = { 3, 2, 4, 7, 9, 1, 17, 12, 18, 14, 13, |
| 642 | 8, 15, 6, 10, 5, 19, 22, 16, 21, 20, 11 }, |
| 643 | }; |
| 644 | |
| 645 | /* |
| 646 | * This routine chooses one of several remapping tables for 22 lines. |
| 647 | * It is unclear which lines are being remapped. It seems to pick |
| 648 | * table cfg7 for the Nezha board. |
| 649 | */ |
| 650 | static void mctl_phy_ac_remapping(const dram_para_t *para, |
| 651 | const dram_config_t *config) |
| 652 | { |
| 653 | const uint8_t *cfg; |
| 654 | uint32_t fuse, val; |
| 655 | |
| 656 | /* |
| 657 | * It is unclear whether the LPDDRx types don't need any remapping, |
| 658 | * or whether the original code just didn't provide tables. |
| 659 | */ |
| 660 | if (para->dram_type != SUNXI_DRAM_TYPE_DDR2 && |
| 661 | para->dram_type != SUNXI_DRAM_TYPE_DDR3) |
| 662 | return; |
| 663 | |
| 664 | fuse = (readl(SUNXI_SID_BASE + 0x28) & 0xf00) >> 8; |
| 665 | debug("DDR efuse: 0x%x\n", fuse); |
| 666 | |
| 667 | if (para->dram_type == SUNXI_DRAM_TYPE_DDR2) { |
| 668 | if (fuse == 15) |
| 669 | return; |
| 670 | cfg = ac_remapping_tables[6]; |
| 671 | } else { |
| 672 | if (config->dram_tpr13 & 0xc0000) { |
| 673 | cfg = ac_remapping_tables[7]; |
| 674 | } else { |
| 675 | switch (fuse) { |
| 676 | case 8: cfg = ac_remapping_tables[2]; break; |
| 677 | case 9: cfg = ac_remapping_tables[3]; break; |
| 678 | case 10: cfg = ac_remapping_tables[5]; break; |
| 679 | case 11: cfg = ac_remapping_tables[4]; break; |
| 680 | default: |
| 681 | case 12: cfg = ac_remapping_tables[1]; break; |
| 682 | case 13: |
| 683 | case 14: cfg = ac_remapping_tables[0]; break; |
| 684 | } |
| 685 | } |
| 686 | } |
| 687 | |
| 688 | val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) | |
| 689 | (cfg[1] << 10) | (cfg[0] << 5); |
| 690 | writel(val, 0x3102500); |
| 691 | |
| 692 | val = (cfg[10] << 25) | (cfg[9] << 20) | (cfg[8] << 15) | |
| 693 | (cfg[ 7] << 10) | (cfg[6] << 5) | cfg[5]; |
| 694 | writel(val, 0x3102504); |
| 695 | |
| 696 | val = (cfg[15] << 20) | (cfg[14] << 15) | (cfg[13] << 10) | |
| 697 | (cfg[12] << 5) | cfg[11]; |
| 698 | writel(val, 0x3102508); |
| 699 | |
| 700 | val = (cfg[21] << 25) | (cfg[20] << 20) | (cfg[19] << 15) | |
| 701 | (cfg[18] << 10) | (cfg[17] << 5) | cfg[16]; |
| 702 | writel(val, 0x310250c); |
| 703 | |
| 704 | val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) | |
| 705 | (cfg[1] << 10) | (cfg[0] << 5) | 1; |
| 706 | writel(val, 0x3102500); |
| 707 | } |
| 708 | |
| 709 | // Init the controller channel. The key part is placing commands in the main |
| 710 | // command register (PIR, 0x3103000) and checking command status (PGSR0, 0x3103010). |
| 711 | // |
| 712 | static unsigned int mctl_channel_init(unsigned int ch_index, |
| 713 | const dram_para_t *para, |
| 714 | const dram_config_t *config) |
| 715 | { |
| 716 | unsigned int val, dqs_gating_mode; |
| 717 | |
| 718 | dqs_gating_mode = (config->dram_tpr13 & 0xc) >> 2; |
| 719 | |
| 720 | // set DDR clock to half of CPU clock |
| 721 | clrsetbits_le32(0x310200c, 0xfff, (para->dram_clk / 2) - 1); |
| 722 | |
| 723 | // MRCTRL0 nibble 3 undocumented |
| 724 | clrsetbits_le32(0x3103108, 0xf00, 0x300); |
| 725 | |
| 726 | if (para->dram_odt_en) |
| 727 | val = 0; |
| 728 | else |
| 729 | val = BIT(5); |
| 730 | |
| 731 | // DX0GCR0 |
| 732 | if (para->dram_clk > 672) |
| 733 | clrsetbits_le32(0x3103344, 0xf63e, val); |
| 734 | else |
| 735 | clrsetbits_le32(0x3103344, 0xf03e, val); |
| 736 | |
| 737 | // DX1GCR0 |
| 738 | if (para->dram_clk > 672) { |
| 739 | setbits_le32(0x3103344, 0x400); |
| 740 | clrsetbits_le32(0x31033c4, 0xf63e, val); |
| 741 | } else { |
| 742 | clrsetbits_le32(0x31033c4, 0xf03e, val); |
| 743 | } |
| 744 | |
| 745 | // 0x3103208 undocumented |
| 746 | setbits_le32(0x3103208, BIT(1)); |
| 747 | |
| 748 | eye_delay_compensation(para); |
| 749 | |
| 750 | // set PLL SSCG ? |
| 751 | val = readl(0x3103108); |
| 752 | if (dqs_gating_mode == 1) { |
| 753 | clrsetbits_le32(0x3103108, 0xc0, 0); |
| 754 | clrbits_le32(0x31030bc, 0x107); |
| 755 | } else if (dqs_gating_mode == 2) { |
| 756 | clrsetbits_le32(0x3103108, 0xc0, 0x80); |
| 757 | |
| 758 | clrsetbits_le32(0x31030bc, 0x107, |
| 759 | (((config->dram_tpr13 >> 16) & 0x1f) - 2) | 0x100); |
| 760 | clrsetbits_le32(0x310311c, BIT(31), BIT(27)); |
| 761 | } else { |
| 762 | clrbits_le32(0x3103108, 0x40); |
| 763 | udelay(10); |
| 764 | setbits_le32(0x3103108, 0xc0); |
| 765 | } |
| 766 | |
| 767 | if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 || |
| 768 | para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) { |
| 769 | if (dqs_gating_mode == 1) |
| 770 | clrsetbits_le32(0x310311c, 0x080000c0, 0x80000000); |
| 771 | else |
| 772 | clrsetbits_le32(0x310311c, 0x77000000, 0x22000000); |
| 773 | } |
| 774 | |
| 775 | clrsetbits_le32(0x31030c0, 0x0fffffff, |
| 776 | (config->dram_para2 & BIT(12)) ? 0x03000001 : 0x01000007); |
| 777 | |
| 778 | if (readl(0x70005d4) & BIT(16)) { |
| 779 | clrbits_le32(0x7010250, 0x2); |
| 780 | udelay(10); |
| 781 | } |
| 782 | |
| 783 | // Set ZQ config |
| 784 | clrsetbits_le32(0x3103140, 0x3ffffff, |
| 785 | (para->dram_zq & 0x00ffffff) | BIT(25)); |
| 786 | |
| 787 | // Initialise DRAM controller |
| 788 | if (dqs_gating_mode == 1) { |
| 789 | //writel(0x52, 0x3103000); // prep PHY reset + PLL init + z-cal |
| 790 | writel(0x53, 0x3103000); // Go |
| 791 | |
| 792 | while ((readl(0x3103010) & 0x1) == 0) { |
| 793 | } // wait for IDONE |
| 794 | udelay(10); |
| 795 | |
| 796 | // 0x520 = prep DQS gating + DRAM init + d-cal |
| 797 | if (para->dram_type == SUNXI_DRAM_TYPE_DDR3) |
| 798 | writel(0x5a0, 0x3103000); // + DRAM reset |
| 799 | else |
| 800 | writel(0x520, 0x3103000); |
| 801 | } else { |
| 802 | if ((readl(0x70005d4) & (1 << 16)) == 0) { |
| 803 | // prep DRAM init + PHY reset + d-cal + PLL init + z-cal |
| 804 | if (para->dram_type == SUNXI_DRAM_TYPE_DDR3) |
| 805 | writel(0x1f2, 0x3103000); // + DRAM reset |
| 806 | else |
| 807 | writel(0x172, 0x3103000); |
| 808 | } else { |
| 809 | // prep PHY reset + d-cal + z-cal |
| 810 | writel(0x62, 0x3103000); |
| 811 | } |
| 812 | } |
| 813 | |
| 814 | setbits_le32(0x3103000, 0x1); // GO |
| 815 | |
| 816 | udelay(10); |
| 817 | while ((readl(0x3103010) & 0x1) == 0) { |
| 818 | } // wait for IDONE |
| 819 | |
| 820 | if (readl(0x70005d4) & BIT(16)) { |
| 821 | clrsetbits_le32(0x310310c, 0x06000000, 0x04000000); |
| 822 | udelay(10); |
| 823 | |
| 824 | setbits_le32(0x3103004, 0x1); |
| 825 | |
| 826 | while ((readl(0x3103018) & 0x7) != 0x3) { |
| 827 | } |
| 828 | |
| 829 | clrbits_le32(0x7010250, 0x1); |
| 830 | udelay(10); |
| 831 | |
| 832 | clrbits_le32(0x3103004, 0x1); |
| 833 | |
| 834 | while ((readl(0x3103018) & 0x7) != 0x1) { |
| 835 | } |
| 836 | |
| 837 | udelay(15); |
| 838 | |
| 839 | if (dqs_gating_mode == 1) { |
| 840 | clrbits_le32(0x3103108, 0xc0); |
| 841 | clrsetbits_le32(0x310310c, 0x06000000, 0x02000000); |
| 842 | udelay(1); |
| 843 | writel(0x401, 0x3103000); |
| 844 | |
| 845 | while ((readl(0x3103010) & 0x1) == 0) { |
| 846 | } |
| 847 | } |
| 848 | } |
| 849 | |
| 850 | // Check for training error |
| 851 | if (readl(0x3103010) & BIT(20)) { |
| 852 | printf("ZQ calibration error, check external 240 ohm resistor\n"); |
| 853 | return 0; |
| 854 | } |
| 855 | |
| 856 | // STATR = Zynq STAT? Wait for status 'normal'? |
| 857 | while ((readl(0x3103018) & 0x1) == 0) { |
| 858 | } |
| 859 | |
| 860 | setbits_le32(0x310308c, BIT(31)); |
| 861 | udelay(10); |
| 862 | clrbits_le32(0x310308c, BIT(31)); |
| 863 | udelay(10); |
| 864 | setbits_le32(0x3102014, BIT(31)); |
| 865 | udelay(10); |
| 866 | |
| 867 | clrbits_le32(0x310310c, 0x06000000); |
| 868 | |
| 869 | if (dqs_gating_mode == 1) |
| 870 | clrsetbits_le32(0x310311c, 0xc0, 0x40); |
| 871 | |
| 872 | return 1; |
| 873 | } |
| 874 | |
| 875 | static unsigned int calculate_rank_size(uint32_t regval) |
| 876 | { |
| 877 | unsigned int bits; |
| 878 | |
| 879 | bits = (regval >> 8) & 0xf; /* page size - 3 */ |
| 880 | bits += (regval >> 4) & 0xf; /* row width - 1 */ |
| 881 | bits += (regval >> 2) & 0x3; /* bank count - 2 */ |
| 882 | bits -= 14; /* 1MB = 20 bits, minus above 6 = 14 */ |
| 883 | |
| 884 | return 1U << bits; |
| 885 | } |
| 886 | |
| 887 | /* |
| 888 | * The below routine reads the dram config registers and extracts |
| 889 | * the number of address bits in each rank available. It then calculates |
| 890 | * total memory size in MB. |
| 891 | */ |
| 892 | static unsigned int DRAMC_get_dram_size(void) |
| 893 | { |
| 894 | uint32_t val; |
| 895 | unsigned int size; |
| 896 | |
| 897 | val = readl(0x3102000); /* MC_WORK_MODE0 */ |
| 898 | size = calculate_rank_size(val); |
| 899 | if ((val & 0x3) == 0) /* single rank? */ |
| 900 | return size; |
| 901 | |
| 902 | val = readl(0x3102004); /* MC_WORK_MODE1 */ |
| 903 | if ((val & 0x3) == 0) /* two identical ranks? */ |
| 904 | return size * 2; |
| 905 | |
| 906 | /* add sizes of both ranks */ |
| 907 | return size + calculate_rank_size(val); |
| 908 | } |
| 909 | |
| 910 | /* |
| 911 | * The below routine reads the command status register to extract |
| 912 | * DQ width and rank count. This follows the DQS training command in |
| 913 | * channel_init. If error bit 22 is reset, we have two ranks and full DQ. |
| 914 | * If there was an error, figure out whether it was half DQ, single rank, |
| 915 | * or both. Set bit 12 and 0 in dram_para2 with the results. |
| 916 | */ |
| 917 | static int dqs_gate_detect(dram_config_t *config) |
| 918 | { |
| 919 | uint32_t dx0, dx1; |
| 920 | |
| 921 | if ((readl(0x3103010) & BIT(22)) == 0) { |
| 922 | config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12); |
| 923 | debug("dual rank and full DQ\n"); |
| 924 | |
| 925 | return 1; |
| 926 | } |
| 927 | |
| 928 | dx0 = (readl(0x3103348) & 0x3000000) >> 24; |
| 929 | if (dx0 == 0) { |
| 930 | config->dram_para2 = (config->dram_para2 & ~0xf) | 0x1001; |
| 931 | debug("dual rank and half DQ\n"); |
| 932 | |
| 933 | return 1; |
| 934 | } |
| 935 | |
| 936 | if (dx0 == 2) { |
| 937 | dx1 = (readl(0x31033c8) & 0x3000000) >> 24; |
| 938 | if (dx1 == 2) { |
| 939 | config->dram_para2 = config->dram_para2 & ~0xf00f; |
| 940 | debug("single rank and full DQ\n"); |
| 941 | } else { |
| 942 | config->dram_para2 = (config->dram_para2 & ~0xf00f) | BIT(0); |
| 943 | debug("single rank and half DQ\n"); |
| 944 | } |
| 945 | |
| 946 | return 1; |
| 947 | } |
| 948 | |
| 949 | if ((config->dram_tpr13 & BIT(29)) == 0) |
| 950 | return 0; |
| 951 | |
| 952 | debug("DX0 state: %d\n", dx0); |
| 953 | debug("DX1 state: %d\n", dx1); |
| 954 | |
| 955 | return 0; |
| 956 | } |
| 957 | |
| 958 | static int dramc_simple_wr_test(unsigned int mem_mb, int len) |
| 959 | { |
| 960 | unsigned int offs = (mem_mb / 2) << 18; // half of memory size |
| 961 | unsigned int patt1 = 0x01234567; |
| 962 | unsigned int patt2 = 0xfedcba98; |
| 963 | unsigned int *addr, v1, v2, i; |
| 964 | |
| 965 | addr = (unsigned int *)CFG_SYS_SDRAM_BASE; |
| 966 | for (i = 0; i != len; i++, addr++) { |
| 967 | writel(patt1 + i, (unsigned long)addr); |
| 968 | writel(patt2 + i, (unsigned long)(addr + offs)); |
| 969 | } |
| 970 | |
| 971 | addr = (unsigned int *)CFG_SYS_SDRAM_BASE; |
| 972 | for (i = 0; i != len; i++) { |
| 973 | v1 = readl((unsigned long)(addr + i)); |
| 974 | v2 = patt1 + i; |
| 975 | if (v1 != v2) { |
| 976 | printf("DRAM: simple test FAIL\n"); |
| 977 | printf("%x != %x at address %p\n", v1, v2, addr + i); |
| 978 | return 1; |
| 979 | } |
| 980 | v1 = readl((unsigned long)(addr + offs + i)); |
| 981 | v2 = patt2 + i; |
| 982 | if (v1 != v2) { |
| 983 | printf("DRAM: simple test FAIL\n"); |
| 984 | printf("%x != %x at address %p\n", v1, v2, addr + offs + i); |
| 985 | return 1; |
| 986 | } |
| 987 | } |
| 988 | |
| 989 | debug("DRAM: simple test OK\n"); |
| 990 | return 0; |
| 991 | } |
| 992 | |
| 993 | // Set the Vref mode for the controller |
| 994 | // |
| 995 | static void mctl_vrefzq_init(const dram_para_t *para, const dram_config_t *config) |
| 996 | { |
| 997 | if (config->dram_tpr13 & BIT(17)) |
| 998 | return; |
| 999 | |
| 1000 | clrsetbits_le32(0x3103110, 0x7f7f7f7f, para->dram_tpr5); |
| 1001 | |
| 1002 | // IOCVR1 |
| 1003 | if ((config->dram_tpr13 & BIT(16)) == 0) |
| 1004 | clrsetbits_le32(0x3103114, 0x7f, para->dram_tpr6 & 0x7f); |
| 1005 | } |
| 1006 | |
| 1007 | // Perform an init of the controller. This is actually done 3 times. The first |
| 1008 | // time to establish the number of ranks and DQ width. The second time to |
| 1009 | // establish the actual ram size. The third time is final one, with the final |
| 1010 | // settings. |
| 1011 | // |
| 1012 | static int mctl_core_init(const dram_para_t *para, const dram_config_t *config) |
| 1013 | { |
| 1014 | mctl_sys_init(para, config); |
| 1015 | |
| 1016 | mctl_vrefzq_init(para, config); |
| 1017 | |
| 1018 | mctl_com_init(para, config); |
| 1019 | |
| 1020 | mctl_phy_ac_remapping(para, config); |
| 1021 | |
| 1022 | mctl_set_timing_params(para, config); |
| 1023 | |
| 1024 | return mctl_channel_init(0, para, config); |
| 1025 | } |
| 1026 | |
| 1027 | /* |
| 1028 | * This routine sizes a DRAM device by cycling through address lines and |
| 1029 | * figuring out if they are connected to a real address line, or if the |
| 1030 | * address is a mirror. |
| 1031 | * First the column and bank bit allocations are set to low values (2 and 9 |
| 1032 | * address lines). Then a maximum allocation (16 lines) is set for rows and |
| 1033 | * this is tested. |
| 1034 | * Next the BA2 line is checked. This seems to be placed above the column, |
| 1035 | * BA0-1 and row addresses. Finally, the column address is allocated 13 lines |
| 1036 | * and these are tested. The results are placed in dram_para1 and dram_para2. |
| 1037 | */ |
| 1038 | |
| 1039 | static uint32_t get_payload(bool odd, unsigned long int ptr) |
| 1040 | { |
| 1041 | if (odd) |
| 1042 | return (uint32_t)ptr; |
| 1043 | else |
| 1044 | return ~((uint32_t)ptr); |
| 1045 | } |
| 1046 | |
| 1047 | static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config) |
| 1048 | { |
| 1049 | unsigned int rval, i, j, rank, maxrank, offs; |
| 1050 | unsigned int shft; |
| 1051 | unsigned long ptr, mc_work_mode, chk; |
| 1052 | |
| 1053 | if (mctl_core_init(para, config) == 0) { |
| 1054 | printf("DRAM initialisation error : 0\n"); |
| 1055 | return 0; |
| 1056 | } |
| 1057 | |
| 1058 | maxrank = (config->dram_para2 & 0xf000) ? 2 : 1; |
| 1059 | mc_work_mode = 0x3102000; |
| 1060 | offs = 0; |
| 1061 | |
| 1062 | /* write test pattern */ |
| 1063 | for (i = 0, ptr = CFG_SYS_SDRAM_BASE; i < 64; i++, ptr += 4) |
| 1064 | writel(get_payload(i & 0x1, ptr), ptr); |
| 1065 | |
| 1066 | for (rank = 0; rank < maxrank;) { |
| 1067 | /* set row mode */ |
| 1068 | clrsetbits_le32(mc_work_mode, 0xf0c, 0x6f0); |
| 1069 | udelay(1); |
| 1070 | |
| 1071 | // Scan per address line, until address wraps (i.e. see shadow) |
| 1072 | for (i = 11; i < 17; i++) { |
| 1073 | chk = CFG_SYS_SDRAM_BASE + (1U << (i + 11)); |
| 1074 | ptr = CFG_SYS_SDRAM_BASE; |
| 1075 | for (j = 0; j < 64; j++) { |
| 1076 | if (readl(chk) != get_payload(j & 0x1, ptr)) |
| 1077 | break; |
| 1078 | ptr += 4; |
| 1079 | chk += 4; |
| 1080 | } |
| 1081 | if (j == 64) |
| 1082 | break; |
| 1083 | } |
| 1084 | if (i > 16) |
| 1085 | i = 16; |
| 1086 | debug("rank %d row = %d\n", rank, i); |
| 1087 | |
| 1088 | /* Store rows in para 1 */ |
| 1089 | shft = offs + 4; |
| 1090 | rval = config->dram_para1; |
| 1091 | rval &= ~(0xff << shft); |
| 1092 | rval |= i << shft; |
| 1093 | config->dram_para1 = rval; |
| 1094 | |
| 1095 | if (rank == 1) /* Set bank mode for rank0 */ |
| 1096 | clrsetbits_le32(0x3102000, 0xffc, 0x6a4); |
| 1097 | |
| 1098 | /* Set bank mode for current rank */ |
| 1099 | clrsetbits_le32(mc_work_mode, 0xffc, 0x6a4); |
| 1100 | udelay(1); |
| 1101 | |
| 1102 | // Test if bit A23 is BA2 or mirror XXX A22? |
| 1103 | chk = CFG_SYS_SDRAM_BASE + (1U << 22); |
| 1104 | ptr = CFG_SYS_SDRAM_BASE; |
| 1105 | for (i = 0, j = 0; i < 64; i++) { |
| 1106 | if (readl(chk) != get_payload(i & 1, ptr)) { |
| 1107 | j = 1; |
| 1108 | break; |
| 1109 | } |
| 1110 | ptr += 4; |
| 1111 | chk += 4; |
| 1112 | } |
| 1113 | |
| 1114 | debug("rank %d bank = %d\n", rank, (j + 1) << 2); /* 4 or 8 */ |
| 1115 | |
| 1116 | /* Store banks in para 1 */ |
| 1117 | shft = 12 + offs; |
| 1118 | rval = config->dram_para1; |
| 1119 | rval &= ~(0xf << shft); |
| 1120 | rval |= j << shft; |
| 1121 | config->dram_para1 = rval; |
| 1122 | |
| 1123 | if (rank == 1) /* Set page mode for rank0 */ |
| 1124 | clrsetbits_le32(0x3102000, 0xffc, 0xaa0); |
| 1125 | |
| 1126 | /* Set page mode for current rank */ |
| 1127 | clrsetbits_le32(mc_work_mode, 0xffc, 0xaa0); |
| 1128 | udelay(1); |
| 1129 | |
| 1130 | // Scan per address line, until address wraps (i.e. see shadow) |
| 1131 | for (i = 9; i < 14; i++) { |
| 1132 | chk = CFG_SYS_SDRAM_BASE + (1U << i); |
| 1133 | ptr = CFG_SYS_SDRAM_BASE; |
| 1134 | for (j = 0; j < 64; j++) { |
| 1135 | if (readl(chk) != get_payload(j & 1, ptr)) |
| 1136 | break; |
| 1137 | ptr += 4; |
| 1138 | chk += 4; |
| 1139 | } |
| 1140 | if (j == 64) |
| 1141 | break; |
| 1142 | } |
| 1143 | if (i > 13) |
| 1144 | i = 13; |
| 1145 | |
| 1146 | unsigned int pgsize = (i == 9) ? 0 : (1 << (i - 10)); |
| 1147 | debug("rank %d page size = %d KB\n", rank, pgsize); |
| 1148 | |
| 1149 | /* Store page size */ |
| 1150 | shft = offs; |
| 1151 | rval = config->dram_para1; |
| 1152 | rval &= ~(0xf << shft); |
| 1153 | rval |= pgsize << shft; |
| 1154 | config->dram_para1 = rval; |
| 1155 | |
| 1156 | // Move to next rank |
| 1157 | rank++; |
| 1158 | if (rank != maxrank) { |
| 1159 | if (rank == 1) { |
| 1160 | /* MC_WORK_MODE */ |
| 1161 | clrsetbits_le32(0x3202000, 0xffc, 0x6f0); |
| 1162 | |
| 1163 | /* MC_WORK_MODE2 */ |
| 1164 | clrsetbits_le32(0x3202004, 0xffc, 0x6f0); |
| 1165 | } |
| 1166 | /* store rank1 config in upper half of para1 */ |
| 1167 | offs += 16; |
| 1168 | mc_work_mode += 4; /* move to MC_WORK_MODE2 */ |
| 1169 | } |
| 1170 | } |
| 1171 | if (maxrank == 2) { |
| 1172 | config->dram_para2 &= 0xfffff0ff; |
| 1173 | /* note: rval is equal to para->dram_para1 here */ |
| 1174 | if ((rval & 0xffff) == (rval >> 16)) { |
| 1175 | debug("rank1 config same as rank0\n"); |
| 1176 | } else { |
| 1177 | config->dram_para2 |= BIT(8); |
| 1178 | debug("rank1 config different from rank0\n"); |
| 1179 | } |
| 1180 | } |
| 1181 | |
| 1182 | return 1; |
| 1183 | } |
| 1184 | |
| 1185 | /* |
| 1186 | * This routine sets up parameters with dqs_gating_mode equal to 1 and two |
| 1187 | * ranks enabled. It then configures the core and tests for 1 or 2 ranks and |
| 1188 | * full or half DQ width. It then resets the parameters to the original values. |
| 1189 | * dram_para2 is updated with the rank and width findings. |
| 1190 | */ |
| 1191 | static int auto_scan_dram_rank_width(const dram_para_t *para, |
| 1192 | dram_config_t *config) |
| 1193 | { |
| 1194 | unsigned int s1 = config->dram_tpr13; |
| 1195 | unsigned int s2 = config->dram_para1; |
| 1196 | |
| 1197 | config->dram_para1 = 0x00b000b0; |
| 1198 | config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12); |
| 1199 | |
| 1200 | /* set DQS probe mode */ |
| 1201 | config->dram_tpr13 = (config->dram_tpr13 & ~0x8) | BIT(2) | BIT(0); |
| 1202 | |
| 1203 | mctl_core_init(para, config); |
| 1204 | |
| 1205 | if (readl(0x3103010) & BIT(20)) |
| 1206 | return 0; |
| 1207 | |
| 1208 | if (dqs_gate_detect(config) == 0) |
| 1209 | return 0; |
| 1210 | |
| 1211 | config->dram_tpr13 = s1; |
| 1212 | config->dram_para1 = s2; |
| 1213 | |
| 1214 | return 1; |
| 1215 | } |
| 1216 | |
| 1217 | /* |
| 1218 | * This routine determines the SDRAM topology. It first establishes the number |
| 1219 | * of ranks and the DQ width. Then it scans the SDRAM address lines to establish |
| 1220 | * the size of each rank. It then updates dram_tpr13 to reflect that the sizes |
| 1221 | * are now known: a re-init will not repeat the autoscan. |
| 1222 | */ |
| 1223 | static int auto_scan_dram_config(const dram_para_t *para, |
| 1224 | dram_config_t *config) |
| 1225 | { |
| 1226 | if (((config->dram_tpr13 & BIT(14)) == 0) && |
| 1227 | (auto_scan_dram_rank_width(para, config) == 0)) { |
| 1228 | printf("ERROR: auto scan dram rank & width failed\n"); |
| 1229 | return 0; |
| 1230 | } |
| 1231 | |
| 1232 | if (((config->dram_tpr13 & BIT(0)) == 0) && |
| 1233 | (auto_scan_dram_size(para, config) == 0)) { |
| 1234 | printf("ERROR: auto scan dram size failed\n"); |
| 1235 | return 0; |
| 1236 | } |
| 1237 | |
| 1238 | if ((config->dram_tpr13 & BIT(15)) == 0) |
| 1239 | config->dram_tpr13 |= BIT(14) | BIT(13) | BIT(1) | BIT(0); |
| 1240 | |
| 1241 | return 1; |
| 1242 | } |
| 1243 | |
| 1244 | static int init_DRAM(int type, const dram_para_t *para) |
| 1245 | { |
| 1246 | dram_config_t config = { |
| 1247 | .dram_para1 = 0x000010d2, |
| 1248 | .dram_para2 = 0, |
| 1249 | .dram_tpr13 = CONFIG_DRAM_SUNXI_TPR13, |
| 1250 | }; |
| 1251 | u32 rc, mem_size_mb; |
| 1252 | |
| 1253 | debug("DRAM BOOT DRIVE INFO: %s\n", "V0.24"); |
| 1254 | debug("DRAM CLK = %d MHz\n", para->dram_clk); |
| 1255 | debug("DRAM Type = %d (2:DDR2,3:DDR3)\n", para->dram_type); |
| 1256 | if ((para->dram_odt_en & 0x1) == 0) |
| 1257 | debug("DRAMC read ODT off\n"); |
| 1258 | else |
| 1259 | debug("DRAMC ZQ value: 0x%x\n", para->dram_zq); |
| 1260 | |
| 1261 | /* Test ZQ status */ |
| 1262 | if (config.dram_tpr13 & BIT(16)) { |
| 1263 | debug("DRAM only have internal ZQ\n"); |
| 1264 | setbits_le32(0x3000160, BIT(8)); |
| 1265 | writel(0, 0x3000168); |
| 1266 | udelay(10); |
| 1267 | } else { |
| 1268 | clrbits_le32(0x3000160, 0x3); |
| 1269 | writel(config.dram_tpr13 & BIT(16), 0x7010254); |
| 1270 | udelay(10); |
| 1271 | clrsetbits_le32(0x3000160, 0x108, BIT(1)); |
| 1272 | udelay(10); |
| 1273 | setbits_le32(0x3000160, BIT(0)); |
| 1274 | udelay(20); |
| 1275 | debug("ZQ value = 0x%x\n", readl(0x300016c)); |
| 1276 | } |
| 1277 | |
| 1278 | dram_voltage_set(para); |
| 1279 | |
| 1280 | /* Set SDRAM controller auto config */ |
| 1281 | if ((config.dram_tpr13 & BIT(0)) == 0) { |
| 1282 | if (auto_scan_dram_config(para, &config) == 0) { |
| 1283 | printf("auto_scan_dram_config() FAILED\n"); |
| 1284 | return 0; |
| 1285 | } |
| 1286 | } |
| 1287 | |
| 1288 | /* report ODT */ |
| 1289 | rc = para->dram_mr1; |
| 1290 | if ((rc & 0x44) == 0) |
| 1291 | debug("DRAM ODT off\n"); |
| 1292 | else |
| 1293 | debug("DRAM ODT value: 0x%x\n", rc); |
| 1294 | |
| 1295 | /* Init core, final run */ |
| 1296 | if (mctl_core_init(para, &config) == 0) { |
| 1297 | printf("DRAM initialisation error: 1\n"); |
| 1298 | return 0; |
| 1299 | } |
| 1300 | |
| 1301 | /* Get SDRAM size */ |
| 1302 | /* TODO: who ever puts a negative number in the top half? */ |
| 1303 | rc = config.dram_para2; |
| 1304 | if (rc & BIT(31)) { |
| 1305 | rc = (rc >> 16) & ~BIT(15); |
| 1306 | } else { |
| 1307 | rc = DRAMC_get_dram_size(); |
| 1308 | debug("DRAM: size = %dMB\n", rc); |
| 1309 | config.dram_para2 = (config.dram_para2 & 0xffffU) | rc << 16; |
| 1310 | } |
| 1311 | mem_size_mb = rc; |
| 1312 | |
| 1313 | /* Purpose ?? */ |
| 1314 | if (config.dram_tpr13 & BIT(30)) { |
| 1315 | rc = para->dram_tpr8; |
| 1316 | if (rc == 0) |
| 1317 | rc = 0x10000200; |
| 1318 | writel(rc, 0x31030a0); |
| 1319 | writel(0x40a, 0x310309c); |
| 1320 | setbits_le32(0x3103004, BIT(0)); |
| 1321 | debug("Enable Auto SR\n"); |
| 1322 | } else { |
| 1323 | clrbits_le32(0x31030a0, 0xffff); |
| 1324 | clrbits_le32(0x3103004, 0x1); |
| 1325 | } |
| 1326 | |
| 1327 | /* Purpose ?? */ |
| 1328 | if (config.dram_tpr13 & BIT(9)) { |
| 1329 | clrsetbits_le32(0x3103100, 0xf000, 0x5000); |
| 1330 | } else { |
| 1331 | if (para->dram_type != SUNXI_DRAM_TYPE_LPDDR2) |
| 1332 | clrbits_le32(0x3103100, 0xf000); |
| 1333 | } |
| 1334 | |
| 1335 | setbits_le32(0x3103140, BIT(31)); |
| 1336 | |
| 1337 | /* CHECK: is that really writing to a different register? */ |
| 1338 | if (config.dram_tpr13 & BIT(8)) |
| 1339 | writel(readl(0x3103140) | 0x300, 0x31030b8); |
| 1340 | |
| 1341 | if (config.dram_tpr13 & BIT(16)) |
| 1342 | clrbits_le32(0x3103108, BIT(13)); |
| 1343 | else |
| 1344 | setbits_le32(0x3103108, BIT(13)); |
| 1345 | |
| 1346 | /* Purpose ?? */ |
| 1347 | if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) |
| 1348 | clrsetbits_le32(0x310307c, 0xf0000, 0x1000); |
| 1349 | |
| 1350 | dram_enable_all_master(); |
| 1351 | if (config.dram_tpr13 & BIT(28)) { |
| 1352 | if ((readl(0x70005d4) & BIT(16)) || |
| 1353 | dramc_simple_wr_test(mem_size_mb, 4096)) |
| 1354 | return 0; |
| 1355 | } |
| 1356 | |
| 1357 | return mem_size_mb; |
| 1358 | } |
| 1359 | |
| 1360 | static const dram_para_t para = { |
| 1361 | .dram_clk = CONFIG_DRAM_CLK, |
| 1362 | .dram_type = CONFIG_SUNXI_DRAM_TYPE, |
| 1363 | .dram_zq = CONFIG_DRAM_ZQ, |
| 1364 | .dram_odt_en = CONFIG_DRAM_SUNXI_ODT_EN, |
| 1365 | .dram_mr0 = 0x1c70, |
| 1366 | .dram_mr1 = 0x42, |
| 1367 | .dram_mr2 = 0x18, |
| 1368 | .dram_mr3 = 0, |
| 1369 | .dram_tpr0 = 0x004a2195, |
| 1370 | .dram_tpr1 = 0x02423190, |
| 1371 | .dram_tpr2 = 0x0008b061, |
| 1372 | .dram_tpr3 = 0xb4787896, // unused |
| 1373 | .dram_tpr4 = 0, |
| 1374 | .dram_tpr5 = 0x48484848, |
| 1375 | .dram_tpr6 = 0x00000048, |
| 1376 | .dram_tpr7 = 0x1620121e, // unused |
| 1377 | .dram_tpr8 = 0, |
| 1378 | .dram_tpr9 = 0, // clock? |
| 1379 | .dram_tpr10 = 0, |
| 1380 | .dram_tpr11 = CONFIG_DRAM_SUNXI_TPR11, |
| 1381 | .dram_tpr12 = CONFIG_DRAM_SUNXI_TPR12, |
| 1382 | }; |
| 1383 | |
| 1384 | unsigned long sunxi_dram_init(void) |
| 1385 | { |
| 1386 | return init_DRAM(0, ¶) * 1024UL * 1024; |
| 1387 | }; |
| 1388 | |
| 1389 | #ifdef CONFIG_RAM /* using the driver model */ |
| 1390 | struct sunxi_ram_priv { |
| 1391 | size_t size; |
| 1392 | }; |
| 1393 | |
| 1394 | static int sunxi_ram_probe(struct udevice *dev) |
| 1395 | { |
| 1396 | struct sunxi_ram_priv *priv = dev_get_priv(dev); |
| 1397 | unsigned long dram_size; |
| 1398 | |
| 1399 | debug("%s: %s: probing\n", __func__, dev->name); |
| 1400 | |
| 1401 | dram_size = sunxi_dram_init(); |
| 1402 | if (!dram_size) { |
| 1403 | printf("DRAM init failed\n"); |
| 1404 | return -ENODEV; |
| 1405 | } |
| 1406 | |
| 1407 | priv->size = dram_size; |
| 1408 | |
| 1409 | return 0; |
| 1410 | } |
| 1411 | |
| 1412 | static int sunxi_ram_get_info(struct udevice *dev, struct ram_info *info) |
| 1413 | { |
| 1414 | struct sunxi_ram_priv *priv = dev_get_priv(dev); |
| 1415 | |
| 1416 | debug("%s: %s: getting info\n", __func__, dev->name); |
| 1417 | |
| 1418 | info->base = CFG_SYS_SDRAM_BASE; |
| 1419 | info->size = priv->size; |
| 1420 | |
| 1421 | return 0; |
| 1422 | } |
| 1423 | |
| 1424 | static struct ram_ops sunxi_ram_ops = { |
| 1425 | .get_info = sunxi_ram_get_info, |
| 1426 | }; |
| 1427 | |
| 1428 | static const struct udevice_id sunxi_ram_ids[] = { |
| 1429 | { .compatible = "allwinner,sun20i-d1-mbus" }, |
| 1430 | { } |
| 1431 | }; |
| 1432 | |
| 1433 | U_BOOT_DRIVER(sunxi_ram) = { |
| 1434 | .name = "sunxi_ram", |
| 1435 | .id = UCLASS_RAM, |
| 1436 | .of_match = sunxi_ram_ids, |
| 1437 | .ops = &sunxi_ram_ops, |
| 1438 | .probe = sunxi_ram_probe, |
| 1439 | .priv_auto = sizeof(struct sunxi_ram_priv), |
| 1440 | }; |
| 1441 | #endif /* CONFIG_RAM (using driver model) */ |