1 /* 2 * Copyright (C) 2013, Intel Corporation 3 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> 4 * 5 * Ported from Intel released Quark UEFI BIOS 6 * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei 7 * 8 * SPDX-License-Identifier: Intel 9 */ 10 11 #include <common.h> 12 #include <asm/arch/device.h> 13 #include <asm/arch/mrc.h> 14 #include <asm/arch/msg_port.h> 15 #include "mrc_util.h" 16 #include "hte.h" 17 #include "smc.h" 18 19 static const uint8_t vref_codes[64] = { 20 /* lowest to highest */ 21 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 22 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 23 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 24 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 25 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 26 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 27 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 28 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F 29 }; 30 31 void mrc_write_mask(u32 unit, u32 addr, u32 data, u32 mask) 32 { 33 msg_port_write(unit, addr, 34 (msg_port_read(unit, addr) & ~(mask)) | 35 ((data) & (mask))); 36 } 37 38 void mrc_alt_write_mask(u32 unit, u32 addr, u32 data, u32 mask) 39 { 40 msg_port_alt_write(unit, addr, 41 (msg_port_alt_read(unit, addr) & ~(mask)) | 42 ((data) & (mask))); 43 } 44 45 void mrc_post_code(uint8_t major, uint8_t minor) 46 { 47 /* send message to UART */ 48 DPF(D_INFO, "POST: 0x%01x%02x\n", major, minor); 49 50 /* error check */ 51 if (major == 0xee) 52 hang(); 53 } 54 55 /* Delay number of nanoseconds */ 56 void delay_n(uint32_t ns) 57 { 58 /* 1000 MHz clock has 1ns period --> no conversion required */ 59 uint64_t final_tsc = rdtsc(); 60 61 final_tsc += ((get_tbclk_mhz() * ns) / 1000); 62 63 while (rdtsc() < final_tsc) 64 ; 65 } 66 67 /* Delay number of microseconds */ 68 void delay_u(uint32_t ms) 69 { 70 /* 64-bit math is not an option, just use loops */ 71 while (ms--) 72 delay_n(1000); 73 } 74 75 /* Select Memory Manager as the source for PRI interface */ 76 void select_mem_mgr(void) 77 { 78 u32 dco; 79 80 ENTERFN(); 81 82 dco = msg_port_read(MEM_CTLR, DCO); 83 dco &= ~BIT28; 84 msg_port_write(MEM_CTLR, DCO, dco); 85 86 LEAVEFN(); 87 } 88 89 /* Select HTE as the source for PRI interface */ 90 void select_hte(void) 91 { 92 u32 dco; 93 94 ENTERFN(); 95 96 dco = msg_port_read(MEM_CTLR, DCO); 97 dco |= BIT28; 98 msg_port_write(MEM_CTLR, DCO, dco); 99 100 LEAVEFN(); 101 } 102 103 /* 104 * Send DRAM command 105 * data should be formated using DCMD_Xxxx macro or emrsXCommand structure 106 */ 107 void dram_init_command(uint32_t data) 108 { 109 pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_DATA_REG, data); 110 pci_write_config_dword(QUARK_HOST_BRIDGE, MSG_CTRL_EXT_REG, 0); 111 msg_port_setup(MSG_OP_DRAM_INIT, MEM_CTLR, 0); 112 113 DPF(D_REGWR, "WR32 %03X %08X %08X\n", MEM_CTLR, 0, data); 114 } 115 116 /* Send DRAM wake command using special MCU side-band WAKE opcode */ 117 void dram_wake_command(void) 118 { 119 ENTERFN(); 120 121 msg_port_setup(MSG_OP_DRAM_WAKE, MEM_CTLR, 0); 122 123 LEAVEFN(); 124 } 125 126 void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane) 127 { 128 /* send message to UART */ 129 DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane); 130 } 131 132 /* 133 * This function will program the RCVEN delays 134 * 135 * (currently doesn't comprehend rank) 136 */ 137 void set_rcvn(uint8_t channel, uint8_t rank, 138 uint8_t byte_lane, uint32_t pi_count) 139 { 140 uint32_t reg; 141 uint32_t msk; 142 uint32_t temp; 143 144 ENTERFN(); 145 146 DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n", 147 channel, rank, byte_lane, pi_count); 148 149 /* 150 * RDPTR (1/2 MCLK, 64 PIs) 151 * BL0 -> B01PTRCTL0[11:08] (0x0-0xF) 152 * BL1 -> B01PTRCTL0[23:20] (0x0-0xF) 153 */ 154 reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 155 (channel * DDRIODQ_CH_OFFSET); 156 msk = (byte_lane & BIT0) ? (BIT23 | BIT22 | BIT21 | BIT20) : 157 (BIT11 | BIT10 | BIT9 | BIT8); 158 temp = (byte_lane & BIT0) ? ((pi_count / HALF_CLK) << 20) : 159 ((pi_count / HALF_CLK) << 8); 160 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 161 162 /* Adjust PI_COUNT */ 163 pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; 164 165 /* 166 * PI (1/64 MCLK, 1 PIs) 167 * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F) 168 * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F) 169 */ 170 reg = (byte_lane & BIT0) ? B1DLLPICODER0 : B0DLLPICODER0; 171 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 172 (channel * DDRIODQ_CH_OFFSET)); 173 msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24); 174 temp = pi_count << 24; 175 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 176 177 /* 178 * DEADBAND 179 * BL0/1 -> B01DBCTL1[08/11] (+1 select) 180 * BL0/1 -> B01DBCTL1[02/05] (enable) 181 */ 182 reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 183 (channel * DDRIODQ_CH_OFFSET); 184 msk = 0x00; 185 temp = 0x00; 186 187 /* enable */ 188 msk |= (byte_lane & BIT0) ? BIT5 : BIT2; 189 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) 190 temp |= msk; 191 192 /* select */ 193 msk |= (byte_lane & BIT0) ? BIT11 : BIT8; 194 if (pi_count < EARLY_DB) 195 temp |= msk; 196 197 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 198 199 /* error check */ 200 if (pi_count > 0x3F) { 201 training_message(channel, rank, byte_lane); 202 mrc_post_code(0xee, 0xe0); 203 } 204 205 LEAVEFN(); 206 } 207 208 /* 209 * This function will return the current RCVEN delay on the given 210 * channel, rank, byte_lane as an absolute PI count. 211 * 212 * (currently doesn't comprehend rank) 213 */ 214 uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane) 215 { 216 uint32_t reg; 217 uint32_t temp; 218 uint32_t pi_count; 219 220 ENTERFN(); 221 222 /* 223 * RDPTR (1/2 MCLK, 64 PIs) 224 * BL0 -> B01PTRCTL0[11:08] (0x0-0xF) 225 * BL1 -> B01PTRCTL0[23:20] (0x0-0xF) 226 */ 227 reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 228 (channel * DDRIODQ_CH_OFFSET); 229 temp = msg_port_alt_read(DDRPHY, reg); 230 temp >>= (byte_lane & BIT0) ? 20 : 8; 231 temp &= 0xF; 232 233 /* Adjust PI_COUNT */ 234 pi_count = temp * HALF_CLK; 235 236 /* 237 * PI (1/64 MCLK, 1 PIs) 238 * BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F) 239 * BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F) 240 */ 241 reg = (byte_lane & BIT0) ? B1DLLPICODER0 : B0DLLPICODER0; 242 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 243 (channel * DDRIODQ_CH_OFFSET)); 244 temp = msg_port_alt_read(DDRPHY, reg); 245 temp >>= 24; 246 temp &= 0x3F; 247 248 /* Adjust PI_COUNT */ 249 pi_count += temp; 250 251 LEAVEFN(); 252 253 return pi_count; 254 } 255 256 /* 257 * This function will program the RDQS delays based on an absolute 258 * amount of PIs. 259 * 260 * (currently doesn't comprehend rank) 261 */ 262 void set_rdqs(uint8_t channel, uint8_t rank, 263 uint8_t byte_lane, uint32_t pi_count) 264 { 265 uint32_t reg; 266 uint32_t msk; 267 uint32_t temp; 268 269 ENTERFN(); 270 DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n", 271 channel, rank, byte_lane, pi_count); 272 273 /* 274 * PI (1/128 MCLK) 275 * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47) 276 * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47) 277 */ 278 reg = (byte_lane & BIT0) ? B1RXDQSPICODE : B0RXDQSPICODE; 279 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 280 (channel * DDRIODQ_CH_OFFSET)); 281 msk = (BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0); 282 temp = pi_count << 0; 283 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 284 285 /* error check (shouldn't go above 0x3F) */ 286 if (pi_count > 0x47) { 287 training_message(channel, rank, byte_lane); 288 mrc_post_code(0xee, 0xe1); 289 } 290 291 LEAVEFN(); 292 } 293 294 /* 295 * This function will return the current RDQS delay on the given 296 * channel, rank, byte_lane as an absolute PI count. 297 * 298 * (currently doesn't comprehend rank) 299 */ 300 uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane) 301 { 302 uint32_t reg; 303 uint32_t temp; 304 uint32_t pi_count; 305 306 ENTERFN(); 307 308 /* 309 * PI (1/128 MCLK) 310 * BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47) 311 * BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47) 312 */ 313 reg = (byte_lane & BIT0) ? B1RXDQSPICODE : B0RXDQSPICODE; 314 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 315 (channel * DDRIODQ_CH_OFFSET)); 316 temp = msg_port_alt_read(DDRPHY, reg); 317 318 /* Adjust PI_COUNT */ 319 pi_count = temp & 0x7F; 320 321 LEAVEFN(); 322 323 return pi_count; 324 } 325 326 /* 327 * This function will program the WDQS delays based on an absolute 328 * amount of PIs. 329 * 330 * (currently doesn't comprehend rank) 331 */ 332 void set_wdqs(uint8_t channel, uint8_t rank, 333 uint8_t byte_lane, uint32_t pi_count) 334 { 335 uint32_t reg; 336 uint32_t msk; 337 uint32_t temp; 338 339 ENTERFN(); 340 341 DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n", 342 channel, rank, byte_lane, pi_count); 343 344 /* 345 * RDPTR (1/2 MCLK, 64 PIs) 346 * BL0 -> B01PTRCTL0[07:04] (0x0-0xF) 347 * BL1 -> B01PTRCTL0[19:16] (0x0-0xF) 348 */ 349 reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 350 (channel * DDRIODQ_CH_OFFSET); 351 msk = (byte_lane & BIT0) ? (BIT19 | BIT18 | BIT17 | BIT16) : 352 (BIT7 | BIT6 | BIT5 | BIT4); 353 temp = pi_count / HALF_CLK; 354 temp <<= (byte_lane & BIT0) ? 16 : 4; 355 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 356 357 /* Adjust PI_COUNT */ 358 pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; 359 360 /* 361 * PI (1/64 MCLK, 1 PIs) 362 * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F) 363 * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F) 364 */ 365 reg = (byte_lane & BIT0) ? B1DLLPICODER0 : B0DLLPICODER0; 366 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 367 (channel * DDRIODQ_CH_OFFSET)); 368 msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16); 369 temp = pi_count << 16; 370 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 371 372 /* 373 * DEADBAND 374 * BL0/1 -> B01DBCTL1[07/10] (+1 select) 375 * BL0/1 -> B01DBCTL1[01/04] (enable) 376 */ 377 reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 378 (channel * DDRIODQ_CH_OFFSET); 379 msk = 0x00; 380 temp = 0x00; 381 382 /* enable */ 383 msk |= (byte_lane & BIT0) ? BIT4 : BIT1; 384 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) 385 temp |= msk; 386 387 /* select */ 388 msk |= (byte_lane & BIT0) ? BIT10 : BIT7; 389 if (pi_count < EARLY_DB) 390 temp |= msk; 391 392 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 393 394 /* error check */ 395 if (pi_count > 0x3F) { 396 training_message(channel, rank, byte_lane); 397 mrc_post_code(0xee, 0xe2); 398 } 399 400 LEAVEFN(); 401 } 402 403 /* 404 * This function will return the amount of WDQS delay on the given 405 * channel, rank, byte_lane as an absolute PI count. 406 * 407 * (currently doesn't comprehend rank) 408 */ 409 uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane) 410 { 411 uint32_t reg; 412 uint32_t temp; 413 uint32_t pi_count; 414 415 ENTERFN(); 416 417 /* 418 * RDPTR (1/2 MCLK, 64 PIs) 419 * BL0 -> B01PTRCTL0[07:04] (0x0-0xF) 420 * BL1 -> B01PTRCTL0[19:16] (0x0-0xF) 421 */ 422 reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 423 (channel * DDRIODQ_CH_OFFSET); 424 temp = msg_port_alt_read(DDRPHY, reg); 425 temp >>= (byte_lane & BIT0) ? 16 : 4; 426 temp &= 0xF; 427 428 /* Adjust PI_COUNT */ 429 pi_count = (temp * HALF_CLK); 430 431 /* 432 * PI (1/64 MCLK, 1 PIs) 433 * BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F) 434 * BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F) 435 */ 436 reg = (byte_lane & BIT0) ? B1DLLPICODER0 : B0DLLPICODER0; 437 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 438 (channel * DDRIODQ_CH_OFFSET)); 439 temp = msg_port_alt_read(DDRPHY, reg); 440 temp >>= 16; 441 temp &= 0x3F; 442 443 /* Adjust PI_COUNT */ 444 pi_count += temp; 445 446 LEAVEFN(); 447 448 return pi_count; 449 } 450 451 /* 452 * This function will program the WDQ delays based on an absolute 453 * number of PIs. 454 * 455 * (currently doesn't comprehend rank) 456 */ 457 void set_wdq(uint8_t channel, uint8_t rank, 458 uint8_t byte_lane, uint32_t pi_count) 459 { 460 uint32_t reg; 461 uint32_t msk; 462 uint32_t temp; 463 464 ENTERFN(); 465 466 DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n", 467 channel, rank, byte_lane, pi_count); 468 469 /* 470 * RDPTR (1/2 MCLK, 64 PIs) 471 * BL0 -> B01PTRCTL0[03:00] (0x0-0xF) 472 * BL1 -> B01PTRCTL0[15:12] (0x0-0xF) 473 */ 474 reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 475 (channel * DDRIODQ_CH_OFFSET); 476 msk = (byte_lane & BIT0) ? (BIT15 | BIT14 | BIT13 | BIT12) : 477 (BIT3 | BIT2 | BIT1 | BIT0); 478 temp = pi_count / HALF_CLK; 479 temp <<= (byte_lane & BIT0) ? 12 : 0; 480 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 481 482 /* Adjust PI_COUNT */ 483 pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; 484 485 /* 486 * PI (1/64 MCLK, 1 PIs) 487 * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F) 488 * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F) 489 */ 490 reg = (byte_lane & BIT0) ? B1DLLPICODER0 : B0DLLPICODER0; 491 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 492 (channel * DDRIODQ_CH_OFFSET)); 493 msk = (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8); 494 temp = pi_count << 8; 495 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 496 497 /* 498 * DEADBAND 499 * BL0/1 -> B01DBCTL1[06/09] (+1 select) 500 * BL0/1 -> B01DBCTL1[00/03] (enable) 501 */ 502 reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 503 (channel * DDRIODQ_CH_OFFSET); 504 msk = 0x00; 505 temp = 0x00; 506 507 /* enable */ 508 msk |= (byte_lane & BIT0) ? BIT3 : BIT0; 509 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) 510 temp |= msk; 511 512 /* select */ 513 msk |= (byte_lane & BIT0) ? BIT9 : BIT6; 514 if (pi_count < EARLY_DB) 515 temp |= msk; 516 517 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 518 519 /* error check */ 520 if (pi_count > 0x3F) { 521 training_message(channel, rank, byte_lane); 522 mrc_post_code(0xee, 0xe3); 523 } 524 525 LEAVEFN(); 526 } 527 528 /* 529 * This function will return the amount of WDQ delay on the given 530 * channel, rank, byte_lane as an absolute PI count. 531 * 532 * (currently doesn't comprehend rank) 533 */ 534 uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane) 535 { 536 uint32_t reg; 537 uint32_t temp; 538 uint32_t pi_count; 539 540 ENTERFN(); 541 542 /* 543 * RDPTR (1/2 MCLK, 64 PIs) 544 * BL0 -> B01PTRCTL0[03:00] (0x0-0xF) 545 * BL1 -> B01PTRCTL0[15:12] (0x0-0xF) 546 */ 547 reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 548 (channel * DDRIODQ_CH_OFFSET); 549 temp = msg_port_alt_read(DDRPHY, reg); 550 temp >>= (byte_lane & BIT0) ? (12) : (0); 551 temp &= 0xF; 552 553 /* Adjust PI_COUNT */ 554 pi_count = temp * HALF_CLK; 555 556 /* 557 * PI (1/64 MCLK, 1 PIs) 558 * BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F) 559 * BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F) 560 */ 561 reg = (byte_lane & BIT0) ? B1DLLPICODER0 : B0DLLPICODER0; 562 reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + 563 (channel * DDRIODQ_CH_OFFSET)); 564 temp = msg_port_alt_read(DDRPHY, reg); 565 temp >>= 8; 566 temp &= 0x3F; 567 568 /* Adjust PI_COUNT */ 569 pi_count += temp; 570 571 LEAVEFN(); 572 573 return pi_count; 574 } 575 576 /* 577 * This function will program the WCMD delays based on an absolute 578 * number of PIs. 579 */ 580 void set_wcmd(uint8_t channel, uint32_t pi_count) 581 { 582 uint32_t reg; 583 uint32_t msk; 584 uint32_t temp; 585 586 ENTERFN(); 587 588 /* 589 * RDPTR (1/2 MCLK, 64 PIs) 590 * CMDPTRREG[11:08] (0x0-0xF) 591 */ 592 reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET); 593 msk = (BIT11 | BIT10 | BIT9 | BIT8); 594 temp = pi_count / HALF_CLK; 595 temp <<= 8; 596 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 597 598 /* Adjust PI_COUNT */ 599 pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; 600 601 /* 602 * PI (1/64 MCLK, 1 PIs) 603 * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused) 604 * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused) 605 * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused) 606 * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused) 607 * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused) 608 * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F) 609 * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused) 610 * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused) 611 */ 612 reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET); 613 614 msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24 | 615 BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16 | 616 BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8 | 617 BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0); 618 619 temp = (pi_count << 24) | (pi_count << 16) | 620 (pi_count << 8) | (pi_count << 0); 621 622 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 623 reg = CMDDLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); /* PO */ 624 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 625 626 /* 627 * DEADBAND 628 * CMDCFGREG0[17] (+1 select) 629 * CMDCFGREG0[16] (enable) 630 */ 631 reg = CMDCFGREG0 + (channel * DDRIOCCC_CH_OFFSET); 632 msk = 0x00; 633 temp = 0x00; 634 635 /* enable */ 636 msk |= BIT16; 637 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) 638 temp |= msk; 639 640 /* select */ 641 msk |= BIT17; 642 if (pi_count < EARLY_DB) 643 temp |= msk; 644 645 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 646 647 /* error check */ 648 if (pi_count > 0x3F) 649 mrc_post_code(0xee, 0xe4); 650 651 LEAVEFN(); 652 } 653 654 /* 655 * This function will return the amount of WCMD delay on the given 656 * channel as an absolute PI count. 657 */ 658 uint32_t get_wcmd(uint8_t channel) 659 { 660 uint32_t reg; 661 uint32_t temp; 662 uint32_t pi_count; 663 664 ENTERFN(); 665 666 /* 667 * RDPTR (1/2 MCLK, 64 PIs) 668 * CMDPTRREG[11:08] (0x0-0xF) 669 */ 670 reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET); 671 temp = msg_port_alt_read(DDRPHY, reg); 672 temp >>= 8; 673 temp &= 0xF; 674 675 /* Adjust PI_COUNT */ 676 pi_count = temp * HALF_CLK; 677 678 /* 679 * PI (1/64 MCLK, 1 PIs) 680 * CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused) 681 * CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused) 682 * CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused) 683 * CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused) 684 * CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused) 685 * CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F) 686 * CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused) 687 * CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused) 688 */ 689 reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET); 690 temp = msg_port_alt_read(DDRPHY, reg); 691 temp >>= 16; 692 temp &= 0x3F; 693 694 /* Adjust PI_COUNT */ 695 pi_count += temp; 696 697 LEAVEFN(); 698 699 return pi_count; 700 } 701 702 /* 703 * This function will program the WCLK delays based on an absolute 704 * number of PIs. 705 */ 706 void set_wclk(uint8_t channel, uint8_t rank, uint32_t pi_count) 707 { 708 uint32_t reg; 709 uint32_t msk; 710 uint32_t temp; 711 712 ENTERFN(); 713 714 /* 715 * RDPTR (1/2 MCLK, 64 PIs) 716 * CCPTRREG[15:12] -> CLK1 (0x0-0xF) 717 * CCPTRREG[11:08] -> CLK0 (0x0-0xF) 718 */ 719 reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); 720 msk = (BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8); 721 temp = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8); 722 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 723 724 /* Adjust PI_COUNT */ 725 pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; 726 727 /* 728 * PI (1/64 MCLK, 1 PIs) 729 * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F) 730 * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F) 731 */ 732 reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0; 733 reg += (channel * DDRIOCCC_CH_OFFSET); 734 msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16 | 735 BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8); 736 temp = (pi_count << 16) | (pi_count << 8); 737 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 738 reg = rank ? ECCB1DLLPICODER1 : ECCB1DLLPICODER1; 739 reg += (channel * DDRIOCCC_CH_OFFSET); 740 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 741 reg = rank ? ECCB1DLLPICODER2 : ECCB1DLLPICODER2; 742 reg += (channel * DDRIOCCC_CH_OFFSET); 743 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 744 reg = rank ? ECCB1DLLPICODER3 : ECCB1DLLPICODER3; 745 reg += (channel * DDRIOCCC_CH_OFFSET); 746 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 747 748 /* 749 * DEADBAND 750 * CCCFGREG1[11:08] (+1 select) 751 * CCCFGREG1[03:00] (enable) 752 */ 753 reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET); 754 msk = 0x00; 755 temp = 0x00; 756 757 /* enable */ 758 msk |= (BIT3 | BIT2 | BIT1 | BIT0); 759 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) 760 temp |= msk; 761 762 /* select */ 763 msk |= (BIT11 | BIT10 | BIT9 | BIT8); 764 if (pi_count < EARLY_DB) 765 temp |= msk; 766 767 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 768 769 /* error check */ 770 if (pi_count > 0x3F) 771 mrc_post_code(0xee, 0xe5); 772 773 LEAVEFN(); 774 } 775 776 /* 777 * This function will return the amout of WCLK delay on the given 778 * channel, rank as an absolute PI count. 779 */ 780 uint32_t get_wclk(uint8_t channel, uint8_t rank) 781 { 782 uint32_t reg; 783 uint32_t temp; 784 uint32_t pi_count; 785 786 ENTERFN(); 787 788 /* 789 * RDPTR (1/2 MCLK, 64 PIs) 790 * CCPTRREG[15:12] -> CLK1 (0x0-0xF) 791 * CCPTRREG[11:08] -> CLK0 (0x0-0xF) 792 */ 793 reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); 794 temp = msg_port_alt_read(DDRPHY, reg); 795 temp >>= rank ? 12 : 8; 796 temp &= 0xF; 797 798 /* Adjust PI_COUNT */ 799 pi_count = temp * HALF_CLK; 800 801 /* 802 * PI (1/64 MCLK, 1 PIs) 803 * ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F) 804 * ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F) 805 */ 806 reg = rank ? ECCB1DLLPICODER0 : ECCB1DLLPICODER0; 807 reg += (channel * DDRIOCCC_CH_OFFSET); 808 temp = msg_port_alt_read(DDRPHY, reg); 809 temp >>= rank ? 16 : 8; 810 temp &= 0x3F; 811 812 pi_count += temp; 813 814 LEAVEFN(); 815 816 return pi_count; 817 } 818 819 /* 820 * This function will program the WCTL delays based on an absolute 821 * number of PIs. 822 * 823 * (currently doesn't comprehend rank) 824 */ 825 void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count) 826 { 827 uint32_t reg; 828 uint32_t msk; 829 uint32_t temp; 830 831 ENTERFN(); 832 833 /* 834 * RDPTR (1/2 MCLK, 64 PIs) 835 * CCPTRREG[31:28] (0x0-0xF) 836 * CCPTRREG[27:24] (0x0-0xF) 837 */ 838 reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); 839 msk = (BIT31 | BIT30 | BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24); 840 temp = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24); 841 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 842 843 /* Adjust PI_COUNT */ 844 pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK; 845 846 /* 847 * PI (1/64 MCLK, 1 PIs) 848 * ECCB1DLLPICODER?[29:24] (0x00-0x3F) 849 * ECCB1DLLPICODER?[29:24] (0x00-0x3F) 850 */ 851 reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); 852 msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24); 853 temp = (pi_count << 24); 854 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 855 reg = ECCB1DLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET); 856 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 857 reg = ECCB1DLLPICODER2 + (channel * DDRIOCCC_CH_OFFSET); 858 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 859 reg = ECCB1DLLPICODER3 + (channel * DDRIOCCC_CH_OFFSET); 860 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 861 862 /* 863 * DEADBAND 864 * CCCFGREG1[13:12] (+1 select) 865 * CCCFGREG1[05:04] (enable) 866 */ 867 reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET); 868 msk = 0x00; 869 temp = 0x00; 870 871 /* enable */ 872 msk |= (BIT5 | BIT4); 873 if ((pi_count < EARLY_DB) || (pi_count > LATE_DB)) 874 temp |= msk; 875 876 /* select */ 877 msk |= (BIT13 | BIT12); 878 if (pi_count < EARLY_DB) 879 temp |= msk; 880 881 mrc_alt_write_mask(DDRPHY, reg, temp, msk); 882 883 /* error check */ 884 if (pi_count > 0x3F) 885 mrc_post_code(0xee, 0xe6); 886 887 LEAVEFN(); 888 } 889 890 /* 891 * This function will return the amount of WCTL delay on the given 892 * channel, rank as an absolute PI count. 893 * 894 * (currently doesn't comprehend rank) 895 */ 896 uint32_t get_wctl(uint8_t channel, uint8_t rank) 897 { 898 uint32_t reg; 899 uint32_t temp; 900 uint32_t pi_count; 901 902 ENTERFN(); 903 904 /* 905 * RDPTR (1/2 MCLK, 64 PIs) 906 * CCPTRREG[31:28] (0x0-0xF) 907 * CCPTRREG[27:24] (0x0-0xF) 908 */ 909 reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET); 910 temp = msg_port_alt_read(DDRPHY, reg); 911 temp >>= 24; 912 temp &= 0xF; 913 914 /* Adjust PI_COUNT */ 915 pi_count = temp * HALF_CLK; 916 917 /* 918 * PI (1/64 MCLK, 1 PIs) 919 * ECCB1DLLPICODER?[29:24] (0x00-0x3F) 920 * ECCB1DLLPICODER?[29:24] (0x00-0x3F) 921 */ 922 reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); 923 temp = msg_port_alt_read(DDRPHY, reg); 924 temp >>= 24; 925 temp &= 0x3F; 926 927 /* Adjust PI_COUNT */ 928 pi_count += temp; 929 930 LEAVEFN(); 931 932 return pi_count; 933 } 934 935 /* 936 * This function will program the internal Vref setting in a given 937 * byte lane in a given channel. 938 */ 939 void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting) 940 { 941 uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL); 942 943 ENTERFN(); 944 945 DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n", 946 channel, byte_lane, setting); 947 948 mrc_alt_write_mask(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + 949 ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)), 950 (vref_codes[setting] << 2), 951 (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2)); 952 953 /* 954 * need to wait ~300ns for Vref to settle 955 * (check that this is necessary) 956 */ 957 delay_n(300); 958 959 /* ??? may need to clear pointers ??? */ 960 961 LEAVEFN(); 962 } 963 964 /* 965 * This function will return the internal Vref setting for the given 966 * channel, byte_lane. 967 */ 968 uint32_t get_vref(uint8_t channel, uint8_t byte_lane) 969 { 970 uint8_t j; 971 uint32_t ret_val = sizeof(vref_codes) / 2; 972 uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL); 973 uint32_t temp; 974 975 ENTERFN(); 976 977 temp = msg_port_alt_read(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + 978 ((byte_lane >> 1) * DDRIODQ_BL_OFFSET))); 979 temp >>= 2; 980 temp &= 0x3F; 981 982 for (j = 0; j < sizeof(vref_codes); j++) { 983 if (vref_codes[j] == temp) { 984 ret_val = j; 985 break; 986 } 987 } 988 989 LEAVEFN(); 990 991 return ret_val; 992 } 993 994 /* 995 * This function will return a 32-bit address in the desired 996 * channel and rank. 997 */ 998 uint32_t get_addr(uint8_t channel, uint8_t rank) 999 { 1000 uint32_t offset = 0x02000000; /* 32MB */ 1001 1002 /* Begin product specific code */ 1003 if (channel > 0) { 1004 DPF(D_ERROR, "ILLEGAL CHANNEL\n"); 1005 DEAD_LOOP(); 1006 } 1007 1008 if (rank > 1) { 1009 DPF(D_ERROR, "ILLEGAL RANK\n"); 1010 DEAD_LOOP(); 1011 } 1012 1013 /* use 256MB lowest density as per DRP == 0x0003 */ 1014 offset += rank * (256 * 1024 * 1024); 1015 1016 return offset; 1017 } 1018 1019 /* 1020 * This function will sample the DQTRAINSTS registers in the given 1021 * channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'. 1022 * 1023 * It will return an encoded 32-bit date in which each bit corresponds to 1024 * the sampled value on the byte lane. 1025 */ 1026 uint32_t sample_dqs(struct mrc_params *mrc_params, uint8_t channel, 1027 uint8_t rank, bool rcvn) 1028 { 1029 uint8_t j; /* just a counter */ 1030 uint8_t bl; /* which BL in the module (always 2 per module) */ 1031 uint8_t bl_grp; /* which BL module */ 1032 /* byte lane divisor */ 1033 uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1; 1034 uint32_t msk[2]; /* BLx in module */ 1035 /* DQTRAINSTS register contents for each sample */ 1036 uint32_t sampled_val[SAMPLE_SIZE]; 1037 uint32_t num_0s; /* tracks the number of '0' samples */ 1038 uint32_t num_1s; /* tracks the number of '1' samples */ 1039 uint32_t ret_val = 0x00; /* assume all '0' samples */ 1040 uint32_t address = get_addr(channel, rank); 1041 1042 /* initialise msk[] */ 1043 msk[0] = rcvn ? BIT1 : BIT9; /* BL0 */ 1044 msk[1] = rcvn ? BIT0 : BIT8; /* BL1 */ 1045 1046 /* cycle through each byte lane group */ 1047 for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++) { 1048 /* take SAMPLE_SIZE samples */ 1049 for (j = 0; j < SAMPLE_SIZE; j++) { 1050 hte_mem_op(address, mrc_params->first_run, 1051 rcvn ? 0 : 1); 1052 mrc_params->first_run = 0; 1053 1054 /* 1055 * record the contents of the proper 1056 * DQTRAINSTS register 1057 */ 1058 sampled_val[j] = msg_port_alt_read(DDRPHY, 1059 (DQTRAINSTS + 1060 (bl_grp * DDRIODQ_BL_OFFSET) + 1061 (channel * DDRIODQ_CH_OFFSET))); 1062 } 1063 1064 /* 1065 * look for a majority value (SAMPLE_SIZE / 2) + 1 1066 * on the byte lane and set that value in the corresponding 1067 * ret_val bit 1068 */ 1069 for (bl = 0; bl < 2; bl++) { 1070 num_0s = 0x00; /* reset '0' tracker for byte lane */ 1071 num_1s = 0x00; /* reset '1' tracker for byte lane */ 1072 for (j = 0; j < SAMPLE_SIZE; j++) { 1073 if (sampled_val[j] & msk[bl]) 1074 num_1s++; 1075 else 1076 num_0s++; 1077 } 1078 if (num_1s > num_0s) 1079 ret_val |= (1 << (bl + (bl_grp * 2))); 1080 } 1081 } 1082 1083 /* 1084 * "ret_val.0" contains the status of BL0 1085 * "ret_val.1" contains the status of BL1 1086 * "ret_val.2" contains the status of BL2 1087 * etc. 1088 */ 1089 return ret_val; 1090 } 1091 1092 /* This function will find the rising edge transition on RCVN or WDQS */ 1093 void find_rising_edge(struct mrc_params *mrc_params, uint32_t delay[], 1094 uint8_t channel, uint8_t rank, bool rcvn) 1095 { 1096 bool all_edges_found; /* determines stop condition */ 1097 bool direction[NUM_BYTE_LANES]; /* direction indicator */ 1098 uint8_t sample; /* sample counter */ 1099 uint8_t bl; /* byte lane counter */ 1100 /* byte lane divisor */ 1101 uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1; 1102 uint32_t sample_result[SAMPLE_CNT]; /* results of sample_dqs() */ 1103 uint32_t temp; 1104 uint32_t transition_pattern; 1105 1106 ENTERFN(); 1107 1108 /* select hte and request initial configuration */ 1109 select_hte(); 1110 mrc_params->first_run = 1; 1111 1112 /* Take 3 sample points (T1,T2,T3) to obtain a transition pattern */ 1113 for (sample = 0; sample < SAMPLE_CNT; sample++) { 1114 /* program the desired delays for sample */ 1115 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) { 1116 /* increase sample delay by 26 PI (0.2 CLK) */ 1117 if (rcvn) { 1118 set_rcvn(channel, rank, bl, 1119 delay[bl] + (sample * SAMPLE_DLY)); 1120 } else { 1121 set_wdqs(channel, rank, bl, 1122 delay[bl] + (sample * SAMPLE_DLY)); 1123 } 1124 } 1125 1126 /* take samples (Tsample_i) */ 1127 sample_result[sample] = sample_dqs(mrc_params, 1128 channel, rank, rcvn); 1129 1130 DPF(D_TRN, 1131 "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n", 1132 (rcvn ? "RCVN" : "WDQS"), channel, rank, sample, 1133 sample * SAMPLE_DLY, sample_result[sample]); 1134 } 1135 1136 /* 1137 * This pattern will help determine where we landed and ultimately 1138 * how to place RCVEN/WDQS. 1139 */ 1140 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) { 1141 /* build transition_pattern (MSB is 1st sample) */ 1142 transition_pattern = 0; 1143 for (sample = 0; sample < SAMPLE_CNT; sample++) { 1144 transition_pattern |= 1145 ((sample_result[sample] & (1 << bl)) >> bl) << 1146 (SAMPLE_CNT - 1 - sample); 1147 } 1148 1149 DPF(D_TRN, "=== transition pattern %d\n", transition_pattern); 1150 1151 /* 1152 * set up to look for rising edge based on 1153 * transition_pattern 1154 */ 1155 switch (transition_pattern) { 1156 case 0: /* sampled 0->0->0 */ 1157 /* move forward from T3 looking for 0->1 */ 1158 delay[bl] += 2 * SAMPLE_DLY; 1159 direction[bl] = FORWARD; 1160 break; 1161 case 1: /* sampled 0->0->1 */ 1162 case 5: /* sampled 1->0->1 (bad duty cycle) *HSD#237503* */ 1163 /* move forward from T2 looking for 0->1 */ 1164 delay[bl] += 1 * SAMPLE_DLY; 1165 direction[bl] = FORWARD; 1166 break; 1167 case 2: /* sampled 0->1->0 (bad duty cycle) *HSD#237503* */ 1168 case 3: /* sampled 0->1->1 */ 1169 /* move forward from T1 looking for 0->1 */ 1170 delay[bl] += 0 * SAMPLE_DLY; 1171 direction[bl] = FORWARD; 1172 break; 1173 case 4: /* sampled 1->0->0 (assumes BL8, HSD#234975) */ 1174 /* move forward from T3 looking for 0->1 */ 1175 delay[bl] += 2 * SAMPLE_DLY; 1176 direction[bl] = FORWARD; 1177 break; 1178 case 6: /* sampled 1->1->0 */ 1179 case 7: /* sampled 1->1->1 */ 1180 /* move backward from T1 looking for 1->0 */ 1181 delay[bl] += 0 * SAMPLE_DLY; 1182 direction[bl] = BACKWARD; 1183 break; 1184 default: 1185 mrc_post_code(0xee, 0xee); 1186 break; 1187 } 1188 1189 /* program delays */ 1190 if (rcvn) 1191 set_rcvn(channel, rank, bl, delay[bl]); 1192 else 1193 set_wdqs(channel, rank, bl, delay[bl]); 1194 } 1195 1196 /* 1197 * Based on the observed transition pattern on the byte lane, 1198 * begin looking for a rising edge with single PI granularity. 1199 */ 1200 do { 1201 all_edges_found = true; /* assume all byte lanes passed */ 1202 /* take a sample */ 1203 temp = sample_dqs(mrc_params, channel, rank, rcvn); 1204 /* check all each byte lane for proper edge */ 1205 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) { 1206 if (temp & (1 << bl)) { 1207 /* sampled "1" */ 1208 if (direction[bl] == BACKWARD) { 1209 /* 1210 * keep looking for edge 1211 * on this byte lane 1212 */ 1213 all_edges_found = false; 1214 delay[bl] -= 1; 1215 if (rcvn) { 1216 set_rcvn(channel, rank, 1217 bl, delay[bl]); 1218 } else { 1219 set_wdqs(channel, rank, 1220 bl, delay[bl]); 1221 } 1222 } 1223 } else { 1224 /* sampled "0" */ 1225 if (direction[bl] == FORWARD) { 1226 /* 1227 * keep looking for edge 1228 * on this byte lane 1229 */ 1230 all_edges_found = false; 1231 delay[bl] += 1; 1232 if (rcvn) { 1233 set_rcvn(channel, rank, 1234 bl, delay[bl]); 1235 } else { 1236 set_wdqs(channel, rank, 1237 bl, delay[bl]); 1238 } 1239 } 1240 } 1241 } 1242 } while (!all_edges_found); 1243 1244 /* restore DDR idle state */ 1245 dram_init_command(DCMD_PREA(rank)); 1246 1247 DPF(D_TRN, "Delay %03X %03X %03X %03X\n", 1248 delay[0], delay[1], delay[2], delay[3]); 1249 1250 LEAVEFN(); 1251 } 1252 1253 /* 1254 * This function will return a 32 bit mask that will be used to 1255 * check for byte lane failures. 1256 */ 1257 uint32_t byte_lane_mask(struct mrc_params *mrc_params) 1258 { 1259 uint32_t j; 1260 uint32_t ret_val = 0x00; 1261 1262 /* 1263 * set ret_val based on NUM_BYTE_LANES such that you will check 1264 * only BL0 in result 1265 * 1266 * (each bit in result represents a byte lane) 1267 */ 1268 for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES) 1269 ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES)); 1270 1271 /* 1272 * HSD#235037 1273 * need to adjust the mask for 16-bit mode 1274 */ 1275 if (mrc_params->channel_width == X16) 1276 ret_val |= (ret_val << 2); 1277 1278 return ret_val; 1279 } 1280 1281 /* 1282 * Check memory executing simple write/read/verify at the specified address. 1283 * 1284 * Bits in the result indicate failure on specific byte lane. 1285 */ 1286 uint32_t check_rw_coarse(struct mrc_params *mrc_params, uint32_t address) 1287 { 1288 uint32_t result = 0; 1289 uint8_t first_run = 0; 1290 1291 if (mrc_params->hte_setup) { 1292 mrc_params->hte_setup = 0; 1293 first_run = 1; 1294 select_hte(); 1295 } 1296 1297 result = hte_basic_write_read(mrc_params, address, first_run, 1298 WRITE_TRAIN); 1299 1300 DPF(D_TRN, "check_rw_coarse result is %x\n", result); 1301 1302 return result; 1303 } 1304 1305 /* 1306 * Check memory executing write/read/verify of many data patterns 1307 * at the specified address. Bits in the result indicate failure 1308 * on specific byte lane. 1309 */ 1310 uint32_t check_bls_ex(struct mrc_params *mrc_params, uint32_t address) 1311 { 1312 uint32_t result; 1313 uint8_t first_run = 0; 1314 1315 if (mrc_params->hte_setup) { 1316 mrc_params->hte_setup = 0; 1317 first_run = 1; 1318 select_hte(); 1319 } 1320 1321 result = hte_write_stress_bit_lanes(mrc_params, address, first_run); 1322 1323 DPF(D_TRN, "check_bls_ex result is %x\n", result); 1324 1325 return result; 1326 } 1327 1328 /* 1329 * 32-bit LFSR with characteristic polynomial: X^32 + X^22 +X^2 + X^1 1330 * 1331 * The function takes pointer to previous 32 bit value and 1332 * modifies it to next value. 1333 */ 1334 void lfsr32(uint32_t *lfsr_ptr) 1335 { 1336 uint32_t bit; 1337 uint32_t lfsr; 1338 int i; 1339 1340 lfsr = *lfsr_ptr; 1341 1342 for (i = 0; i < 32; i++) { 1343 bit = 1 ^ (lfsr & BIT0); 1344 bit = bit ^ ((lfsr & BIT1) >> 1); 1345 bit = bit ^ ((lfsr & BIT2) >> 2); 1346 bit = bit ^ ((lfsr & BIT22) >> 22); 1347 1348 lfsr = ((lfsr >> 1) | (bit << 31)); 1349 } 1350 1351 *lfsr_ptr = lfsr; 1352 } 1353 1354 /* Clear the pointers in a given byte lane in a given channel */ 1355 void clear_pointers(void) 1356 { 1357 uint8_t channel; 1358 uint8_t bl; 1359 1360 ENTERFN(); 1361 1362 for (channel = 0; channel < NUM_CHANNELS; channel++) { 1363 for (bl = 0; bl < NUM_BYTE_LANES; bl++) { 1364 mrc_alt_write_mask(DDRPHY, 1365 (B01PTRCTL1 + 1366 (channel * DDRIODQ_CH_OFFSET) + 1367 ((bl >> 1) * DDRIODQ_BL_OFFSET)), 1368 ~BIT8, BIT8); 1369 1370 mrc_alt_write_mask(DDRPHY, 1371 (B01PTRCTL1 + 1372 (channel * DDRIODQ_CH_OFFSET) + 1373 ((bl >> 1) * DDRIODQ_BL_OFFSET)), 1374 BIT8, BIT8); 1375 } 1376 } 1377 1378 LEAVEFN(); 1379 } 1380 1381 static void print_timings_internal(uint8_t algo, uint8_t channel, uint8_t rank, 1382 uint8_t bl_divisor) 1383 { 1384 uint8_t bl; 1385 1386 switch (algo) { 1387 case RCVN: 1388 DPF(D_INFO, "\nRCVN[%02d:%02d]", channel, rank); 1389 break; 1390 case WDQS: 1391 DPF(D_INFO, "\nWDQS[%02d:%02d]", channel, rank); 1392 break; 1393 case WDQX: 1394 DPF(D_INFO, "\nWDQx[%02d:%02d]", channel, rank); 1395 break; 1396 case RDQS: 1397 DPF(D_INFO, "\nRDQS[%02d:%02d]", channel, rank); 1398 break; 1399 case VREF: 1400 DPF(D_INFO, "\nVREF[%02d:%02d]", channel, rank); 1401 break; 1402 case WCMD: 1403 DPF(D_INFO, "\nWCMD[%02d:%02d]", channel, rank); 1404 break; 1405 case WCTL: 1406 DPF(D_INFO, "\nWCTL[%02d:%02d]", channel, rank); 1407 break; 1408 case WCLK: 1409 DPF(D_INFO, "\nWCLK[%02d:%02d]", channel, rank); 1410 break; 1411 default: 1412 break; 1413 } 1414 1415 for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) { 1416 switch (algo) { 1417 case RCVN: 1418 DPF(D_INFO, " %03d", get_rcvn(channel, rank, bl)); 1419 break; 1420 case WDQS: 1421 DPF(D_INFO, " %03d", get_wdqs(channel, rank, bl)); 1422 break; 1423 case WDQX: 1424 DPF(D_INFO, " %03d", get_wdq(channel, rank, bl)); 1425 break; 1426 case RDQS: 1427 DPF(D_INFO, " %03d", get_rdqs(channel, rank, bl)); 1428 break; 1429 case VREF: 1430 DPF(D_INFO, " %03d", get_vref(channel, bl)); 1431 break; 1432 case WCMD: 1433 DPF(D_INFO, " %03d", get_wcmd(channel)); 1434 break; 1435 case WCTL: 1436 DPF(D_INFO, " %03d", get_wctl(channel, rank)); 1437 break; 1438 case WCLK: 1439 DPF(D_INFO, " %03d", get_wclk(channel, rank)); 1440 break; 1441 default: 1442 break; 1443 } 1444 } 1445 } 1446 1447 void print_timings(struct mrc_params *mrc_params) 1448 { 1449 uint8_t algo; 1450 uint8_t channel; 1451 uint8_t rank; 1452 uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1; 1453 1454 DPF(D_INFO, "\n---------------------------"); 1455 DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3"); 1456 DPF(D_INFO, "\n==========================="); 1457 1458 for (algo = 0; algo < MAX_ALGOS; algo++) { 1459 for (channel = 0; channel < NUM_CHANNELS; channel++) { 1460 if (mrc_params->channel_enables & (1 << channel)) { 1461 for (rank = 0; rank < NUM_RANKS; rank++) { 1462 if (mrc_params->rank_enables & 1463 (1 << rank)) { 1464 print_timings_internal(algo, 1465 channel, rank, 1466 bl_divisor); 1467 } 1468 } 1469 } 1470 } 1471 } 1472 1473 DPF(D_INFO, "\n---------------------------"); 1474 DPF(D_INFO, "\n"); 1475 } 1476