1 /************************************************************************ 2 * 3 * Copyright (c) 2013-2015 Intel Corporation. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 * This file contains all of the Cat Mountain Memory Reference Code (MRC). 14 * 15 * These functions are generic and should work for any Cat Mountain config. 16 * 17 * MRC requires two data structures to be passed in which are initialised by "PreMemInit()". 18 * 19 * The basic flow is as follows: 20 * 01) Check for supported DDR speed configuration 21 * 02) Set up MEMORY_MANAGER buffer as pass-through (POR) 22 * 03) Set Channel Interleaving Mode and Channel Stride to the most aggressive setting possible 23 * 04) Set up the MCU logic 24 * 05) Set up the DDR_PHY logic 25 * 06) Initialise the DRAMs (JEDEC) 26 * 07) Perform the Receive Enable Calibration algorithm 27 * 08) Perform the Write Leveling algorithm 28 * 09) Perform the Read Training algorithm (includes internal Vref) 29 * 10) Perform the Write Training algorithm 30 * 11) Set Channel Interleaving Mode and Channel Stride to the desired settings 31 * 32 * Dunit configuration based on Valleyview MRC. 33 * 34 ***************************************************************************/ 35 36 #include "mrc.h" 37 #include "memory_options.h" 38 39 #include "meminit.h" 40 #include "meminit_utils.h" 41 #include "hte.h" 42 #include "io.h" 43 44 // Override ODT to off state if requested 45 #define DRMC_DEFAULT (mrc_params->rd_odt_value==0?BIT12:0) 46 47 48 // tRFC values (in picoseconds) per density 49 const uint32_t tRFC[5] = 50 { 51 90000, // 512Mb 52 110000, // 1Gb 53 160000, // 2Gb 54 300000, // 4Gb 55 350000, // 8Gb 56 }; 57 58 // tCK clock period in picoseconds per speed index 800, 1066, 1333 59 const uint32_t tCK[3] = 60 { 61 2500, 62 1875, 63 1500 64 }; 65 66 #ifdef SIM 67 // Select static timings specific to simulation environment 68 #define PLATFORM_ID 0 69 #else 70 // Select static timings specific to ClantonPeek platform 71 #define PLATFORM_ID 1 72 #endif 73 74 75 // Global variables 76 const uint16_t ddr_wclk[] = 77 {193, 158}; 78 79 const uint16_t ddr_wctl[] = 80 { 1, 217}; 81 82 const uint16_t ddr_wcmd[] = 83 { 1, 220}; 84 85 86 #ifdef BACKUP_RCVN 87 const uint16_t ddr_rcvn[] = 88 {129, 498}; 89 #endif // BACKUP_RCVN 90 91 #ifdef BACKUP_WDQS 92 const uint16_t ddr_wdqs[] = 93 { 65, 289}; 94 #endif // BACKUP_WDQS 95 96 #ifdef BACKUP_RDQS 97 const uint8_t ddr_rdqs[] = 98 { 32, 24}; 99 #endif // BACKUP_RDQS 100 101 #ifdef BACKUP_WDQ 102 const uint16_t ddr_wdq[] = 103 { 32, 257}; 104 #endif // BACKUP_WDQ 105 106 107 108 // Select MEMORY_MANAGER as the source for PRI interface 109 static void select_memory_manager( 110 MRCParams_t *mrc_params) 111 { 112 RegDCO Dco; 113 114 ENTERFN(); 115 116 Dco.raw = isbR32m(MCU, DCO); 117 Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER 118 isbW32m(MCU, DCO, Dco.raw); 119 120 LEAVEFN(); 121 } 122 123 // Select HTE as the source for PRI interface 124 void select_hte( 125 MRCParams_t *mrc_params) 126 { 127 RegDCO Dco; 128 129 ENTERFN(); 130 131 Dco.raw = isbR32m(MCU, DCO); 132 Dco.field.PMICTL = 1; //1 - PRI owned by HTE 133 isbW32m(MCU, DCO, Dco.raw); 134 135 LEAVEFN(); 136 } 137 138 // Send DRAM command, data should be formated 139 // using DCMD_Xxxx macro or emrsXCommand structure. 140 static void dram_init_command( 141 uint32_t data) 142 { 143 Wr32(DCMD, 0, data); 144 } 145 146 // Send DRAM wake command using special MCU side-band WAKE opcode 147 static void dram_wake_command( 148 void) 149 { 150 ENTERFN(); 151 152 Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG), 153 (uint32_t) SB_COMMAND(SB_WAKE_CMND_OPCODE, MCU, 0)); 154 155 LEAVEFN(); 156 } 157 158 // Stop self refresh driven by MCU 159 static void clear_self_refresh( 160 MRCParams_t *mrc_params) 161 { 162 ENTERFN(); 163 164 // clear the PMSTS Channel Self Refresh bits 165 isbM32m(MCU, PMSTS, BIT0, BIT0); 166 167 LEAVEFN(); 168 } 169 170 // Configure MCU before jedec init sequence 171 static void prog_decode_before_jedec( 172 MRCParams_t *mrc_params) 173 { 174 RegDRP Drp; 175 RegDRCF Drfc; 176 RegDCAL Dcal; 177 RegDSCH Dsch; 178 RegDPMC0 Dpmc0; 179 180 ENTERFN(); 181 182 // Disable power saving features 183 Dpmc0.raw = isbR32m(MCU, DPMC0); 184 Dpmc0.field.CLKGTDIS = 1; 185 Dpmc0.field.DISPWRDN = 1; 186 Dpmc0.field.DYNSREN = 0; 187 Dpmc0.field.PCLSTO = 0; 188 isbW32m(MCU, DPMC0, Dpmc0.raw); 189 190 // Disable out of order transactions 191 Dsch.raw = isbR32m(MCU, DSCH); 192 Dsch.field.OOODIS = 1; 193 Dsch.field.NEWBYPDIS = 1; 194 isbW32m(MCU, DSCH, Dsch.raw); 195 196 // Disable issuing the REF command 197 Drfc.raw = isbR32m(MCU, DRFC); 198 Drfc.field.tREFI = 0; 199 isbW32m(MCU, DRFC, Drfc.raw); 200 201 // Disable ZQ calibration short 202 Dcal.raw = isbR32m(MCU, DCAL); 203 Dcal.field.ZQCINT = 0; 204 Dcal.field.SRXZQCL = 0; 205 isbW32m(MCU, DCAL, Dcal.raw); 206 207 // Training performed in address mode 0, rank population has limited impact, however 208 // simulator complains if enabled non-existing rank. 209 Drp.raw = 0; 210 if (mrc_params->rank_enables & 1) 211 Drp.field.rank0Enabled = 1; 212 if (mrc_params->rank_enables & 2) 213 Drp.field.rank1Enabled = 1; 214 isbW32m(MCU, DRP, Drp.raw); 215 216 LEAVEFN(); 217 } 218 219 // After Cold Reset, BIOS should set COLDWAKE bit to 1 before 220 // sending the WAKE message to the Dunit. 221 // For Standby Exit, or any other mode in which the DRAM is in 222 // SR, this bit must be set to 0. 223 static void perform_ddr_reset( 224 MRCParams_t *mrc_params) 225 { 226 ENTERFN(); 227 228 // Set COLDWAKE bit before sending the WAKE message 229 isbM32m(MCU, DRMC, BIT16, BIT16); 230 231 // Send wake command to DUNIT (MUST be done before JEDEC) 232 dram_wake_command(); 233 234 // Set default value 235 isbW32m(MCU, DRMC, DRMC_DEFAULT); 236 237 LEAVEFN(); 238 } 239 240 // Dunit Initialisation Complete. 241 // Indicates that initialisation of the Dunit has completed. 242 // Memory accesses are permitted and maintenance operation 243 // begins. Until this bit is set to a 1, the memory controller will 244 // not accept DRAM requests from the MEMORY_MANAGER or HTE. 245 static void set_ddr_init_complete( 246 MRCParams_t *mrc_params) 247 { 248 RegDCO Dco; 249 250 ENTERFN(); 251 252 Dco.raw = isbR32m(MCU, DCO); 253 Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER 254 Dco.field.IC = 1; //1 - initialisation complete 255 isbW32m(MCU, DCO, Dco.raw); 256 257 LEAVEFN(); 258 } 259 260 static void prog_page_ctrl( 261 MRCParams_t *mrc_params) 262 { 263 RegDPMC0 Dpmc0; 264 265 ENTERFN(); 266 267 Dpmc0.raw = isbR32m(MCU, DPMC0); 268 269 Dpmc0.field.PCLSTO = 0x4; 270 Dpmc0.field.PREAPWDEN = 1; 271 272 isbW32m(MCU, DPMC0, Dpmc0.raw); 273 } 274 275 // Configure MCU Power Management Control Register 276 // and Scheduler Control Register. 277 static void prog_ddr_control( 278 MRCParams_t *mrc_params) 279 { 280 RegDSCH Dsch; 281 RegDPMC0 Dpmc0; 282 283 ENTERFN(); 284 285 Dpmc0.raw = isbR32m(MCU, DPMC0); 286 Dsch.raw = isbR32m(MCU, DSCH); 287 288 Dpmc0.field.DISPWRDN = mrc_params->power_down_disable; 289 Dpmc0.field.CLKGTDIS = 0; 290 Dpmc0.field.PCLSTO = 4; 291 Dpmc0.field.PREAPWDEN = 1; 292 293 Dsch.field.OOODIS = 0; 294 Dsch.field.OOOST3DIS = 0; 295 Dsch.field.NEWBYPDIS = 0; 296 297 isbW32m(MCU, DSCH, Dsch.raw); 298 isbW32m(MCU, DPMC0, Dpmc0.raw); 299 300 // CMDTRIST = 2h - CMD/ADDR are tristated when no valid command 301 isbM32m(MCU, DPMC1, 2 << 4, BIT5|BIT4); 302 303 LEAVEFN(); 304 } 305 306 // After training complete configure MCU Rank Population Register 307 // specifying: ranks enabled, device width, density, address mode. 308 static void prog_dra_drb( 309 MRCParams_t *mrc_params) 310 { 311 RegDRP Drp; 312 RegDCO Dco; 313 314 ENTERFN(); 315 316 Dco.raw = isbR32m(MCU, DCO); 317 Dco.field.IC = 0; 318 isbW32m(MCU, DCO, Dco.raw); 319 320 Drp.raw = 0; 321 if (mrc_params->rank_enables & 1) 322 Drp.field.rank0Enabled = 1; 323 if (mrc_params->rank_enables & 2) 324 Drp.field.rank1Enabled = 1; 325 if (mrc_params->dram_width == x16) 326 { 327 Drp.field.dimm0DevWidth = 1; 328 Drp.field.dimm1DevWidth = 1; 329 } 330 // Density encoding in DRAMParams_t 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb 331 // has to be mapped RANKDENSx encoding (0=1Gb) 332 Drp.field.dimm0DevDensity = mrc_params->params.DENSITY - 1; 333 Drp.field.dimm1DevDensity = mrc_params->params.DENSITY - 1; 334 335 // Address mode can be overwritten if ECC enabled 336 Drp.field.addressMap = mrc_params->address_mode; 337 338 isbW32m(MCU, DRP, Drp.raw); 339 340 Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER 341 Dco.field.IC = 1; //1 - initialisation complete 342 isbW32m(MCU, DCO, Dco.raw); 343 344 LEAVEFN(); 345 } 346 347 // Configure refresh rate and short ZQ calibration interval. 348 // Activate dynamic self refresh. 349 static void change_refresh_period( 350 MRCParams_t *mrc_params) 351 { 352 RegDRCF Drfc; 353 RegDCAL Dcal; 354 RegDPMC0 Dpmc0; 355 356 ENTERFN(); 357 358 Drfc.raw = isbR32m(MCU, DRFC); 359 Drfc.field.tREFI = mrc_params->refresh_rate; 360 Drfc.field.REFDBTCLR = 1; 361 isbW32m(MCU, DRFC, Drfc.raw); 362 363 Dcal.raw = isbR32m(MCU, DCAL); 364 Dcal.field.ZQCINT = 3; // 63ms 365 isbW32m(MCU, DCAL, Dcal.raw); 366 367 Dpmc0.raw = isbR32m(MCU, DPMC0); 368 Dpmc0.field.ENPHYCLKGATE = 1; 369 Dpmc0.field.DYNSREN = 1; 370 isbW32m(MCU, DPMC0, Dpmc0.raw); 371 372 LEAVEFN(); 373 } 374 375 // Send DRAM wake command 376 static void perform_wake( 377 MRCParams_t *mrc_params) 378 { 379 ENTERFN(); 380 381 dram_wake_command(); 382 383 LEAVEFN(); 384 } 385 386 // prog_ddr_timing_control (aka mcu_init): 387 // POST_CODE[major] == 0x02 388 // 389 // It will initialise timing registers in the MCU (DTR0..DTR4). 390 static void prog_ddr_timing_control( 391 MRCParams_t *mrc_params) 392 { 393 uint8_t TCL, WL; 394 uint8_t TRP, TRCD, TRAS, TWR, TWTR, TRRD, TRTP, TFAW; 395 uint32_t TCK; 396 397 RegDTR0 Dtr0; 398 RegDTR1 Dtr1; 399 RegDTR2 Dtr2; 400 RegDTR3 Dtr3; 401 RegDTR4 Dtr4; 402 403 ENTERFN(); 404 405 // mcu_init starts 406 post_code(0x02, 0x00); 407 408 Dtr0.raw = isbR32m(MCU, DTR0); 409 Dtr1.raw = isbR32m(MCU, DTR1); 410 Dtr2.raw = isbR32m(MCU, DTR2); 411 Dtr3.raw = isbR32m(MCU, DTR3); 412 Dtr4.raw = isbR32m(MCU, DTR4); 413 414 TCK = tCK[mrc_params->ddr_speed]; // Clock in picoseconds 415 TCL = mrc_params->params.tCL; // CAS latency in clocks 416 TRP = TCL; // Per CAT MRC 417 TRCD = TCL; // Per CAT MRC 418 TRAS = MCEIL(mrc_params->params.tRAS, TCK); 419 TWR = MCEIL(15000, TCK); // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 420 421 TWTR = MCEIL(mrc_params->params.tWTR, TCK); 422 TRRD = MCEIL(mrc_params->params.tRRD, TCK); 423 TRTP = 4; // Valid for 800 and 1066, use 5 for 1333 424 TFAW = MCEIL(mrc_params->params.tFAW, TCK); 425 426 WL = 5 + mrc_params->ddr_speed; 427 428 Dtr0.field.dramFrequency = mrc_params->ddr_speed; 429 430 Dtr0.field.tCL = TCL - 5; //Convert from TCL (DRAM clocks) to VLV indx 431 Dtr0.field.tRP = TRP - 5; //5 bit DRAM Clock 432 Dtr0.field.tRCD = TRCD - 5; //5 bit DRAM Clock 433 434 Dtr1.field.tWCL = WL - 3; //Convert from WL (DRAM clocks) to VLV indx 435 Dtr1.field.tWTP = WL + 4 + TWR - 14; //Change to tWTP 436 Dtr1.field.tRTP = MMAX(TRTP, 4) - 3; //4 bit DRAM Clock 437 Dtr1.field.tRRD = TRRD - 4; //4 bit DRAM Clock 438 Dtr1.field.tCMD = 1; //2N 439 Dtr1.field.tRAS = TRAS - 14; //6 bit DRAM Clock 440 441 Dtr1.field.tFAW = ((TFAW + 1) >> 1) - 5; //4 bit DRAM Clock 442 Dtr1.field.tCCD = 0; //Set 4 Clock CAS to CAS delay (multi-burst) 443 Dtr2.field.tRRDR = 1; 444 Dtr2.field.tWWDR = 2; 445 Dtr2.field.tRWDR = 2; 446 Dtr3.field.tWRDR = 2; 447 Dtr3.field.tWRDD = 2; 448 449 if (mrc_params->ddr_speed == DDRFREQ_800) 450 { 451 // Extended RW delay (+1) 452 Dtr3.field.tRWSR = TCL - 5 + 1; 453 } 454 else if(mrc_params->ddr_speed == DDRFREQ_1066) 455 { 456 // Extended RW delay (+1) 457 Dtr3.field.tRWSR = TCL - 5 + 1; 458 } 459 460 Dtr3.field.tWRSR = 4 + WL + TWTR - 11; 461 462 if (mrc_params->ddr_speed == DDRFREQ_800) 463 { 464 Dtr3.field.tXP = MMAX(0, 1 - Dtr1.field.tCMD); 465 } 466 else 467 { 468 Dtr3.field.tXP = MMAX(0, 2 - Dtr1.field.tCMD); 469 } 470 471 Dtr4.field.WRODTSTRT = Dtr1.field.tCMD; 472 Dtr4.field.WRODTSTOP = Dtr1.field.tCMD; 473 Dtr4.field.RDODTSTRT = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2; //Convert from WL (DRAM clocks) to VLV indx 474 Dtr4.field.RDODTSTOP = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2; 475 Dtr4.field.TRGSTRDIS = 0; 476 Dtr4.field.ODTDIS = 0; 477 478 isbW32m(MCU, DTR0, Dtr0.raw); 479 isbW32m(MCU, DTR1, Dtr1.raw); 480 isbW32m(MCU, DTR2, Dtr2.raw); 481 isbW32m(MCU, DTR3, Dtr3.raw); 482 isbW32m(MCU, DTR4, Dtr4.raw); 483 484 LEAVEFN(); 485 } 486 487 // ddrphy_init: 488 // POST_CODE[major] == 0x03 489 // 490 // This function performs some initialisation on the DDRIO unit. 491 // This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES. 492 static void ddrphy_init(MRCParams_t *mrc_params) 493 { 494 uint32_t tempD; // temporary DWORD 495 uint8_t channel_i; // channel counter 496 uint8_t rank_i; // rank counter 497 uint8_t bl_grp_i; // byte lane group counter (2 BLs per module) 498 499 uint8_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1; // byte lane divisor 500 uint8_t speed = mrc_params->ddr_speed & (BIT1|BIT0); // For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 501 uint8_t tCAS; 502 uint8_t tCWL; 503 504 ENTERFN(); 505 506 tCAS = mrc_params->params.tCL; 507 tCWL = 5 + mrc_params->ddr_speed; 508 509 // ddrphy_init starts 510 post_code(0x03, 0x00); 511 512 // HSD#231531 513 // Make sure IOBUFACT is deasserted before initialising the DDR PHY. 514 // HSD#234845 515 // Make sure WRPTRENABLE is deasserted before initialising the DDR PHY. 516 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) { 517 if (mrc_params->channel_enables & (1<<channel_i)) { 518 // Deassert DDRPHY Initialisation Complete 519 isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT20, BIT20); // SPID_INIT_COMPLETE=0 520 // Deassert IOBUFACT 521 isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT2, BIT2); // IOBUFACTRST_N=0 522 // Disable WRPTR 523 isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT0, BIT0); // WRPTRENABLE=0 524 } // if channel enabled 525 } // channel_i loop 526 527 // Put PHY in reset 528 isbM32m(DDRPHY, MASTERRSTN, 0, BIT0); // PHYRSTN=0 529 530 // Initialise DQ01,DQ23,CMD,CLK-CTL,COMP modules 531 // STEP0: 532 post_code(0x03, 0x10); 533 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) { 534 if (mrc_params->channel_enables & (1<<channel_i)) { 535 536 // DQ01-DQ23 537 for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) { 538 isbM32m(DDRPHY, (DQOBSCKEBBCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i) ? (0x00) : (BIT22)), (BIT22)); // Analog MUX select - IO2xCLKSEL 539 540 // ODT Strength 541 switch (mrc_params->rd_odt_value) { 542 case 1: tempD = 0x3; break; // 60 ohm 543 case 2: tempD = 0x3; break; // 120 ohm 544 case 3: tempD = 0x3; break; // 180 ohm 545 default: tempD = 0x3; break; // 120 ohm 546 } 547 isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength 548 isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength 549 // Dynamic ODT/DIFFAMP 550 tempD = (((tCAS)<<24)|((tCAS)<<16)|((tCAS)<<8)|((tCAS)<<0)); 551 switch (speed) { 552 case 0: tempD -= 0x01010101; break; // 800 553 case 1: tempD -= 0x02020202; break; // 1066 554 case 2: tempD -= 0x03030303; break; // 1333 555 case 3: tempD -= 0x04040404; break; // 1600 556 } 557 isbM32m(DDRPHY, (B01LATCTL1 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // Launch Time: ODT, DIFFAMP, ODT, DIFFAMP 558 switch (speed) { 559 // HSD#234715 560 case 0: tempD = ((0x06<<16)|(0x07<<8)); break; // 800 561 case 1: tempD = ((0x07<<16)|(0x08<<8)); break; // 1066 562 case 2: tempD = ((0x09<<16)|(0x0A<<8)); break; // 1333 563 case 3: tempD = ((0x0A<<16)|(0x0B<<8)); break; // 1600 564 } 565 isbM32m(DDRPHY, (B0ONDURCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8))); // On Duration: ODT, DIFFAMP 566 isbM32m(DDRPHY, (B1ONDURCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8))); // On Duration: ODT, DIFFAMP 567 568 switch (mrc_params->rd_odt_value) { 569 case 0: tempD = ((0x3F<<16)|(0x3f<<10)); break; // override DIFFAMP=on, ODT=off 570 default: tempD = ((0x3F<<16)|(0x2A<<10)); break; // override DIFFAMP=on, ODT=on 571 } 572 isbM32m(DDRPHY, (B0OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT 573 isbM32m(DDRPHY, (B1OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT 574 575 // DLL Setup 576 // 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO) 577 isbM32m(DDRPHY, (B0LATCTL0 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (((tCAS+7)<<16)|((tCAS-4)<<8)|((tCWL-2)<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // 1xCLK: tEDP, RCVEN, WDQS 578 isbM32m(DDRPHY, (B1LATCTL0 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (((tCAS+7)<<16)|((tCAS-4)<<8)|((tCWL-2)<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // 1xCLK: tEDP, RCVEN, WDQS 579 580 // RCVEN Bypass (PO) 581 isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP 582 isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP 583 // TX 584 isbM32m(DDRPHY, (DQCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT16), (BIT16)); // 0 means driving DQ during DQS-preamble 585 isbM32m(DDRPHY, (B01PTRCTL1 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT8), (BIT8)); // WR_LVL mode disable 586 // RX (PO) 587 isbM32m(DDRPHY, (B0VREFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x03<<2)|(0x0<<1)|(0x0<<0)), ((BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|BIT1|BIT0)); // Internal Vref Code, Enable#, Ext_or_Int (1=Ext) 588 isbM32m(DDRPHY, (B1VREFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x03<<2)|(0x0<<1)|(0x0<<0)), ((BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|BIT1|BIT0)); // Internal Vref Code, Enable#, Ext_or_Int (1=Ext) 589 isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable 590 isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable 591 } 592 // CLKEBB 593 isbM32m(DDRPHY, (CMDOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT23)); 594 595 // Enable tristate control of cmd/address bus 596 isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT1|BIT0)); 597 598 // ODT RCOMP 599 isbM32m(DDRPHY, (CMDRCOMPODT + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<5)|(0x03<<0)), ((BIT9|BIT8|BIT7|BIT6|BIT5)|(BIT4|BIT3|BIT2|BIT1|BIT0))); 600 601 // CMDPM* registers must be programmed in this order... 602 isbM32m(DDRPHY, (CMDPMDLYREG4 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFFFU<<16)|(0xFFFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8|BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn On Delays: SFR (regulator), MPLL 603 isbM32m(DDRPHY, (CMDPMDLYREG3 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFU<<28)|(0xFFF<<16)|(0xF<<12)|(0x616<<0)), ((BIT31|BIT30|BIT29|BIT28)|(BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8|BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3, VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT_for_PM_MSG_gt0, MDLL Turn On 604 isbM32m(DDRPHY, (CMDPMDLYREG2 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // MPLL Divider Reset Delays 605 isbM32m(DDRPHY, (CMDPMDLYREG1 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn Off Delays: VREG, Staggered MDLL, MDLL, PI 606 isbM32m(DDRPHY, (CMDPMDLYREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT 607 isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x6<<8)|BIT6|(0x4<<0)), (BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|(BIT11|BIT10|BIT9|BIT8)|BIT6|(BIT3|BIT2|BIT1|BIT0))); // Allow PUnit signals 608 isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x3<<4)|(0x7<<0)), ((BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DLL_VREG Bias Trim, VREF Tuning for DLL_VREG 609 // CLK-CTL 610 isbM32m(DDRPHY, (CCOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT24)); // CLKEBB 611 isbM32m(DDRPHY, (CCCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x0<<16)|(0x0<<12)|(0x0<<8)|(0xF<<4)|BIT0), ((BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|BIT0)); // Buffer Enable: CS,CKE,ODT,CLK 612 isbM32m(DDRPHY, (CCRCOMPODT + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<8)|(0x03<<0)), ((BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT RCOMP 613 isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x3<<4)|(0x7<<0)), ((BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DLL_VREG Bias Trim, VREF Tuning for DLL_VREG 614 615 // COMP (RON channel specific) 616 // - DQ/DQS/DM RON: 32 Ohm 617 // - CTRL/CMD RON: 27 Ohm 618 // - CLK RON: 26 Ohm 619 isbM32m(DDRPHY, (DQVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x08<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD 620 isbM32m(DDRPHY, (CMDVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0C<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD 621 isbM32m(DDRPHY, (CLKVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0F<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD 622 isbM32m(DDRPHY, (DQSVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x08<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD 623 isbM32m(DDRPHY, (CTLVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0C<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD 624 625 // DQS Swapped Input Enable 626 isbM32m(DDRPHY, (COMPEN1CH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT19|BIT17), ((BIT31|BIT30)|BIT19|BIT17|(BIT15|BIT14))); 627 628 // ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50) 629 isbM32m(DDRPHY, (DQVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x32<<8)|(0x03<<0)), ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD 630 isbM32m(DDRPHY, (DQSVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x32<<8)|(0x03<<0)), ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD 631 isbM32m(DDRPHY, (CLKVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0E<<8)|(0x05<<0)), ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD 632 633 // Slew rate settings are frequency specific, numbers below are for 800Mhz (speed == 0) 634 // - DQ/DQS/DM/CLK SR: 4V/ns, 635 // - CTRL/CMD SR: 1.5V/ns 636 tempD = (0x0E<<16)|(0x0E<<12)|(0x08<<8)|(0x0B<<4)|(0x0B<<0); 637 isbM32m(DDRPHY, (DLYSELCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (tempD), ((BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ 638 isbM32m(DDRPHY, (TCOVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x05<<16)|(0x05<<8)|(0x05<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // TCO Vref CLK,DQS,DQ 639 isbM32m(DDRPHY, (CCBUFODTCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x03<<8)|(0x03<<0)), ((BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // ODTCOMP CMD/CTL PU/PD 640 isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), (0), ((BIT31|BIT30)|BIT8)); // COMP 641 642 #ifdef BACKUP_COMPS 643 // DQ COMP Overrides 644 isbM32m(DDRPHY, (DQDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU 645 isbM32m(DDRPHY, (DQDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD 646 isbM32m(DDRPHY, (DQDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU 647 isbM32m(DDRPHY, (DQDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD 648 isbM32m(DDRPHY, (DQODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU 649 isbM32m(DDRPHY, (DQODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD 650 isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU 651 isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD 652 // DQS COMP Overrides 653 isbM32m(DDRPHY, (DQSDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU 654 isbM32m(DDRPHY, (DQSDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD 655 isbM32m(DDRPHY, (DQSDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU 656 isbM32m(DDRPHY, (DQSDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD 657 isbM32m(DDRPHY, (DQSODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU 658 isbM32m(DDRPHY, (DQSODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD 659 isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU 660 isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD 661 // CLK COMP Overrides 662 isbM32m(DDRPHY, (CLKDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU 663 isbM32m(DDRPHY, (CLKDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD 664 isbM32m(DDRPHY, (CLKDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU 665 isbM32m(DDRPHY, (CLKDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD 666 isbM32m(DDRPHY, (CLKODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU 667 isbM32m(DDRPHY, (CLKODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD 668 isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU 669 isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD 670 // CMD COMP Overrides 671 isbM32m(DDRPHY, (CMDDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU 672 isbM32m(DDRPHY, (CMDDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD 673 isbM32m(DDRPHY, (CMDDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU 674 isbM32m(DDRPHY, (CMDDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD 675 // CTL COMP Overrides 676 isbM32m(DDRPHY, (CTLDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU 677 isbM32m(DDRPHY, (CTLDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD 678 isbM32m(DDRPHY, (CTLDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU 679 isbM32m(DDRPHY, (CTLDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD 680 #else 681 // DQ TCOCOMP Overrides 682 isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU 683 isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD 684 // DQS TCOCOMP Overrides 685 isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU 686 isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD 687 // CLK TCOCOMP Overrides 688 isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU 689 isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD 690 #endif // BACKUP_COMPS 691 // program STATIC delays 692 #ifdef BACKUP_WCMD 693 set_wcmd(channel_i, ddr_wcmd[PLATFORM_ID]); 694 #else 695 set_wcmd(channel_i, ddr_wclk[PLATFORM_ID] + HALF_CLK); 696 #endif // BACKUP_WCMD 697 for (rank_i=0; rank_i<NUM_RANKS; rank_i++) { 698 if (mrc_params->rank_enables & (1<<rank_i)) { 699 set_wclk(channel_i, rank_i, ddr_wclk[PLATFORM_ID]); 700 #ifdef BACKUP_WCTL 701 set_wctl(channel_i, rank_i, ddr_wctl[PLATFORM_ID]); 702 #else 703 set_wctl(channel_i, rank_i, ddr_wclk[PLATFORM_ID] + HALF_CLK); 704 #endif // BACKUP_WCTL 705 } 706 } 707 } 708 } 709 // COMP (non channel specific) 710 //isbM32m(DDRPHY, (), (), ()); 711 isbM32m(DDRPHY, (DQANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable 712 isbM32m(DDRPHY, (DQANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable 713 isbM32m(DDRPHY, (CMDANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable 714 isbM32m(DDRPHY, (CMDANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable 715 isbM32m(DDRPHY, (CLKANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable 716 isbM32m(DDRPHY, (CLKANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable 717 isbM32m(DDRPHY, (DQSANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable 718 isbM32m(DDRPHY, (DQSANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable 719 isbM32m(DDRPHY, (CTLANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable 720 isbM32m(DDRPHY, (CTLANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable 721 isbM32m(DDRPHY, (DQANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable 722 isbM32m(DDRPHY, (DQANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable 723 isbM32m(DDRPHY, (CLKANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable 724 isbM32m(DDRPHY, (CLKANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable 725 isbM32m(DDRPHY, (DQSANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable 726 isbM32m(DDRPHY, (DQSANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable 727 isbM32m(DDRPHY, (DQANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable 728 isbM32m(DDRPHY, (DQANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable 729 isbM32m(DDRPHY, (CMDANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable 730 isbM32m(DDRPHY, (CMDANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable 731 isbM32m(DDRPHY, (CLKANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable 732 isbM32m(DDRPHY, (CLKANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable 733 isbM32m(DDRPHY, (DQSANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable 734 isbM32m(DDRPHY, (DQSANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable 735 isbM32m(DDRPHY, (CTLANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable 736 isbM32m(DDRPHY, (CTLANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable 737 isbM32m(DDRPHY, (DQANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable 738 isbM32m(DDRPHY, (DQANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable 739 isbM32m(DDRPHY, (CLKANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable 740 isbM32m(DDRPHY, (CLKANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable 741 isbM32m(DDRPHY, (DQSANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable 742 isbM32m(DDRPHY, (DQSANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable 743 isbM32m(DDRPHY, (TCOCNTCTRL), (0x1<<0), (BIT1|BIT0)); // TCOCOMP: Pulse Count 744 isbM32m(DDRPHY, (CHNLBUFSTATIC), ((0x03<<24)|(0x03<<16)), ((BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODT: CMD/CTL PD/PU 745 isbM32m(DDRPHY, (MSCNTR), (0x64<<0), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0)); // Set 1us counter 746 isbM32m(DDRPHY, (LATCH1CTL), (0x1<<28), (BIT30|BIT29|BIT28)); // ??? 747 748 // Release PHY from reset 749 isbM32m(DDRPHY, MASTERRSTN, BIT0, BIT0); // PHYRSTN=1 750 751 // STEP1: 752 post_code(0x03, 0x11); 753 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) { 754 if (mrc_params->channel_enables & (1<<channel_i)) { 755 // DQ01-DQ23 756 for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) { 757 isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG 758 delay_n(3); 759 } 760 // ECC 761 isbM32m(DDRPHY, (ECCMDLLCTL), (BIT13), (BIT13)); // Enable VREG 762 delay_n(3); 763 // CMD 764 isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG 765 delay_n(3); 766 // CLK-CTL 767 isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG 768 delay_n(3); 769 } 770 } 771 772 // STEP2: 773 post_code(0x03, 0x12); 774 delay_n(200); 775 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) { 776 if (mrc_params->channel_enables & (1<<channel_i)) { 777 // DQ01-DQ23 778 for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) { 779 isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT17), (BIT17)); // Enable MCDLL 780 delay_n(50); 781 } 782 // ECC 783 isbM32m(DDRPHY, (ECCMDLLCTL), (BIT17), (BIT17)); // Enable MCDLL 784 delay_n(50); 785 // CMD 786 isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL 787 delay_n(50); 788 // CLK-CTL 789 isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL 790 delay_n(50); 791 } 792 } 793 794 // STEP3: 795 post_code(0x03, 0x13); 796 delay_n(100); 797 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) { 798 if (mrc_params->channel_enables & (1<<channel_i)) { 799 // DQ01-DQ23 800 for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) { 801 #ifdef FORCE_16BIT_DDRIO 802 tempD = ((bl_grp_i) && (mrc_params->channel_width == x16)) ? ((0x1<<12)|(0x1<<8)|(0xF<<4)|(0xF<<0)) : ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0)); 803 #else 804 tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0)); 805 #endif 806 isbM32m(DDRPHY, (DQDLLTXCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL 807 delay_n(3); 808 isbM32m(DDRPHY, (DQDLLRXCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT3|BIT2|BIT1|BIT0), (BIT3|BIT2|BIT1|BIT0)); // Enable RXDLL 809 delay_n(3); 810 isbM32m(DDRPHY, (B0OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT3|BIT2|BIT1|BIT0), (BIT3|BIT2|BIT1|BIT0)); // Enable RXDLL Overrides BL0 811 } 812 813 // ECC 814 tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0)); 815 isbM32m(DDRPHY, (ECCDLLTXCTL), (tempD), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL 816 delay_n(3); 817 818 // CMD (PO) 819 isbM32m(DDRPHY, (CMDDLLTXCTL + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0)), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL 820 delay_n(3); 821 } 822 } 823 824 825 // STEP4: 826 post_code(0x03, 0x14); 827 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) { 828 if (mrc_params->channel_enables & (1<<channel_i)) { 829 // Host To Memory Clock Alignment (HMC) for 800/1066 830 for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) { 831 isbM32m(DDRPHY, (DQCLKALIGNREG2 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i)?(0x3):(0x1)), (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID 832 } 833 isbM32m(DDRPHY, (ECCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID 834 isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x0, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID 835 isbM32m(DDRPHY, (CCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID 836 isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), (0x2<<4), (BIT5|BIT4)); // CLK_ALIGN_MODE 837 isbM32m(DDRPHY, (CMDCLKALIGNREG1 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x18<<16)|(0x10<<8)|(0x8<<2)|(0x1<<0)), ((BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|(BIT1|BIT0))); // NUM_SAMPLES, MAX_SAMPLES, MACRO_PI_STEP, MICRO_PI_STEP 838 isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x10<<16)|(0x4<<8)|(0x2<<4)), ((BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4))); // ???, TOTAL_NUM_MODULES, FIRST_U_PARTITION 839 #ifdef HMC_TEST 840 isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT24, BIT24); // START_CLK_ALIGN=1 841 while (isbR32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET))) & BIT24); // wait for START_CLK_ALIGN=0 842 #endif // HMC_TEST 843 844 // Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN 845 isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), BIT0, BIT0); // WRPTRENABLE=1 846 847 848 #ifdef SIM 849 // comp is not working on simulator 850 #else 851 // COMP initial 852 isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), BIT5, BIT5); // enable bypass for CLK buffer (PO) 853 isbM32m(DDRPHY, (CMPCTRL), (BIT0), (BIT0)); // Initial COMP Enable 854 while (isbR32m(DDRPHY, (CMPCTRL)) & BIT0); // wait for Initial COMP Enable = 0 855 isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), ~BIT5, BIT5); // disable bypass for CLK buffer (PO) 856 #endif 857 858 // IOBUFACT 859 // STEP4a 860 isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT2, BIT2); // IOBUFACTRST_N=1 861 862 // DDRPHY initialisation complete 863 isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT20, BIT20); // SPID_INIT_COMPLETE=1 864 } 865 } 866 867 LEAVEFN(); 868 return; 869 } 870 871 // jedec_init (aka PerformJedecInit): 872 // This function performs JEDEC initialisation on all enabled channels. 873 static void jedec_init( 874 MRCParams_t *mrc_params, 875 uint32_t silent) 876 { 877 uint8_t TWR, WL, Rank; 878 uint32_t TCK; 879 880 RegDTR0 DTR0reg; 881 882 DramInitDDR3MRS0 mrs0Command; 883 DramInitDDR3EMR1 emrs1Command; 884 DramInitDDR3EMR2 emrs2Command; 885 DramInitDDR3EMR3 emrs3Command; 886 887 ENTERFN(); 888 889 // jedec_init starts 890 if (!silent) 891 { 892 post_code(0x04, 0x00); 893 } 894 895 // Assert RESET# for 200us 896 isbM32m(DDRPHY, CCDDR3RESETCTL, BIT1, (BIT8|BIT1)); // DDR3_RESET_SET=0, DDR3_RESET_RESET=1 897 #ifdef QUICKSIM 898 // Don't waste time during simulation 899 delay_u(2); 900 #else 901 delay_u(200); 902 #endif 903 isbM32m(DDRPHY, CCDDR3RESETCTL, BIT8, (BIT8|BIT1)); // DDR3_RESET_SET=1, DDR3_RESET_RESET=0 904 905 DTR0reg.raw = isbR32m(MCU, DTR0); 906 907 // Set CKEVAL for populated ranks 908 // then send NOP to each rank (#4550197) 909 { 910 uint32_t DRPbuffer; 911 uint32_t DRMCbuffer; 912 913 DRPbuffer = isbR32m(MCU, DRP); 914 DRPbuffer &= 0x3; 915 DRMCbuffer = isbR32m(MCU, DRMC); 916 DRMCbuffer &= 0xFFFFFFFC; 917 DRMCbuffer |= (BIT4 | DRPbuffer); 918 919 isbW32m(MCU, DRMC, DRMCbuffer); 920 921 for (Rank = 0; Rank < NUM_RANKS; Rank++) 922 { 923 // Skip to next populated rank 924 if ((mrc_params->rank_enables & (1 << Rank)) == 0) 925 { 926 continue; 927 } 928 929 dram_init_command(DCMD_NOP(Rank)); 930 } 931 932 isbW32m(MCU, DRMC, DRMC_DEFAULT); 933 } 934 935 // setup for emrs 2 936 // BIT[15:11] --> Always "0" 937 // BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0) 938 // BIT[08] --> Always "0" 939 // BIT[07] --> SRT: use sr_temp_range 940 // BIT[06] --> ASR: want "Manual SR Reference" (0) 941 // BIT[05:03] --> CWL: use oem_tCWL 942 // BIT[02:00] --> PASR: want "Full Array" (0) 943 emrs2Command.raw = 0; 944 emrs2Command.field.bankAddress = 2; 945 946 WL = 5 + mrc_params->ddr_speed; 947 emrs2Command.field.CWL = WL - 5; 948 emrs2Command.field.SRT = mrc_params->sr_temp_range; 949 950 // setup for emrs 3 951 // BIT[15:03] --> Always "0" 952 // BIT[02] --> MPR: want "Normal Operation" (0) 953 // BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0) 954 emrs3Command.raw = 0; 955 emrs3Command.field.bankAddress = 3; 956 957 // setup for emrs 1 958 // BIT[15:13] --> Always "0" 959 // BIT[12:12] --> Qoff: want "Output Buffer Enabled" (0) 960 // BIT[11:11] --> TDQS: want "Disabled" (0) 961 // BIT[10:10] --> Always "0" 962 // BIT[09,06,02] --> Rtt_nom: use rtt_nom_value 963 // BIT[08] --> Always "0" 964 // BIT[07] --> WR_LVL: want "Disabled" (0) 965 // BIT[05,01] --> DIC: use ron_value 966 // BIT[04:03] --> AL: additive latency want "0" (0) 967 // BIT[00] --> DLL: want "Enable" (0) 968 // 969 // (BIT5|BIT1) set Ron value 970 // 00 --> RZQ/6 (40ohm) 971 // 01 --> RZQ/7 (34ohm) 972 // 1* --> RESERVED 973 // 974 // (BIT9|BIT6|BIT2) set Rtt_nom value 975 // 000 --> Disabled 976 // 001 --> RZQ/4 ( 60ohm) 977 // 010 --> RZQ/2 (120ohm) 978 // 011 --> RZQ/6 ( 40ohm) 979 // 1** --> RESERVED 980 emrs1Command.raw = 0; 981 emrs1Command.field.bankAddress = 1; 982 emrs1Command.field.dllEnabled = 0; // 0 = Enable , 1 = Disable 983 984 if (mrc_params->ron_value == 0) 985 { 986 emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_34; 987 } 988 else 989 { 990 emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_40; 991 } 992 993 994 if (mrc_params->rtt_nom_value == 0) 995 { 996 emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_40 << 6); 997 } 998 else if (mrc_params->rtt_nom_value == 1) 999 { 1000 emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_60 << 6); 1001 } 1002 else if (mrc_params->rtt_nom_value == 2) 1003 { 1004 emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_120 << 6); 1005 } 1006 1007 // save MRS1 value (excluding control fields) 1008 mrc_params->mrs1 = emrs1Command.raw >> 6; 1009 1010 // setup for mrs 0 1011 // BIT[15:13] --> Always "0" 1012 // BIT[12] --> PPD: for Quark (1) 1013 // BIT[11:09] --> WR: use oem_tWR 1014 // BIT[08] --> DLL: want "Reset" (1, self clearing) 1015 // BIT[07] --> MODE: want "Normal" (0) 1016 // BIT[06:04,02] --> CL: use oem_tCAS 1017 // BIT[03] --> RD_BURST_TYPE: want "Interleave" (1) 1018 // BIT[01:00] --> BL: want "8 Fixed" (0) 1019 // WR: 1020 // 0 --> 16 1021 // 1 --> 5 1022 // 2 --> 6 1023 // 3 --> 7 1024 // 4 --> 8 1025 // 5 --> 10 1026 // 6 --> 12 1027 // 7 --> 14 1028 // CL: 1029 // BIT[02:02] "0" if oem_tCAS <= 11 (1866?) 1030 // BIT[06:04] use oem_tCAS-4 1031 mrs0Command.raw = 0; 1032 mrs0Command.field.bankAddress = 0; 1033 mrs0Command.field.dllReset = 1; 1034 mrs0Command.field.BL = 0; 1035 mrs0Command.field.PPD = 1; 1036 mrs0Command.field.casLatency = DTR0reg.field.tCL + 1; 1037 1038 TCK = tCK[mrc_params->ddr_speed]; 1039 TWR = MCEIL(15000, TCK); // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 1040 mrs0Command.field.writeRecovery = TWR - 4; 1041 1042 for (Rank = 0; Rank < NUM_RANKS; Rank++) 1043 { 1044 // Skip to next populated rank 1045 if ((mrc_params->rank_enables & (1 << Rank)) == 0) 1046 { 1047 continue; 1048 } 1049 1050 emrs2Command.field.rankSelect = Rank; 1051 dram_init_command(emrs2Command.raw); 1052 1053 emrs3Command.field.rankSelect = Rank; 1054 dram_init_command(emrs3Command.raw); 1055 1056 emrs1Command.field.rankSelect = Rank; 1057 dram_init_command(emrs1Command.raw); 1058 1059 mrs0Command.field.rankSelect = Rank; 1060 dram_init_command(mrs0Command.raw); 1061 1062 dram_init_command(DCMD_ZQCL(Rank)); 1063 } 1064 1065 LEAVEFN(); 1066 return; 1067 } 1068 1069 // rcvn_cal: 1070 // POST_CODE[major] == 0x05 1071 // 1072 // This function will perform our RCVEN Calibration Algorithm. 1073 // We will only use the 2xCLK domain timings to perform RCVEN Calibration. 1074 // All byte lanes will be calibrated "simultaneously" per channel per rank. 1075 static void rcvn_cal( 1076 MRCParams_t *mrc_params) 1077 { 1078 uint8_t channel_i; // channel counter 1079 uint8_t rank_i; // rank counter 1080 uint8_t bl_i; // byte lane counter 1081 uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor 1082 1083 #ifdef R2R_SHARING 1084 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs 1085 #ifndef BACKUP_RCVN 1086 uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs 1087 #endif // BACKUP_RCVN 1088 #endif // R2R_SHARING 1089 1090 #ifdef BACKUP_RCVN 1091 #else 1092 uint32_t tempD; // temporary DWORD 1093 uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane 1094 RegDTR1 dtr1; 1095 RegDTR1 dtr1save; 1096 #endif // BACKUP_RCVN 1097 ENTERFN(); 1098 1099 // rcvn_cal starts 1100 post_code(0x05, 0x00); 1101 1102 #ifndef BACKUP_RCVN 1103 // need separate burst to sample DQS preamble 1104 dtr1.raw = dtr1save.raw = isbR32m(MCU, DTR1); 1105 dtr1.field.tCCD = 1; 1106 isbW32m(MCU, DTR1, dtr1.raw); 1107 #endif 1108 1109 #ifdef R2R_SHARING 1110 // need to set "final_delay[][]" elements to "0" 1111 memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay)); 1112 #endif // R2R_SHARING 1113 1114 // loop through each enabled channel 1115 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1116 { 1117 if (mrc_params->channel_enables & (1 << channel_i)) 1118 { 1119 // perform RCVEN Calibration on a per rank basis 1120 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1121 { 1122 if (mrc_params->rank_enables & (1 << rank_i)) 1123 { 1124 // POST_CODE here indicates the current channel and rank being calibrated 1125 post_code(0x05, (0x10 + ((channel_i << 4) | rank_i))); 1126 1127 #ifdef BACKUP_RCVN 1128 // set hard-coded timing values 1129 for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++) 1130 { 1131 set_rcvn(channel_i, rank_i, bl_i, ddr_rcvn[PLATFORM_ID]); 1132 } 1133 #else 1134 // enable FIFORST 1135 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2) 1136 { 1137 isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), 0, 1138 BIT8); // 0 is enabled 1139 } // bl_i loop 1140 // initialise the starting delay to 128 PI (tCAS +1 CLK) 1141 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1142 { 1143 #ifdef SIM 1144 // Original value was late at the end of DQS sequence 1145 delay[bl_i] = 3 * FULL_CLK; 1146 #else 1147 delay[bl_i] = (4 + 1) * FULL_CLK; // 1x CLK domain timing is tCAS-4 1148 #endif 1149 1150 set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]); 1151 } // bl_i loop 1152 1153 // now find the rising edge 1154 find_rising_edge(mrc_params, delay, channel_i, rank_i, true); 1155 // Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse. 1156 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1157 { 1158 delay[bl_i] += QRTR_CLK; 1159 set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]); 1160 } // bl_i loop 1161 // Now decrement delay by 128 PI (1 CLK) until we sample a "0" 1162 do 1163 { 1164 1165 tempD = sample_dqs(mrc_params, channel_i, rank_i, true); 1166 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1167 { 1168 if (tempD & (1 << bl_i)) 1169 { 1170 if (delay[bl_i] >= FULL_CLK) 1171 { 1172 delay[bl_i] -= FULL_CLK; 1173 set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]); 1174 } 1175 else 1176 { 1177 // not enough delay 1178 training_message(channel_i, rank_i, bl_i); 1179 post_code(0xEE, 0x50); 1180 } 1181 } 1182 } // bl_i loop 1183 } while (tempD & 0xFF); 1184 1185 #ifdef R2R_SHARING 1186 // increment "num_ranks_enabled" 1187 num_ranks_enabled++; 1188 // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble. 1189 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1190 { 1191 delay[bl_i] += QRTR_CLK; 1192 // add "delay[]" values to "final_delay[][]" for rolling average 1193 final_delay[channel_i][bl_i] += delay[bl_i]; 1194 // set timing based on rolling average values 1195 set_rcvn(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled)); 1196 } // bl_i loop 1197 #else 1198 // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble. 1199 for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++) 1200 { 1201 delay[bl_i] += QRTR_CLK; 1202 set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]); 1203 } // bl_i loop 1204 1205 #endif // R2R_SHARING 1206 1207 // disable FIFORST 1208 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2) 1209 { 1210 isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), BIT8, 1211 BIT8); // 1 is disabled 1212 } // bl_i loop 1213 1214 #endif // BACKUP_RCVN 1215 1216 } // if rank is enabled 1217 } // rank_i loop 1218 } // if channel is enabled 1219 } // channel_i loop 1220 1221 #ifndef BACKUP_RCVN 1222 // restore original 1223 isbW32m(MCU, DTR1, dtr1save.raw); 1224 #endif 1225 1226 #ifdef MRC_SV 1227 if (mrc_params->tune_rcvn) 1228 { 1229 uint32_t rcven, val; 1230 uint32_t rdcmd2rcven; 1231 1232 /* 1233 Formulas for RDCMD2DATAVALID & DIFFAMP dynamic timings 1234 1235 1. Set after RCVEN training 1236 1237 //Tune RDCMD2DATAVALID 1238 1239 x80/x84[21:16] 1240 MAX OF 2 RANKS : round up (rdcmd2rcven (rcven 1x) + 2x x 2 + PI/128) + 5 1241 1242 //rdcmd2rcven x80/84[12:8] 1243 //rcven 2x x70[23:20] & [11:8] 1244 1245 //Tune DIFFAMP Timings 1246 1247 //diffampen launch x88[20:16] & [4:0] -- B01LATCTL1 1248 MIN OF 2 RANKS : round down (rcven 1x + 2x x 2 + PI/128) - 1 1249 1250 //diffampen length x8C/x90 [13:8] -- B0ONDURCTL B1ONDURCTL 1251 MAX OF 2 RANKS : roundup (rcven 1x + 2x x 2 + PI/128) + 5 1252 1253 1254 2. need to do a fiforst after settings these values 1255 */ 1256 1257 DPF(D_INFO, "BEFORE\n"); 1258 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0)); 1259 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1)); 1260 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL)); 1261 1262 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0)); 1263 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL)); 1264 1265 rcven = get_rcvn(0, 0, 0) / 128; 1266 rdcmd2rcven = (isbR32m(DDRPHY, B0LATCTL0) >> 8) & 0x1F; 1267 val = rdcmd2rcven + rcven + 6; 1268 isbM32m(DDRPHY, B0LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)); 1269 1270 val = rdcmd2rcven + rcven - 1; 1271 isbM32m(DDRPHY, B01LATCTL1, val << 0, (BIT4|BIT3|BIT2|BIT1|BIT0)); 1272 1273 val = rdcmd2rcven + rcven + 5; 1274 isbM32m(DDRPHY, B0ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)); 1275 1276 rcven = get_rcvn(0, 0, 1) / 128; 1277 rdcmd2rcven = (isbR32m(DDRPHY, B1LATCTL0) >> 8) & 0x1F; 1278 val = rdcmd2rcven + rcven + 6; 1279 isbM32m(DDRPHY, B1LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)); 1280 1281 val = rdcmd2rcven + rcven - 1; 1282 isbM32m(DDRPHY, B01LATCTL1, val << 16, (BIT20|BIT19|BIT18|BIT17|BIT16)); 1283 1284 val = rdcmd2rcven + rcven + 5; 1285 isbM32m(DDRPHY, B1ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)); 1286 1287 DPF(D_INFO, "AFTER\n"); 1288 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0)); 1289 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1)); 1290 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL)); 1291 1292 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0)); 1293 DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL)); 1294 1295 DPF(D_INFO, "\nPress a key\n"); 1296 mgetc(); 1297 1298 // fifo reset 1299 isbM32m(DDRPHY, B01PTRCTL1, 0, BIT8); // 0 is enabled 1300 delay_n(3); 1301 isbM32m(DDRPHY, B01PTRCTL1, BIT8, BIT8); // 1 is disabled 1302 } 1303 #endif 1304 1305 LEAVEFN(); 1306 return; 1307 } 1308 1309 // Check memory executing write/read/verify of many data patterns 1310 // at the specified address. Bits in the result indicate failure 1311 // on specific byte lane. 1312 static uint32_t check_bls_ex( 1313 MRCParams_t *mrc_params, 1314 uint32_t address) 1315 { 1316 uint32_t result; 1317 uint8_t first_run = 0; 1318 1319 if (mrc_params->hte_setup) 1320 { 1321 mrc_params->hte_setup = 0; 1322 1323 first_run = 1; 1324 select_hte(mrc_params); 1325 } 1326 1327 result = WriteStressBitLanesHTE(mrc_params, address, first_run); 1328 1329 DPF(D_TRN, "check_bls_ex result is %x\n", result); 1330 return result; 1331 } 1332 1333 // Check memory executing simple write/read/verify at 1334 // the specified address. Bits in the result indicate failure 1335 // on specific byte lane. 1336 static uint32_t check_rw_coarse( 1337 MRCParams_t *mrc_params, 1338 uint32_t address) 1339 { 1340 uint32_t result = 0; 1341 uint8_t first_run = 0; 1342 1343 if (mrc_params->hte_setup) 1344 { 1345 mrc_params->hte_setup = 0; 1346 1347 first_run = 1; 1348 select_hte(mrc_params); 1349 } 1350 1351 result = BasicWriteReadHTE(mrc_params, address, first_run, WRITE_TRAIN); 1352 1353 DPF(D_TRN, "check_rw_coarse result is %x\n", result); 1354 return result; 1355 } 1356 1357 // wr_level: 1358 // POST_CODE[major] == 0x06 1359 // 1360 // This function will perform the Write Levelling algorithm (align WCLK and WDQS). 1361 // This algorithm will act on each rank in each channel separately. 1362 static void wr_level( 1363 MRCParams_t *mrc_params) 1364 { 1365 uint8_t channel_i; // channel counter 1366 uint8_t rank_i; // rank counter 1367 uint8_t bl_i; // byte lane counter 1368 uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor 1369 1370 #ifdef R2R_SHARING 1371 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs 1372 #ifndef BACKUP_WDQS 1373 uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs 1374 #endif // BACKUP_WDQS 1375 #endif // R2R_SHARING 1376 1377 #ifdef BACKUP_WDQS 1378 #else 1379 bool all_edges_found; // determines stop condition for CRS_WR_LVL 1380 uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane 1381 // static makes it so the data is loaded in the heap once by shadow(), where 1382 // non-static copies the data onto the stack every time this function is called. 1383 1384 uint32_t address; // address to be checked during COARSE_WR_LVL 1385 RegDTR4 dtr4; 1386 RegDTR4 dtr4save; 1387 #endif // BACKUP_WDQS 1388 1389 ENTERFN(); 1390 1391 // wr_level starts 1392 post_code(0x06, 0x00); 1393 1394 #ifdef R2R_SHARING 1395 // need to set "final_delay[][]" elements to "0" 1396 memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay)); 1397 #endif // R2R_SHARING 1398 // loop through each enabled channel 1399 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1400 { 1401 if (mrc_params->channel_enables & (1 << channel_i)) 1402 { 1403 // perform WRITE LEVELING algorithm on a per rank basis 1404 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1405 { 1406 if (mrc_params->rank_enables & (1 << rank_i)) 1407 { 1408 // POST_CODE here indicates the current rank and channel being calibrated 1409 post_code(0x06, (0x10 + ((channel_i << 4) | rank_i))); 1410 1411 #ifdef BACKUP_WDQS 1412 for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++) 1413 { 1414 set_wdqs(channel_i, rank_i, bl_i, ddr_wdqs[PLATFORM_ID]); 1415 set_wdq(channel_i, rank_i, bl_i, (ddr_wdqs[PLATFORM_ID] - QRTR_CLK)); 1416 } 1417 #else 1418 1419 { // Begin product specific code 1420 1421 // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state 1422 dram_init_command(DCMD_PREA(rank_i)); 1423 1424 // enable Write Levelling Mode (EMRS1 w/ Write Levelling Mode Enable) 1425 dram_init_command(DCMD_MRS1(rank_i,0x0082)); 1426 1427 // set ODT DRAM Full Time Termination disable in MCU 1428 dtr4.raw = dtr4save.raw = isbR32m(MCU, DTR4); 1429 dtr4.field.ODTDIS = 1; 1430 isbW32m(MCU, DTR4, dtr4.raw); 1431 1432 for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++) 1433 { 1434 isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i), 1435 (BIT28 | (0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)), 1436 (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Enable Sandy Bridge Mode (WDQ Tri-State) & Ensure 5 WDQS pulses during Write Leveling 1437 } 1438 1439 isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (BIT16), (BIT16)); // Write Leveling Mode enabled in IO 1440 } // End product specific code 1441 // Initialise the starting delay to WCLK 1442 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1443 { 1444 { // Begin product specific code 1445 // CLK0 --> RK0 1446 // CLK1 --> RK1 1447 delay[bl_i] = get_wclk(channel_i, rank_i); 1448 } // End product specific code 1449 set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]); 1450 } // bl_i loop 1451 // now find the rising edge 1452 find_rising_edge(mrc_params, delay, channel_i, rank_i, false); 1453 { // Begin product specific code 1454 // disable Write Levelling Mode 1455 isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (0), (BIT16)); // Write Leveling Mode disabled in IO 1456 1457 for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++) 1458 { 1459 isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i), 1460 ((0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)), 1461 (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation 1462 } // bl_i loop 1463 1464 // restore original DTR4 1465 isbW32m(MCU, DTR4, dtr4save.raw); 1466 1467 // restore original value (Write Levelling Mode Disable) 1468 dram_init_command(DCMD_MRS1(rank_i, mrc_params->mrs1)); 1469 1470 // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state 1471 dram_init_command(DCMD_PREA(rank_i)); 1472 } // End product specific code 1473 1474 post_code(0x06, (0x30 + ((channel_i << 4) | rank_i))); 1475 1476 // COARSE WRITE LEVEL: 1477 // check that we're on the correct clock edge 1478 1479 // hte reconfiguration request 1480 mrc_params->hte_setup = 1; 1481 1482 // start CRS_WR_LVL with WDQS = WDQS + 128 PI 1483 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1484 { 1485 delay[bl_i] = get_wdqs(channel_i, rank_i, bl_i) + FULL_CLK; 1486 set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]); 1487 // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) 1488 set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK)); 1489 } // bl_i loop 1490 1491 // get an address in the targeted channel/rank 1492 address = get_addr(mrc_params, channel_i, rank_i); 1493 do 1494 { 1495 uint32_t coarse_result = 0x00; 1496 uint32_t coarse_result_mask = byte_lane_mask(mrc_params); 1497 all_edges_found = true; // assume pass 1498 1499 #ifdef SIM 1500 // need restore memory to idle state as write can be in bad sync 1501 dram_init_command (DCMD_PREA(rank_i)); 1502 #endif 1503 1504 mrc_params->hte_setup = 1; 1505 coarse_result = check_rw_coarse(mrc_params, address); 1506 1507 // check for failures and margin the byte lane back 128 PI (1 CLK) 1508 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1509 { 1510 if (coarse_result & (coarse_result_mask << bl_i)) 1511 { 1512 all_edges_found = false; 1513 delay[bl_i] -= FULL_CLK; 1514 set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]); 1515 // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) 1516 set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK)); 1517 } 1518 } // bl_i loop 1519 1520 } while (!all_edges_found); 1521 1522 #ifdef R2R_SHARING 1523 // increment "num_ranks_enabled" 1524 num_ranks_enabled++; 1525 // accumulate "final_delay[][]" values from "delay[]" values for rolling average 1526 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1527 { 1528 final_delay[channel_i][bl_i] += delay[bl_i]; 1529 set_wdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled)); 1530 // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) 1531 set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled) - QRTR_CLK); 1532 } // bl_i loop 1533 #endif // R2R_SHARING 1534 #endif // BACKUP_WDQS 1535 1536 } // if rank is enabled 1537 } // rank_i loop 1538 } // if channel is enabled 1539 } // channel_i loop 1540 1541 LEAVEFN(); 1542 return; 1543 } 1544 1545 // rd_train: 1546 // POST_CODE[major] == 0x07 1547 // 1548 // This function will perform the READ TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time. 1549 // The idea here is to train the VREF and RDQS (and eventually RDQ) values to achieve maximum READ margins. 1550 // The algorithm will first determine the X coordinate (RDQS setting). 1551 // This is done by collapsing the VREF eye until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX. 1552 // Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX, then average those; this will be the final X coordinate. 1553 // The algorithm will then determine the Y coordinate (VREF setting). 1554 // This is done by collapsing the RDQS eye until we find a minimum required VREF eye for RDQS_MIN and RDQS_MAX. 1555 // Then we take the averages of the VREF eye at RDQS_MIN and RDQS_MAX, then average those; this will be the final Y coordinate. 1556 // NOTE: this algorithm assumes the eye curves have a one-to-one relationship, meaning for each X the curve has only one Y and vice-a-versa. 1557 static void rd_train( 1558 MRCParams_t *mrc_params) 1559 { 1560 1561 #define MIN_RDQS_EYE 10 // in PI Codes 1562 #define MIN_VREF_EYE 10 // in VREF Codes 1563 #define RDQS_STEP 1 // how many RDQS codes to jump while margining 1564 #define VREF_STEP 1 // how many VREF codes to jump while margining 1565 #define VREF_MIN (0x00) // offset into "vref_codes[]" for minimum allowed VREF setting 1566 #define VREF_MAX (0x3F) // offset into "vref_codes[]" for maximum allowed VREF setting 1567 #define RDQS_MIN (0x00) // minimum RDQS delay value 1568 #define RDQS_MAX (0x3F) // maximum RDQS delay value 1569 #define B 0 // BOTTOM VREF 1570 #define T 1 // TOP VREF 1571 #define L 0 // LEFT RDQS 1572 #define R 1 // RIGHT RDQS 1573 1574 uint8_t channel_i; // channel counter 1575 uint8_t rank_i; // rank counter 1576 uint8_t bl_i; // byte lane counter 1577 uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor 1578 #ifdef BACKUP_RDQS 1579 #else 1580 uint8_t side_x; // tracks LEFT/RIGHT approach vectors 1581 uint8_t side_y; // tracks BOTTOM/TOP approach vectors 1582 uint8_t x_coordinate[2/*side_x*/][2/*side_y*/][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // X coordinate data (passing RDQS values) for approach vectors 1583 uint8_t y_coordinate[2/*side_x*/][2/*side_y*/][NUM_CHANNELS][NUM_BYTE_LANES]; // Y coordinate data (passing VREF values) for approach vectors 1584 uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // centered X (RDQS) 1585 uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES]; // centered Y (VREF) 1586 uint32_t address; // target address for "check_bls_ex()" 1587 uint32_t result; // result of "check_bls_ex()" 1588 uint32_t bl_mask; // byte lane mask for "result" checking 1589 #ifdef R2R_SHARING 1590 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs 1591 uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs 1592 #endif // R2R_SHARING 1593 #endif // BACKUP_RDQS 1594 // rd_train starts 1595 post_code(0x07, 0x00); 1596 1597 ENTERFN(); 1598 1599 #ifdef BACKUP_RDQS 1600 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) 1601 { 1602 if (mrc_params->channel_enables & (1<<channel_i)) 1603 { 1604 for (rank_i=0; rank_i<NUM_RANKS; rank_i++) 1605 { 1606 if (mrc_params->rank_enables & (1<<rank_i)) 1607 { 1608 for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++) 1609 { 1610 set_rdqs(channel_i, rank_i, bl_i, ddr_rdqs[PLATFORM_ID]); 1611 } // bl_i loop 1612 } // if rank is enabled 1613 } // rank_i loop 1614 } // if channel is enabled 1615 } // channel_i loop 1616 #else 1617 // initialise x/y_coordinate arrays 1618 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1619 { 1620 if (mrc_params->channel_enables & (1 << channel_i)) 1621 { 1622 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1623 { 1624 if (mrc_params->rank_enables & (1 << rank_i)) 1625 { 1626 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1627 { 1628 // x_coordinate: 1629 x_coordinate[L][B][channel_i][rank_i][bl_i] = RDQS_MIN; 1630 x_coordinate[R][B][channel_i][rank_i][bl_i] = RDQS_MAX; 1631 x_coordinate[L][T][channel_i][rank_i][bl_i] = RDQS_MIN; 1632 x_coordinate[R][T][channel_i][rank_i][bl_i] = RDQS_MAX; 1633 // y_coordinate: 1634 y_coordinate[L][B][channel_i][bl_i] = VREF_MIN; 1635 y_coordinate[R][B][channel_i][bl_i] = VREF_MIN; 1636 y_coordinate[L][T][channel_i][bl_i] = VREF_MAX; 1637 y_coordinate[R][T][channel_i][bl_i] = VREF_MAX; 1638 } // bl_i loop 1639 } // if rank is enabled 1640 } // rank_i loop 1641 } // if channel is enabled 1642 } // channel_i loop 1643 1644 // initialise other variables 1645 bl_mask = byte_lane_mask(mrc_params); 1646 address = get_addr(mrc_params, 0, 0); 1647 1648 #ifdef R2R_SHARING 1649 // need to set "final_delay[][]" elements to "0" 1650 memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay)); 1651 #endif // R2R_SHARING 1652 1653 // look for passing coordinates 1654 for (side_y = B; side_y <= T; side_y++) 1655 { 1656 for (side_x = L; side_x <= R; side_x++) 1657 { 1658 1659 post_code(0x07, (0x10 + (side_y * 2) + (side_x))); 1660 1661 // find passing values 1662 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1663 { 1664 if (mrc_params->channel_enables & (0x1 << channel_i)) 1665 { 1666 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1667 { 1668 1669 if (mrc_params->rank_enables & (0x1 << rank_i)) 1670 { 1671 // set x/y_coordinate search starting settings 1672 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1673 { 1674 set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]); 1675 set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]); 1676 } // bl_i loop 1677 // get an address in the target channel/rank 1678 address = get_addr(mrc_params, channel_i, rank_i); 1679 1680 // request HTE reconfiguration 1681 mrc_params->hte_setup = 1; 1682 1683 // test the settings 1684 do 1685 { 1686 1687 // result[07:00] == failing byte lane (MAX 8) 1688 result = check_bls_ex( mrc_params, address); 1689 1690 // check for failures 1691 if (result & 0xFF) 1692 { 1693 // at least 1 byte lane failed 1694 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1695 { 1696 if (result & (bl_mask << bl_i)) 1697 { 1698 // adjust the RDQS values accordingly 1699 if (side_x == L) 1700 { 1701 x_coordinate[L][side_y][channel_i][rank_i][bl_i] += RDQS_STEP; 1702 } 1703 else 1704 { 1705 x_coordinate[R][side_y][channel_i][rank_i][bl_i] -= RDQS_STEP; 1706 } 1707 // check that we haven't closed the RDQS_EYE too much 1708 if ((x_coordinate[L][side_y][channel_i][rank_i][bl_i] > (RDQS_MAX - MIN_RDQS_EYE)) || 1709 (x_coordinate[R][side_y][channel_i][rank_i][bl_i] < (RDQS_MIN + MIN_RDQS_EYE)) 1710 || 1711 (x_coordinate[L][side_y][channel_i][rank_i][bl_i] 1712 == x_coordinate[R][side_y][channel_i][rank_i][bl_i])) 1713 { 1714 // not enough RDQS margin available at this VREF 1715 // update VREF values accordingly 1716 if (side_y == B) 1717 { 1718 y_coordinate[side_x][B][channel_i][bl_i] += VREF_STEP; 1719 } 1720 else 1721 { 1722 y_coordinate[side_x][T][channel_i][bl_i] -= VREF_STEP; 1723 } 1724 // check that we haven't closed the VREF_EYE too much 1725 if ((y_coordinate[side_x][B][channel_i][bl_i] > (VREF_MAX - MIN_VREF_EYE)) || 1726 (y_coordinate[side_x][T][channel_i][bl_i] < (VREF_MIN + MIN_VREF_EYE)) || 1727 (y_coordinate[side_x][B][channel_i][bl_i] == y_coordinate[side_x][T][channel_i][bl_i])) 1728 { 1729 // VREF_EYE collapsed below MIN_VREF_EYE 1730 training_message(channel_i, rank_i, bl_i); 1731 post_code(0xEE, (0x70 + (side_y * 2) + (side_x))); 1732 } 1733 else 1734 { 1735 // update the VREF setting 1736 set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]); 1737 // reset the X coordinate to begin the search at the new VREF 1738 x_coordinate[side_x][side_y][channel_i][rank_i][bl_i] = 1739 (side_x == L) ? (RDQS_MIN) : (RDQS_MAX); 1740 } 1741 } 1742 // update the RDQS setting 1743 set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]); 1744 } // if bl_i failed 1745 } // bl_i loop 1746 } // at least 1 byte lane failed 1747 } while (result & 0xFF); 1748 } // if rank is enabled 1749 } // rank_i loop 1750 } // if channel is enabled 1751 } // channel_i loop 1752 } // side_x loop 1753 } // side_y loop 1754 1755 post_code(0x07, 0x20); 1756 1757 // find final RDQS (X coordinate) & final VREF (Y coordinate) 1758 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1759 { 1760 if (mrc_params->channel_enables & (1 << channel_i)) 1761 { 1762 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1763 { 1764 if (mrc_params->rank_enables & (1 << rank_i)) 1765 { 1766 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1767 { 1768 uint32_t tempD1; 1769 uint32_t tempD2; 1770 1771 // x_coordinate: 1772 DPF(D_INFO, "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n", rank_i, bl_i, 1773 x_coordinate[L][T][channel_i][rank_i][bl_i], 1774 x_coordinate[R][T][channel_i][rank_i][bl_i], 1775 x_coordinate[L][B][channel_i][rank_i][bl_i], 1776 x_coordinate[R][B][channel_i][rank_i][bl_i]); 1777 1778 tempD1 = (x_coordinate[R][T][channel_i][rank_i][bl_i] + x_coordinate[L][T][channel_i][rank_i][bl_i]) / 2; // average the TOP side LEFT & RIGHT values 1779 tempD2 = (x_coordinate[R][B][channel_i][rank_i][bl_i] + x_coordinate[L][B][channel_i][rank_i][bl_i]) / 2; // average the BOTTOM side LEFT & RIGHT values 1780 x_center[channel_i][rank_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages 1781 1782 // y_coordinate: 1783 DPF(D_INFO, "VREF R/L eye lane%d : %d-%d %d-%d\n", bl_i, 1784 y_coordinate[R][B][channel_i][bl_i], 1785 y_coordinate[R][T][channel_i][bl_i], 1786 y_coordinate[L][B][channel_i][bl_i], 1787 y_coordinate[L][T][channel_i][bl_i]); 1788 1789 tempD1 = (y_coordinate[R][T][channel_i][bl_i] + y_coordinate[R][B][channel_i][bl_i]) / 2; // average the RIGHT side TOP & BOTTOM values 1790 tempD2 = (y_coordinate[L][T][channel_i][bl_i] + y_coordinate[L][B][channel_i][bl_i]) / 2; // average the LEFT side TOP & BOTTOM values 1791 y_center[channel_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages 1792 } // bl_i loop 1793 } // if rank is enabled 1794 } // rank_i loop 1795 } // if channel is enabled 1796 } // channel_i loop 1797 1798 #ifdef RX_EYE_CHECK 1799 // perform an eye check 1800 for (side_y=B; side_y<=T; side_y++) 1801 { 1802 for (side_x=L; side_x<=R; side_x++) 1803 { 1804 1805 post_code(0x07, (0x30 + (side_y * 2) + (side_x))); 1806 1807 // update the settings for the eye check 1808 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) 1809 { 1810 if (mrc_params->channel_enables & (1<<channel_i)) 1811 { 1812 for (rank_i=0; rank_i<NUM_RANKS; rank_i++) 1813 { 1814 if (mrc_params->rank_enables & (1<<rank_i)) 1815 { 1816 for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++) 1817 { 1818 if (side_x == L) 1819 { 1820 set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] - (MIN_RDQS_EYE / 2))); 1821 } 1822 else 1823 { 1824 set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] + (MIN_RDQS_EYE / 2))); 1825 } 1826 if (side_y == B) 1827 { 1828 set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] - (MIN_VREF_EYE / 2))); 1829 } 1830 else 1831 { 1832 set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] + (MIN_VREF_EYE / 2))); 1833 } 1834 } // bl_i loop 1835 } // if rank is enabled 1836 } // rank_i loop 1837 } // if channel is enabled 1838 } // channel_i loop 1839 1840 // request HTE reconfiguration 1841 mrc_params->hte_setup = 1; 1842 1843 // check the eye 1844 if (check_bls_ex( mrc_params, address) & 0xFF) 1845 { 1846 // one or more byte lanes failed 1847 post_code(0xEE, (0x74 + (side_x * 2) + (side_y))); 1848 } 1849 } // side_x loop 1850 } // side_y loop 1851 #endif // RX_EYE_CHECK 1852 1853 post_code(0x07, 0x40); 1854 1855 // set final placements 1856 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1857 { 1858 if (mrc_params->channel_enables & (1 << channel_i)) 1859 { 1860 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1861 { 1862 if (mrc_params->rank_enables & (1 << rank_i)) 1863 { 1864 #ifdef R2R_SHARING 1865 // increment "num_ranks_enabled" 1866 num_ranks_enabled++; 1867 #endif // R2R_SHARING 1868 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1869 { 1870 // x_coordinate: 1871 #ifdef R2R_SHARING 1872 final_delay[channel_i][bl_i] += x_center[channel_i][rank_i][bl_i]; 1873 set_rdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled)); 1874 #else 1875 set_rdqs(channel_i, rank_i, bl_i, x_center[channel_i][rank_i][bl_i]); 1876 #endif // R2R_SHARING 1877 // y_coordinate: 1878 set_vref(channel_i, bl_i, y_center[channel_i][bl_i]); 1879 } // bl_i loop 1880 } // if rank is enabled 1881 } // rank_i loop 1882 } // if channel is enabled 1883 } // channel_i loop 1884 #endif // BACKUP_RDQS 1885 LEAVEFN(); 1886 return; 1887 } 1888 1889 // wr_train: 1890 // POST_CODE[major] == 0x08 1891 // 1892 // This function will perform the WRITE TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time. 1893 // The idea here is to train the WDQ timings to achieve maximum WRITE margins. 1894 // The algorithm will start with WDQ at the current WDQ setting (tracks WDQS in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data patterns pass. 1895 // This is because WDQS will be aligned to WCLK by the Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window of validity. 1896 static void wr_train( 1897 MRCParams_t *mrc_params) 1898 { 1899 1900 #define WDQ_STEP 1 // how many WDQ codes to jump while margining 1901 #define L 0 // LEFT side loop value definition 1902 #define R 1 // RIGHT side loop value definition 1903 1904 uint8_t channel_i; // channel counter 1905 uint8_t rank_i; // rank counter 1906 uint8_t bl_i; // byte lane counter 1907 uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor 1908 #ifdef BACKUP_WDQ 1909 #else 1910 uint8_t side_i; // LEFT/RIGHT side indicator (0=L, 1=R) 1911 uint32_t tempD; // temporary DWORD 1912 uint32_t delay[2/*side_i*/][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // 2 arrays, for L & R side passing delays 1913 uint32_t address; // target address for "check_bls_ex()" 1914 uint32_t result; // result of "check_bls_ex()" 1915 uint32_t bl_mask; // byte lane mask for "result" checking 1916 #ifdef R2R_SHARING 1917 uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs 1918 uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs 1919 #endif // R2R_SHARING 1920 #endif // BACKUP_WDQ 1921 1922 // wr_train starts 1923 post_code(0x08, 0x00); 1924 1925 ENTERFN(); 1926 1927 #ifdef BACKUP_WDQ 1928 for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) 1929 { 1930 if (mrc_params->channel_enables & (1<<channel_i)) 1931 { 1932 for (rank_i=0; rank_i<NUM_RANKS; rank_i++) 1933 { 1934 if (mrc_params->rank_enables & (1<<rank_i)) 1935 { 1936 for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++) 1937 { 1938 set_wdq(channel_i, rank_i, bl_i, ddr_wdq[PLATFORM_ID]); 1939 } // bl_i loop 1940 } // if rank is enabled 1941 } // rank_i loop 1942 } // if channel is enabled 1943 } // channel_i loop 1944 #else 1945 // initialise "delay" 1946 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1947 { 1948 if (mrc_params->channel_enables & (1 << channel_i)) 1949 { 1950 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1951 { 1952 if (mrc_params->rank_enables & (1 << rank_i)) 1953 { 1954 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1955 { 1956 // want to start with WDQ = (WDQS - QRTR_CLK) +/- QRTR_CLK 1957 tempD = get_wdqs(channel_i, rank_i, bl_i) - QRTR_CLK; 1958 delay[L][channel_i][rank_i][bl_i] = tempD - QRTR_CLK; 1959 delay[R][channel_i][rank_i][bl_i] = tempD + QRTR_CLK; 1960 } // bl_i loop 1961 } // if rank is enabled 1962 } // rank_i loop 1963 } // if channel is enabled 1964 } // channel_i loop 1965 1966 // initialise other variables 1967 bl_mask = byte_lane_mask(mrc_params); 1968 address = get_addr(mrc_params, 0, 0); 1969 1970 #ifdef R2R_SHARING 1971 // need to set "final_delay[][]" elements to "0" 1972 memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay)); 1973 #endif // R2R_SHARING 1974 1975 // start algorithm on the LEFT side and train each channel/bl until no failures are observed, then repeat for the RIGHT side. 1976 for (side_i = L; side_i <= R; side_i++) 1977 { 1978 post_code(0x08, (0x10 + (side_i))); 1979 1980 // set starting values 1981 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 1982 { 1983 if (mrc_params->channel_enables & (1 << channel_i)) 1984 { 1985 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 1986 { 1987 if (mrc_params->rank_enables & (1 << rank_i)) 1988 { 1989 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 1990 { 1991 set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]); 1992 } // bl_i loop 1993 } // if rank is enabled 1994 } // rank_i loop 1995 } // if channel is enabled 1996 } // channel_i loop 1997 1998 // find passing values 1999 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 2000 { 2001 if (mrc_params->channel_enables & (0x1 << channel_i)) 2002 { 2003 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 2004 { 2005 if (mrc_params->rank_enables & (0x1 << rank_i)) 2006 { 2007 // get an address in the target channel/rank 2008 address = get_addr(mrc_params, channel_i, rank_i); 2009 2010 // request HTE reconfiguration 2011 mrc_params->hte_setup = 1; 2012 2013 // check the settings 2014 do 2015 { 2016 2017 #ifdef SIM 2018 // need restore memory to idle state as write can be in bad sync 2019 dram_init_command (DCMD_PREA(rank_i)); 2020 #endif 2021 2022 // result[07:00] == failing byte lane (MAX 8) 2023 result = check_bls_ex( mrc_params, address); 2024 // check for failures 2025 if (result & 0xFF) 2026 { 2027 // at least 1 byte lane failed 2028 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 2029 { 2030 if (result & (bl_mask << bl_i)) 2031 { 2032 if (side_i == L) 2033 { 2034 delay[L][channel_i][rank_i][bl_i] += WDQ_STEP; 2035 } 2036 else 2037 { 2038 delay[R][channel_i][rank_i][bl_i] -= WDQ_STEP; 2039 } 2040 // check for algorithm failure 2041 if (delay[L][channel_i][rank_i][bl_i] != delay[R][channel_i][rank_i][bl_i]) 2042 { 2043 // margin available, update delay setting 2044 set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]); 2045 } 2046 else 2047 { 2048 // no margin available, notify the user and halt 2049 training_message(channel_i, rank_i, bl_i); 2050 post_code(0xEE, (0x80 + side_i)); 2051 } 2052 } // if bl_i failed 2053 } // bl_i loop 2054 } // at least 1 byte lane failed 2055 } while (result & 0xFF); // stop when all byte lanes pass 2056 } // if rank is enabled 2057 } // rank_i loop 2058 } // if channel is enabled 2059 } // channel_i loop 2060 } // side_i loop 2061 2062 // program WDQ to the middle of passing window 2063 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 2064 { 2065 if (mrc_params->channel_enables & (1 << channel_i)) 2066 { 2067 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 2068 { 2069 if (mrc_params->rank_enables & (1 << rank_i)) 2070 { 2071 #ifdef R2R_SHARING 2072 // increment "num_ranks_enabled" 2073 num_ranks_enabled++; 2074 #endif // R2R_SHARING 2075 for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++) 2076 { 2077 2078 DPF(D_INFO, "WDQ eye rank%d lane%d : %d-%d\n", rank_i, bl_i, 2079 delay[L][channel_i][rank_i][bl_i], 2080 delay[R][channel_i][rank_i][bl_i]); 2081 2082 tempD = (delay[R][channel_i][rank_i][bl_i] + delay[L][channel_i][rank_i][bl_i]) / 2; 2083 2084 #ifdef R2R_SHARING 2085 final_delay[channel_i][bl_i] += tempD; 2086 set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled)); 2087 #else 2088 set_wdq(channel_i, rank_i, bl_i, tempD); 2089 #endif // R2R_SHARING 2090 2091 } // bl_i loop 2092 } // if rank is enabled 2093 } // rank_i loop 2094 } // if channel is enabled 2095 } // channel_i loop 2096 #endif // BACKUP_WDQ 2097 LEAVEFN(); 2098 return; 2099 } 2100 2101 // Wrapper for jedec initialisation routine 2102 static void perform_jedec_init( 2103 MRCParams_t *mrc_params) 2104 { 2105 jedec_init(mrc_params, 0); 2106 } 2107 2108 // Configure DDRPHY for Auto-Refresh, Periodic Compensations, 2109 // Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down 2110 static void set_auto_refresh( 2111 MRCParams_t *mrc_params) 2112 { 2113 uint32_t channel_i; 2114 uint32_t rank_i; 2115 uint32_t bl_i; 2116 uint32_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1; 2117 uint32_t tempD; 2118 2119 ENTERFN(); 2120 2121 // enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down 2122 for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++) 2123 { 2124 if (mrc_params->channel_enables & (1 << channel_i)) 2125 { 2126 // Enable Periodic RCOMPS 2127 isbM32m(DDRPHY, CMPCTRL, (BIT1), (BIT1)); 2128 2129 2130 // Enable Dynamic DiffAmp & Set Read ODT Value 2131 switch (mrc_params->rd_odt_value) 2132 { 2133 case 0: tempD = 0x3F; break; // OFF 2134 default: tempD = 0x00; break; // Auto 2135 } // rd_odt_value switch 2136 2137 for (bl_i=0; bl_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_i++) 2138 { 2139 isbM32m(DDRPHY, (B0OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), 2140 ((0x00<<16)|(tempD<<10)), 2141 ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT 2142 2143 isbM32m(DDRPHY, (B1OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), 2144 ((0x00<<16)|(tempD<<10)), 2145 ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10)));// Override: DIFFAMP, ODT 2146 } // bl_i loop 2147 2148 // Issue ZQCS command 2149 for (rank_i = 0; rank_i < NUM_RANKS; rank_i++) 2150 { 2151 if (mrc_params->rank_enables & (1 << rank_i)) 2152 { 2153 dram_init_command(DCMD_ZQCS(rank_i)); 2154 } // if rank_i enabled 2155 } // rank_i loop 2156 2157 } // if channel_i enabled 2158 } // channel_i loop 2159 2160 clear_pointers(); 2161 2162 LEAVEFN(); 2163 return; 2164 } 2165 2166 // Depending on configuration enables ECC support. 2167 // Available memory size is decresed, and updated with 0s 2168 // in order to clear error status. Address mode 2 forced. 2169 static void ecc_enable( 2170 MRCParams_t *mrc_params) 2171 { 2172 RegDRP Drp; 2173 RegDSCH Dsch; 2174 RegDECCCTRL Ctr; 2175 2176 if (mrc_params->ecc_enables == 0) return; 2177 2178 ENTERFN(); 2179 2180 // Configuration required in ECC mode 2181 Drp.raw = isbR32m(MCU, DRP); 2182 Drp.field.addressMap = 2; 2183 Drp.field.split64 = 1; 2184 isbW32m(MCU, DRP, Drp.raw); 2185 2186 // Disable new request bypass 2187 Dsch.raw = isbR32m(MCU, DSCH); 2188 Dsch.field.NEWBYPDIS = 1; 2189 isbW32m(MCU, DSCH, Dsch.raw); 2190 2191 // Enable ECC 2192 Ctr.raw = 0; 2193 Ctr.field.SBEEN = 1; 2194 Ctr.field.DBEEN = 1; 2195 Ctr.field.ENCBGEN = 1; 2196 isbW32m(MCU, DECCCTRL, Ctr.raw); 2197 2198 #ifdef SIM 2199 // Read back to be sure writing took place 2200 Ctr.raw = isbR32m(MCU, DECCCTRL); 2201 #endif 2202 2203 // Assume 8 bank memory, one bank is gone for ECC 2204 mrc_params->mem_size -= mrc_params->mem_size / 8; 2205 2206 // For S3 resume memory content has to be preserved 2207 if (mrc_params->boot_mode != bmS3) 2208 { 2209 select_hte(mrc_params); 2210 HteMemInit(mrc_params, MrcMemInit, MrcHaltHteEngineOnError); 2211 select_memory_manager(mrc_params); 2212 } 2213 2214 LEAVEFN(); 2215 return; 2216 } 2217 2218 // Lock MCU registers at the end of initialisation sequence. 2219 static void lock_registers( 2220 MRCParams_t *mrc_params) 2221 { 2222 RegDCO Dco; 2223 2224 ENTERFN(); 2225 2226 Dco.raw = isbR32m(MCU, DCO); 2227 Dco.field.PMIDIS = 0; //0 - PRI enabled 2228 Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER 2229 Dco.field.DRPLOCK = 1; 2230 Dco.field.REUTLOCK = 1; 2231 isbW32m(MCU, DCO, Dco.raw); 2232 2233 LEAVEFN(); 2234 2235 } 2236 2237 #ifdef MRC_SV 2238 2239 // cache write back invalidate 2240 static void asm_wbinvd(void) 2241 { 2242 #if defined (SIM) || defined (GCC) 2243 asm( 2244 "wbinvd;" 2245 ); 2246 #else 2247 __asm wbinvd; 2248 #endif 2249 } 2250 2251 // cache invalidate 2252 static void asm_invd(void) 2253 { 2254 #if defined (SIM) || defined (GCC) 2255 asm( 2256 "invd;" 2257 ); 2258 #else 2259 __asm invd; 2260 #endif 2261 } 2262 2263 2264 static void cpu_read(void) 2265 { 2266 uint32_t adr, dat, limit; 2267 2268 asm_invd(); 2269 2270 limit = 8 * 1024; 2271 for (adr = 0; adr < limit; adr += 4) 2272 { 2273 dat = *(uint32_t*) adr; 2274 if ((adr & 0x0F) == 0) 2275 { 2276 DPF(D_INFO, "\n%x : ", adr); 2277 } 2278 DPF(D_INFO, "%x ", dat); 2279 } 2280 DPF(D_INFO, "\n"); 2281 2282 DPF(D_INFO, "CPU read done\n"); 2283 } 2284 2285 2286 static void cpu_write(void) 2287 { 2288 uint32_t adr, limit; 2289 2290 limit = 8 * 1024; 2291 for (adr = 0; adr < limit; adr += 4) 2292 { 2293 *(uint32_t*) adr = 0xDEAD0000 + adr; 2294 } 2295 2296 asm_wbinvd(); 2297 2298 DPF(D_INFO, "CPU write done\n"); 2299 } 2300 2301 2302 static void cpu_memory_test( 2303 MRCParams_t *mrc_params) 2304 { 2305 uint32_t result = 0; 2306 uint32_t val, dat, adr, adr0, step, limit; 2307 uint64_t my_tsc; 2308 2309 ENTERFN(); 2310 2311 asm_invd(); 2312 2313 adr0 = 1 * 1024 * 1024; 2314 limit = 256 * 1024 * 1024; 2315 2316 for (step = 0; step <= 4; step++) 2317 { 2318 DPF(D_INFO, "Mem test step %d starting from %xh\n", step, adr0); 2319 2320 my_tsc = read_tsc(); 2321 for (adr = adr0; adr < limit; adr += sizeof(uint32_t)) 2322 { 2323 if (step == 0) dat = adr; 2324 else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f)); 2325 else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f)); 2326 else if (step == 3) dat = 0x5555AAAA; 2327 else if (step == 4) dat = 0xAAAA5555; 2328 2329 *(uint32_t*) adr = dat; 2330 } 2331 DPF(D_INFO, "Write time %llXh\n", read_tsc() - my_tsc); 2332 2333 my_tsc = read_tsc(); 2334 for (adr = adr0; adr < limit; adr += sizeof(uint32_t)) 2335 { 2336 if (step == 0) dat = adr; 2337 else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f)); 2338 else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f)); 2339 else if (step == 3) dat = 0x5555AAAA; 2340 else if (step == 4) dat = 0xAAAA5555; 2341 2342 val = *(uint32_t*) adr; 2343 2344 if (val != dat) 2345 { 2346 DPF(D_INFO, "%x vs. %x@%x\n", dat, val, adr); 2347 result = adr|BIT31; 2348 } 2349 } 2350 DPF(D_INFO, "Read time %llXh\n", read_tsc() - my_tsc); 2351 } 2352 2353 DPF( D_INFO, "Memory test result %x\n", result); 2354 LEAVEFN(); 2355 } 2356 #endif // MRC_SV 2357 2358 2359 // Execute memory test, if error dtected it is 2360 // indicated in mrc_params->status. 2361 static void memory_test( 2362 MRCParams_t *mrc_params) 2363 { 2364 uint32_t result = 0; 2365 2366 ENTERFN(); 2367 2368 select_hte(mrc_params); 2369 result = HteMemInit(mrc_params, MrcMemTest, MrcHaltHteEngineOnError); 2370 select_memory_manager(mrc_params); 2371 2372 DPF(D_INFO, "Memory test result %x\n", result); 2373 mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST); 2374 LEAVEFN(); 2375 } 2376 2377 2378 // Force same timings as with backup settings 2379 static void static_timings( 2380 MRCParams_t *mrc_params) 2381 2382 { 2383 uint8_t ch, rk, bl; 2384 2385 for (ch = 0; ch < NUM_CHANNELS; ch++) 2386 { 2387 for (rk = 0; rk < NUM_RANKS; rk++) 2388 { 2389 for (bl = 0; bl < NUM_BYTE_LANES; bl++) 2390 { 2391 set_rcvn(ch, rk, bl, 498); // RCVN 2392 set_rdqs(ch, rk, bl, 24); // RDQS 2393 set_wdqs(ch, rk, bl, 292); // WDQS 2394 set_wdq( ch, rk, bl, 260); // WDQ 2395 if (rk == 0) 2396 { 2397 set_vref(ch, bl, 32); // VREF (RANK0 only) 2398 } 2399 } 2400 set_wctl(ch, rk, 217); // WCTL 2401 } 2402 set_wcmd(ch, 220); // WCMD 2403 } 2404 2405 return; 2406 } 2407 2408 // 2409 // Initialise system memory. 2410 // 2411 void MemInit( 2412 MRCParams_t *mrc_params) 2413 { 2414 static const MemInit_t init[] = 2415 { 2416 { 0x0101, bmCold|bmFast|bmWarm|bmS3, clear_self_refresh }, //0 2417 { 0x0200, bmCold|bmFast|bmWarm|bmS3, prog_ddr_timing_control }, //1 initialise the MCU 2418 { 0x0103, bmCold|bmFast , prog_decode_before_jedec }, //2 2419 { 0x0104, bmCold|bmFast , perform_ddr_reset }, //3 2420 { 0x0300, bmCold|bmFast |bmS3, ddrphy_init }, //4 initialise the DDRPHY 2421 { 0x0400, bmCold|bmFast , perform_jedec_init }, //5 perform JEDEC initialisation of DRAMs 2422 { 0x0105, bmCold|bmFast , set_ddr_init_complete }, //6 2423 { 0x0106, bmFast|bmWarm|bmS3, restore_timings }, //7 2424 { 0x0106, bmCold , default_timings }, //8 2425 { 0x0500, bmCold , rcvn_cal }, //9 perform RCVN_CAL algorithm 2426 { 0x0600, bmCold , wr_level }, //10 perform WR_LEVEL algorithm 2427 { 0x0120, bmCold , prog_page_ctrl }, //11 2428 { 0x0700, bmCold , rd_train }, //12 perform RD_TRAIN algorithm 2429 { 0x0800, bmCold , wr_train }, //13 perform WR_TRAIN algorithm 2430 { 0x010B, bmCold , store_timings }, //14 2431 { 0x010C, bmCold|bmFast|bmWarm|bmS3, enable_scrambling }, //15 2432 { 0x010D, bmCold|bmFast|bmWarm|bmS3, prog_ddr_control }, //16 2433 { 0x010E, bmCold|bmFast|bmWarm|bmS3, prog_dra_drb }, //17 2434 { 0x010F, bmWarm|bmS3, perform_wake }, //18 2435 { 0x0110, bmCold|bmFast|bmWarm|bmS3, change_refresh_period }, //19 2436 { 0x0111, bmCold|bmFast|bmWarm|bmS3, set_auto_refresh }, //20 2437 { 0x0112, bmCold|bmFast|bmWarm|bmS3, ecc_enable }, //21 2438 { 0x0113, bmCold|bmFast , memory_test }, //22 2439 { 0x0114, bmCold|bmFast|bmWarm|bmS3, lock_registers } //23 set init done 2440 }; 2441 2442 uint32_t i; 2443 2444 ENTERFN(); 2445 2446 DPF(D_INFO, "Meminit build %s %s\n", __DATE__, __TIME__); 2447 2448 // MRC started 2449 post_code(0x01, 0x00); 2450 2451 if (mrc_params->boot_mode != bmCold) 2452 { 2453 if (mrc_params->ddr_speed != mrc_params->timings.ddr_speed) 2454 { 2455 // full training required as frequency changed 2456 mrc_params->boot_mode = bmCold; 2457 } 2458 } 2459 2460 for (i = 0; i < MCOUNT(init); i++) 2461 { 2462 uint64_t my_tsc; 2463 2464 #ifdef MRC_SV 2465 if (mrc_params->menu_after_mrc && i > 14) 2466 { 2467 uint8_t ch; 2468 2469 mylop: 2470 2471 DPF(D_INFO, "-- c - continue --\n"); 2472 DPF(D_INFO, "-- j - move to jedec init --\n"); 2473 DPF(D_INFO, "-- m - memory test --\n"); 2474 DPF(D_INFO, "-- r - cpu read --\n"); 2475 DPF(D_INFO, "-- w - cpu write --\n"); 2476 DPF(D_INFO, "-- b - hte base test --\n"); 2477 DPF(D_INFO, "-- g - hte extended test --\n"); 2478 2479 ch = mgetc(); 2480 switch (ch) 2481 { 2482 case 'c': 2483 break; 2484 case 'j': //move to jedec init 2485 i = 5; 2486 break; 2487 2488 case 'M': 2489 case 'N': 2490 { 2491 uint32_t n, res, cnt=0; 2492 2493 for(n=0; mgetch()==0; n++) 2494 { 2495 if( ch == 'M' || n % 256 == 0) 2496 { 2497 DPF(D_INFO, "n=%d e=%d\n", n, cnt); 2498 } 2499 2500 res = 0; 2501 2502 if( ch == 'M') 2503 { 2504 memory_test(mrc_params); 2505 res |= mrc_params->status; 2506 } 2507 2508 mrc_params->hte_setup = 1; 2509 res |= check_bls_ex(mrc_params, 0x00000000); 2510 res |= check_bls_ex(mrc_params, 0x00000000); 2511 res |= check_bls_ex(mrc_params, 0x00000000); 2512 res |= check_bls_ex(mrc_params, 0x00000000); 2513 2514 if( mrc_params->rank_enables & 2) 2515 { 2516 mrc_params->hte_setup = 1; 2517 res |= check_bls_ex(mrc_params, 0x40000000); 2518 res |= check_bls_ex(mrc_params, 0x40000000); 2519 res |= check_bls_ex(mrc_params, 0x40000000); 2520 res |= check_bls_ex(mrc_params, 0x40000000); 2521 } 2522 2523 if( res != 0) 2524 { 2525 DPF(D_INFO, "###########\n"); 2526 DPF(D_INFO, "#\n"); 2527 DPF(D_INFO, "# Error count %d\n", ++cnt); 2528 DPF(D_INFO, "#\n"); 2529 DPF(D_INFO, "###########\n"); 2530 } 2531 2532 } // for 2533 2534 select_memory_manager(mrc_params); 2535 } 2536 goto mylop; 2537 case 'm': 2538 memory_test(mrc_params); 2539 goto mylop; 2540 case 'n': 2541 cpu_memory_test(mrc_params); 2542 goto mylop; 2543 2544 case 'l': 2545 ch = mgetc(); 2546 if (ch <= '9') DpfPrintMask ^= (ch - '0') << 3; 2547 DPF(D_INFO, "Log mask %x\n", DpfPrintMask); 2548 goto mylop; 2549 case 'p': 2550 print_timings(mrc_params); 2551 goto mylop; 2552 case 'R': 2553 rd_train(mrc_params); 2554 goto mylop; 2555 case 'W': 2556 wr_train(mrc_params); 2557 goto mylop; 2558 2559 case 'r': 2560 cpu_read(); 2561 goto mylop; 2562 case 'w': 2563 cpu_write(); 2564 goto mylop; 2565 2566 case 'g': 2567 { 2568 uint32_t result; 2569 select_hte(mrc_params); 2570 mrc_params->hte_setup = 1; 2571 result = check_bls_ex(mrc_params, 0); 2572 DPF(D_INFO, "Extended test result %x\n", result); 2573 select_memory_manager(mrc_params); 2574 } 2575 goto mylop; 2576 case 'b': 2577 { 2578 uint32_t result; 2579 select_hte(mrc_params); 2580 mrc_params->hte_setup = 1; 2581 result = check_rw_coarse(mrc_params, 0); 2582 DPF(D_INFO, "Base test result %x\n", result); 2583 select_memory_manager(mrc_params); 2584 } 2585 goto mylop; 2586 case 'B': 2587 select_hte(mrc_params); 2588 HteMemOp(0x2340, 1, 1); 2589 select_memory_manager(mrc_params); 2590 goto mylop; 2591 2592 case '3': 2593 { 2594 RegDPMC0 DPMC0reg; 2595 2596 DPF( D_INFO, "===>> Start suspend\n"); 2597 isbR32m(MCU, DSTAT); 2598 2599 DPMC0reg.raw = isbR32m(MCU, DPMC0); 2600 DPMC0reg.field.DYNSREN = 0; 2601 DPMC0reg.field.powerModeOpCode = 0x05; // Disable Master DLL 2602 isbW32m(MCU, DPMC0, DPMC0reg.raw); 2603 2604 // Should be off for negative test case verification 2605 #if 1 2606 Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG), 2607 (uint32_t)SB_COMMAND(SB_SUSPEND_CMND_OPCODE, MCU, 0)); 2608 #endif 2609 2610 DPF( D_INFO, "press key\n"); 2611 mgetc(); 2612 DPF( D_INFO, "===>> Start resume\n"); 2613 isbR32m(MCU, DSTAT); 2614 2615 mrc_params->boot_mode = bmS3; 2616 i = 0; 2617 } 2618 2619 } // switch 2620 2621 } // if( menu 2622 #endif //MRC_SV 2623 2624 if (mrc_params->boot_mode & init[i].boot_path) 2625 { 2626 uint8_t major = init[i].post_code >> 8 & 0xFF; 2627 uint8_t minor = init[i].post_code >> 0 & 0xFF; 2628 post_code(major, minor); 2629 2630 my_tsc = read_tsc(); 2631 init[i].init_fn(mrc_params); 2632 DPF(D_TIME, "Execution time %llX", read_tsc() - my_tsc); 2633 } 2634 } 2635 2636 // display the timings 2637 print_timings(mrc_params); 2638 2639 // MRC is complete. 2640 post_code(0x01, 0xFF); 2641 2642 LEAVEFN(); 2643 return; 2644 } 2645