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/mrc.h> 13 #include <asm/arch/msg_port.h> 14 #include "mrc_util.h" 15 #include "hte.h" 16 17 /** 18 * Enable HTE to detect all possible errors for the given training parameters 19 * (per-bit or full byte lane). 20 */ 21 static void hte_enable_all_errors(void) 22 { 23 msg_port_write(HTE, 0x000200A2, 0xFFFFFFFF); 24 msg_port_write(HTE, 0x000200A3, 0x000000FF); 25 msg_port_write(HTE, 0x000200A4, 0x00000000); 26 } 27 28 /** 29 * Go and read the HTE register in order to find any error 30 * 31 * @return: The errors detected in the HTE status register 32 */ 33 static u32 hte_check_errors(void) 34 { 35 return msg_port_read(HTE, 0x000200A7); 36 } 37 38 /** 39 * Wait until HTE finishes 40 */ 41 static void hte_wait_for_complete(void) 42 { 43 u32 tmp; 44 45 ENTERFN(); 46 47 do {} while ((msg_port_read(HTE, 0x00020012) & BIT30) != 0); 48 49 tmp = msg_port_read(HTE, 0x00020011); 50 tmp |= BIT9; 51 tmp &= ~(BIT12 | BIT13); 52 msg_port_write(HTE, 0x00020011, tmp); 53 54 LEAVEFN(); 55 } 56 57 /** 58 * Clear registers related with errors in the HTE 59 */ 60 static void hte_clear_error_regs(void) 61 { 62 u32 tmp; 63 64 /* 65 * Clear all HTE errors and enable error checking 66 * for burst and chunk. 67 */ 68 tmp = msg_port_read(HTE, 0x000200A1); 69 tmp |= BIT8; 70 msg_port_write(HTE, 0x000200A1, tmp); 71 } 72 73 /** 74 * Execute a basic single-cache-line memory write/read/verify test using simple 75 * constant pattern, different for READ_TRAIN and WRITE_TRAIN modes. 76 * 77 * See hte_basic_write_read() which is the external visible wrapper. 78 * 79 * @mrc_params: host structure for all MRC global data 80 * @addr: memory adress being tested (must hit specific channel/rank) 81 * @first_run: if set then the HTE registers are configured, otherwise it is 82 * assumed configuration is done and we just re-run the test 83 * @mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern) 84 * 85 * @return: byte lane failure on each bit (for Quark only bit0 and bit1) 86 */ 87 static u16 hte_basic_data_cmp(struct mrc_params *mrc_params, u32 addr, 88 u8 first_run, u8 mode) 89 { 90 u32 pattern; 91 u32 offset; 92 93 if (first_run) { 94 msg_port_write(HTE, 0x00020020, 0x01B10021); 95 msg_port_write(HTE, 0x00020021, 0x06000000); 96 msg_port_write(HTE, 0x00020022, addr >> 6); 97 msg_port_write(HTE, 0x00020062, 0x00800015); 98 msg_port_write(HTE, 0x00020063, 0xAAAAAAAA); 99 msg_port_write(HTE, 0x00020064, 0xCCCCCCCC); 100 msg_port_write(HTE, 0x00020065, 0xF0F0F0F0); 101 msg_port_write(HTE, 0x00020061, 0x00030008); 102 103 if (mode == WRITE_TRAIN) 104 pattern = 0xC33C0000; 105 else /* READ_TRAIN */ 106 pattern = 0xAA5555AA; 107 108 for (offset = 0x80; offset <= 0x8F; offset++) 109 msg_port_write(HTE, offset, pattern); 110 } 111 112 msg_port_write(HTE, 0x000200A1, 0xFFFF1000); 113 msg_port_write(HTE, 0x00020011, 0x00011000); 114 msg_port_write(HTE, 0x00020011, 0x00011100); 115 116 hte_wait_for_complete(); 117 118 /* 119 * Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for 120 * any bytelane errors. 121 */ 122 return (hte_check_errors() >> 8) & 0xFF; 123 } 124 125 /** 126 * Examine a single-cache-line memory with write/read/verify test using multiple 127 * data patterns (victim-aggressor algorithm). 128 * 129 * See hte_write_stress_bit_lanes() which is the external visible wrapper. 130 * 131 * @mrc_params: host structure for all MRC global data 132 * @addr: memory adress being tested (must hit specific channel/rank) 133 * @loop_cnt: number of test iterations 134 * @seed_victim: victim data pattern seed 135 * @seed_aggressor: aggressor data pattern seed 136 * @victim_bit: should be 0 as auto-rotate feature is in use 137 * @first_run: if set then the HTE registers are configured, otherwise it is 138 * assumed configuration is done and we just re-run the test 139 * 140 * @return: byte lane failure on each bit (for Quark only bit0 and bit1) 141 */ 142 static u16 hte_rw_data_cmp(struct mrc_params *mrc_params, u32 addr, 143 u8 loop_cnt, u32 seed_victim, u32 seed_aggressor, 144 u8 victim_bit, u8 first_run) 145 { 146 u32 offset; 147 u32 tmp; 148 149 if (first_run) { 150 msg_port_write(HTE, 0x00020020, 0x00910024); 151 msg_port_write(HTE, 0x00020023, 0x00810024); 152 msg_port_write(HTE, 0x00020021, 0x06070000); 153 msg_port_write(HTE, 0x00020024, 0x06070000); 154 msg_port_write(HTE, 0x00020022, addr >> 6); 155 msg_port_write(HTE, 0x00020025, addr >> 6); 156 msg_port_write(HTE, 0x00020062, 0x0000002A); 157 msg_port_write(HTE, 0x00020063, seed_victim); 158 msg_port_write(HTE, 0x00020064, seed_aggressor); 159 msg_port_write(HTE, 0x00020065, seed_victim); 160 161 /* 162 * Write the pattern buffers to select the victim bit 163 * 164 * Start with bit0 165 */ 166 for (offset = 0x80; offset <= 0x8F; offset++) { 167 if ((offset % 8) == victim_bit) 168 msg_port_write(HTE, offset, 0x55555555); 169 else 170 msg_port_write(HTE, offset, 0xCCCCCCCC); 171 } 172 173 msg_port_write(HTE, 0x00020061, 0x00000000); 174 msg_port_write(HTE, 0x00020066, 0x03440000); 175 msg_port_write(HTE, 0x000200A1, 0xFFFF1000); 176 } 177 178 tmp = 0x10001000 | (loop_cnt << 16); 179 msg_port_write(HTE, 0x00020011, tmp); 180 msg_port_write(HTE, 0x00020011, tmp | BIT8); 181 182 hte_wait_for_complete(); 183 184 /* 185 * Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for 186 * any bytelane errors. 187 */ 188 return (hte_check_errors() >> 8) & 0xFF; 189 } 190 191 /** 192 * Use HW HTE engine to initialize or test all memory attached to a given DUNIT. 193 * If flag is MRC_MEM_INIT, this routine writes 0s to all memory locations to 194 * initialize ECC. If flag is MRC_MEM_TEST, this routine will send an 5AA55AA5 195 * pattern to all memory locations on the RankMask and then read it back. 196 * Then it sends an A55AA55A pattern to all memory locations on the RankMask 197 * and reads it back. 198 * 199 * @mrc_params: host structure for all MRC global data 200 * @flag: MRC_MEM_INIT or MRC_MEM_TEST 201 * 202 * @return: errors register showing HTE failures. Also prints out which rank 203 * failed the HTE test if failure occurs. For rank detection to work, 204 * the address map must be left in its default state. If MRC changes 205 * the address map, this function must be modified to change it back 206 * to default at the beginning, then restore it at the end. 207 */ 208 u32 hte_mem_init(struct mrc_params *mrc_params, u8 flag) 209 { 210 u32 offset; 211 int test_num; 212 int i; 213 214 /* 215 * Clear out the error registers at the start of each memory 216 * init or memory test run. 217 */ 218 hte_clear_error_regs(); 219 220 msg_port_write(HTE, 0x00020062, 0x00000015); 221 222 for (offset = 0x80; offset <= 0x8F; offset++) 223 msg_port_write(HTE, offset, ((offset & 1) ? 0xA55A : 0x5AA5)); 224 225 msg_port_write(HTE, 0x00020021, 0x00000000); 226 msg_port_write(HTE, 0x00020022, (mrc_params->mem_size >> 6) - 1); 227 msg_port_write(HTE, 0x00020063, 0xAAAAAAAA); 228 msg_port_write(HTE, 0x00020064, 0xCCCCCCCC); 229 msg_port_write(HTE, 0x00020065, 0xF0F0F0F0); 230 msg_port_write(HTE, 0x00020066, 0x03000000); 231 232 switch (flag) { 233 case MRC_MEM_INIT: 234 /* 235 * Only 1 write pass through memory is needed 236 * to initialize ECC 237 */ 238 test_num = 1; 239 break; 240 case MRC_MEM_TEST: 241 /* Write/read then write/read with inverted pattern */ 242 test_num = 4; 243 break; 244 default: 245 DPF(D_INFO, "Unknown parameter for flag: %d\n", flag); 246 return 0xFFFFFFFF; 247 } 248 249 DPF(D_INFO, "hte_mem_init"); 250 251 for (i = 0; i < test_num; i++) { 252 DPF(D_INFO, "."); 253 254 if (i == 0) { 255 msg_port_write(HTE, 0x00020061, 0x00000000); 256 msg_port_write(HTE, 0x00020020, 0x00110010); 257 } else if (i == 1) { 258 msg_port_write(HTE, 0x00020061, 0x00000000); 259 msg_port_write(HTE, 0x00020020, 0x00010010); 260 } else if (i == 2) { 261 msg_port_write(HTE, 0x00020061, 0x00010100); 262 msg_port_write(HTE, 0x00020020, 0x00110010); 263 } else { 264 msg_port_write(HTE, 0x00020061, 0x00010100); 265 msg_port_write(HTE, 0x00020020, 0x00010010); 266 } 267 268 msg_port_write(HTE, 0x00020011, 0x00111000); 269 msg_port_write(HTE, 0x00020011, 0x00111100); 270 271 hte_wait_for_complete(); 272 273 /* If this is a READ pass, check for errors at the end */ 274 if ((i % 2) == 1) { 275 /* Return immediately if error */ 276 if (hte_check_errors()) 277 break; 278 } 279 } 280 281 DPF(D_INFO, "done\n"); 282 283 return hte_check_errors(); 284 } 285 286 /** 287 * Execute a basic single-cache-line memory write/read/verify test using simple 288 * constant pattern, different for READ_TRAIN and WRITE_TRAIN modes. 289 * 290 * @mrc_params: host structure for all MRC global data 291 * @addr: memory adress being tested (must hit specific channel/rank) 292 * @first_run: if set then the HTE registers are configured, otherwise it is 293 * assumed configuration is done and we just re-run the test 294 * @mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern) 295 * 296 * @return: byte lane failure on each bit (for Quark only bit0 and bit1) 297 */ 298 u16 hte_basic_write_read(struct mrc_params *mrc_params, u32 addr, 299 u8 first_run, u8 mode) 300 { 301 u16 errors; 302 303 ENTERFN(); 304 305 /* Enable all error reporting in preparation for HTE test */ 306 hte_enable_all_errors(); 307 hte_clear_error_regs(); 308 309 errors = hte_basic_data_cmp(mrc_params, addr, first_run, mode); 310 311 LEAVEFN(); 312 313 return errors; 314 } 315 316 /** 317 * Examine a single-cache-line memory with write/read/verify test using multiple 318 * data patterns (victim-aggressor algorithm). 319 * 320 * @mrc_params: host structure for all MRC global data 321 * @addr: memory adress being tested (must hit specific channel/rank) 322 * @first_run: if set then the HTE registers are configured, otherwise it is 323 * assumed configuration is done and we just re-run the test 324 * 325 * @return: byte lane failure on each bit (for Quark only bit0 and bit1) 326 */ 327 u16 hte_write_stress_bit_lanes(struct mrc_params *mrc_params, 328 u32 addr, u8 first_run) 329 { 330 u16 errors; 331 u8 victim_bit = 0; 332 333 ENTERFN(); 334 335 /* Enable all error reporting in preparation for HTE test */ 336 hte_enable_all_errors(); 337 hte_clear_error_regs(); 338 339 /* 340 * Loop through each bit in the bytelane. 341 * 342 * Each pass creates a victim bit while keeping all other bits the same 343 * as aggressors. AVN HTE adds an auto-rotate feature which allows us 344 * to program the entire victim/aggressor sequence in 1 step. 345 * 346 * The victim bit rotates on each pass so no need to have software 347 * implement a victim bit loop like on VLV. 348 */ 349 errors = hte_rw_data_cmp(mrc_params, addr, HTE_LOOP_CNT, 350 HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, 351 victim_bit, first_run); 352 353 LEAVEFN(); 354 355 return errors; 356 } 357 358 /** 359 * Execute a basic single-cache-line memory write or read. 360 * This is just for receive enable / fine write-levelling purpose. 361 * 362 * @addr: memory adress being tested (must hit specific channel/rank) 363 * @first_run: if set then the HTE registers are configured, otherwise it is 364 * assumed configuration is done and we just re-run the test 365 * @is_write: when non-zero memory write operation executed, otherwise read 366 */ 367 void hte_mem_op(u32 addr, u8 first_run, u8 is_write) 368 { 369 u32 offset; 370 u32 tmp; 371 372 hte_enable_all_errors(); 373 hte_clear_error_regs(); 374 375 if (first_run) { 376 tmp = is_write ? 0x01110021 : 0x01010021; 377 msg_port_write(HTE, 0x00020020, tmp); 378 379 msg_port_write(HTE, 0x00020021, 0x06000000); 380 msg_port_write(HTE, 0x00020022, addr >> 6); 381 msg_port_write(HTE, 0x00020062, 0x00800015); 382 msg_port_write(HTE, 0x00020063, 0xAAAAAAAA); 383 msg_port_write(HTE, 0x00020064, 0xCCCCCCCC); 384 msg_port_write(HTE, 0x00020065, 0xF0F0F0F0); 385 msg_port_write(HTE, 0x00020061, 0x00030008); 386 387 for (offset = 0x80; offset <= 0x8F; offset++) 388 msg_port_write(HTE, offset, 0xC33C0000); 389 } 390 391 msg_port_write(HTE, 0x000200A1, 0xFFFF1000); 392 msg_port_write(HTE, 0x00020011, 0x00011000); 393 msg_port_write(HTE, 0x00020011, 0x00011100); 394 395 hte_wait_for_complete(); 396 } 397