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