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