1*b35ce0c4SPankaj Gupta /* 2*b35ce0c4SPankaj Gupta * Copyright 2021 NXP 3*b35ce0c4SPankaj Gupta * 4*b35ce0c4SPankaj Gupta * SPDX-License-Identifier: BSD-3-Clause 5*b35ce0c4SPankaj Gupta * 6*b35ce0c4SPankaj Gupta */ 7*b35ce0c4SPankaj Gupta 8*b35ce0c4SPankaj Gupta #include <errno.h> 9*b35ce0c4SPankaj Gupta #include <stdbool.h> 10*b35ce0c4SPankaj Gupta #include <stdint.h> 11*b35ce0c4SPankaj Gupta #include <stdio.h> 12*b35ce0c4SPankaj Gupta #include <stdlib.h> 13*b35ce0c4SPankaj Gupta #include <string.h> 14*b35ce0c4SPankaj Gupta 15*b35ce0c4SPankaj Gupta 16*b35ce0c4SPankaj Gupta #include <common/debug.h> 17*b35ce0c4SPankaj Gupta #include <ddr.h> 18*b35ce0c4SPankaj Gupta #include <dimm.h> 19*b35ce0c4SPankaj Gupta #include <i2c.h> 20*b35ce0c4SPankaj Gupta #include <lib/utils.h> 21*b35ce0c4SPankaj Gupta 22*b35ce0c4SPankaj Gupta int read_spd(unsigned char chip, void *buf, int len) 23*b35ce0c4SPankaj Gupta { 24*b35ce0c4SPankaj Gupta unsigned char dummy = 0U; 25*b35ce0c4SPankaj Gupta int ret; 26*b35ce0c4SPankaj Gupta 27*b35ce0c4SPankaj Gupta if (len < 256) { 28*b35ce0c4SPankaj Gupta ERROR("Invalid SPD length\n"); 29*b35ce0c4SPankaj Gupta return -EINVAL; 30*b35ce0c4SPankaj Gupta } 31*b35ce0c4SPankaj Gupta 32*b35ce0c4SPankaj Gupta i2c_write(SPD_SPA0_ADDRESS, 0, 1, &dummy, 1); 33*b35ce0c4SPankaj Gupta ret = i2c_read(chip, 0, 1, buf, 256); 34*b35ce0c4SPankaj Gupta if (ret == 0) { 35*b35ce0c4SPankaj Gupta i2c_write(SPD_SPA1_ADDRESS, 0, 1, &dummy, 1); 36*b35ce0c4SPankaj Gupta ret = i2c_read(chip, 0, 1, buf + 256, min(256, len - 256)); 37*b35ce0c4SPankaj Gupta } 38*b35ce0c4SPankaj Gupta if (ret != 0) { 39*b35ce0c4SPankaj Gupta zeromem(buf, len); 40*b35ce0c4SPankaj Gupta } 41*b35ce0c4SPankaj Gupta 42*b35ce0c4SPankaj Gupta return ret; 43*b35ce0c4SPankaj Gupta } 44*b35ce0c4SPankaj Gupta 45*b35ce0c4SPankaj Gupta int crc16(unsigned char *ptr, int count) 46*b35ce0c4SPankaj Gupta { 47*b35ce0c4SPankaj Gupta int i; 48*b35ce0c4SPankaj Gupta int crc = 0; 49*b35ce0c4SPankaj Gupta 50*b35ce0c4SPankaj Gupta while (--count >= 0) { 51*b35ce0c4SPankaj Gupta crc = crc ^ (int)*ptr++ << 8; 52*b35ce0c4SPankaj Gupta for (i = 0; i < 8; ++i) { 53*b35ce0c4SPankaj Gupta if ((crc & 0x8000) != 0) { 54*b35ce0c4SPankaj Gupta crc = crc << 1 ^ 0x1021; 55*b35ce0c4SPankaj Gupta } else { 56*b35ce0c4SPankaj Gupta crc = crc << 1; 57*b35ce0c4SPankaj Gupta } 58*b35ce0c4SPankaj Gupta } 59*b35ce0c4SPankaj Gupta } 60*b35ce0c4SPankaj Gupta return crc & 0xffff; 61*b35ce0c4SPankaj Gupta } 62*b35ce0c4SPankaj Gupta 63*b35ce0c4SPankaj Gupta static int ddr4_spd_check(const struct ddr4_spd *spd) 64*b35ce0c4SPankaj Gupta { 65*b35ce0c4SPankaj Gupta void *p = (void *)spd; 66*b35ce0c4SPankaj Gupta int csum16; 67*b35ce0c4SPankaj Gupta int len; 68*b35ce0c4SPankaj Gupta char crc_lsb; /* byte 126 */ 69*b35ce0c4SPankaj Gupta char crc_msb; /* byte 127 */ 70*b35ce0c4SPankaj Gupta 71*b35ce0c4SPankaj Gupta len = 126; 72*b35ce0c4SPankaj Gupta csum16 = crc16(p, len); 73*b35ce0c4SPankaj Gupta 74*b35ce0c4SPankaj Gupta crc_lsb = (char) (csum16 & 0xff); 75*b35ce0c4SPankaj Gupta crc_msb = (char) (csum16 >> 8); 76*b35ce0c4SPankaj Gupta 77*b35ce0c4SPankaj Gupta if (spd->crc[0] != crc_lsb || spd->crc[1] != crc_msb) { 78*b35ce0c4SPankaj Gupta ERROR("SPD CRC = 0x%x%x, computed CRC = 0x%x%x\n", 79*b35ce0c4SPankaj Gupta spd->crc[1], spd->crc[0], crc_msb, crc_lsb); 80*b35ce0c4SPankaj Gupta return -EINVAL; 81*b35ce0c4SPankaj Gupta } 82*b35ce0c4SPankaj Gupta 83*b35ce0c4SPankaj Gupta p = (void *)spd + 128; 84*b35ce0c4SPankaj Gupta len = 126; 85*b35ce0c4SPankaj Gupta csum16 = crc16(p, len); 86*b35ce0c4SPankaj Gupta 87*b35ce0c4SPankaj Gupta crc_lsb = (char) (csum16 & 0xff); 88*b35ce0c4SPankaj Gupta crc_msb = (char) (csum16 >> 8); 89*b35ce0c4SPankaj Gupta 90*b35ce0c4SPankaj Gupta if (spd->mod_section.uc[126] != crc_lsb || 91*b35ce0c4SPankaj Gupta spd->mod_section.uc[127] != crc_msb) { 92*b35ce0c4SPankaj Gupta ERROR("SPD CRC = 0x%x%x, computed CRC = 0x%x%x\n", 93*b35ce0c4SPankaj Gupta spd->mod_section.uc[127], spd->mod_section.uc[126], 94*b35ce0c4SPankaj Gupta crc_msb, crc_lsb); 95*b35ce0c4SPankaj Gupta return -EINVAL; 96*b35ce0c4SPankaj Gupta } 97*b35ce0c4SPankaj Gupta 98*b35ce0c4SPankaj Gupta return 0; 99*b35ce0c4SPankaj Gupta } 100*b35ce0c4SPankaj Gupta 101*b35ce0c4SPankaj Gupta static unsigned long long 102*b35ce0c4SPankaj Gupta compute_ranksize(const struct ddr4_spd *spd) 103*b35ce0c4SPankaj Gupta { 104*b35ce0c4SPankaj Gupta unsigned long long bsize; 105*b35ce0c4SPankaj Gupta 106*b35ce0c4SPankaj Gupta int nbit_sdram_cap_bsize = 0; 107*b35ce0c4SPankaj Gupta int nbit_primary_bus_width = 0; 108*b35ce0c4SPankaj Gupta int nbit_sdram_width = 0; 109*b35ce0c4SPankaj Gupta int die_count = 0; 110*b35ce0c4SPankaj Gupta bool package_3ds; 111*b35ce0c4SPankaj Gupta 112*b35ce0c4SPankaj Gupta if ((spd->density_banks & 0xf) <= 7) { 113*b35ce0c4SPankaj Gupta nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28; 114*b35ce0c4SPankaj Gupta } 115*b35ce0c4SPankaj Gupta if ((spd->bus_width & 0x7) < 4) { 116*b35ce0c4SPankaj Gupta nbit_primary_bus_width = (spd->bus_width & 0x7) + 3; 117*b35ce0c4SPankaj Gupta } 118*b35ce0c4SPankaj Gupta if ((spd->organization & 0x7) < 4) { 119*b35ce0c4SPankaj Gupta nbit_sdram_width = (spd->organization & 0x7) + 2; 120*b35ce0c4SPankaj Gupta } 121*b35ce0c4SPankaj Gupta package_3ds = (spd->package_type & 0x3) == 0x2; 122*b35ce0c4SPankaj Gupta if (package_3ds) { 123*b35ce0c4SPankaj Gupta die_count = (spd->package_type >> 4) & 0x7; 124*b35ce0c4SPankaj Gupta } 125*b35ce0c4SPankaj Gupta 126*b35ce0c4SPankaj Gupta bsize = 1ULL << (nbit_sdram_cap_bsize - 3 + 127*b35ce0c4SPankaj Gupta nbit_primary_bus_width - nbit_sdram_width + 128*b35ce0c4SPankaj Gupta die_count); 129*b35ce0c4SPankaj Gupta 130*b35ce0c4SPankaj Gupta return bsize; 131*b35ce0c4SPankaj Gupta } 132*b35ce0c4SPankaj Gupta 133*b35ce0c4SPankaj Gupta int cal_dimm_params(const struct ddr4_spd *spd, struct dimm_params *pdimm) 134*b35ce0c4SPankaj Gupta { 135*b35ce0c4SPankaj Gupta int ret; 136*b35ce0c4SPankaj Gupta int i; 137*b35ce0c4SPankaj Gupta static const unsigned char udimm_rc_e_dq[18] = { 138*b35ce0c4SPankaj Gupta 0x0c, 0x2c, 0x15, 0x35, 0x15, 0x35, 0x0b, 0x2c, 0x15, 139*b35ce0c4SPankaj Gupta 0x35, 0x0b, 0x35, 0x0b, 0x2c, 0x0b, 0x35, 0x15, 0x36 140*b35ce0c4SPankaj Gupta }; 141*b35ce0c4SPankaj Gupta int spd_error = 0; 142*b35ce0c4SPankaj Gupta unsigned char *ptr; 143*b35ce0c4SPankaj Gupta unsigned char val; 144*b35ce0c4SPankaj Gupta 145*b35ce0c4SPankaj Gupta if (spd->mem_type != SPD_MEMTYPE_DDR4) { 146*b35ce0c4SPankaj Gupta ERROR("Not a DDR4 DIMM.\n"); 147*b35ce0c4SPankaj Gupta return -EINVAL; 148*b35ce0c4SPankaj Gupta } 149*b35ce0c4SPankaj Gupta 150*b35ce0c4SPankaj Gupta ret = ddr4_spd_check(spd); 151*b35ce0c4SPankaj Gupta if (ret != 0) { 152*b35ce0c4SPankaj Gupta ERROR("DIMM SPD checksum mismatch\n"); 153*b35ce0c4SPankaj Gupta return -EINVAL; 154*b35ce0c4SPankaj Gupta } 155*b35ce0c4SPankaj Gupta 156*b35ce0c4SPankaj Gupta /* 157*b35ce0c4SPankaj Gupta * The part name in ASCII in the SPD EEPROM is not null terminated. 158*b35ce0c4SPankaj Gupta * Guarantee null termination here by presetting all bytes to 0 159*b35ce0c4SPankaj Gupta * and copying the part name in ASCII from the SPD onto it 160*b35ce0c4SPankaj Gupta */ 161*b35ce0c4SPankaj Gupta if ((spd->info_size_crc & 0xF) > 2) { 162*b35ce0c4SPankaj Gupta memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); 163*b35ce0c4SPankaj Gupta } 164*b35ce0c4SPankaj Gupta 165*b35ce0c4SPankaj Gupta /* DIMM organization parameters */ 166*b35ce0c4SPankaj Gupta pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1; 167*b35ce0c4SPankaj Gupta debug("n_ranks %d\n", pdimm->n_ranks); 168*b35ce0c4SPankaj Gupta pdimm->rank_density = compute_ranksize(spd); 169*b35ce0c4SPankaj Gupta if (pdimm->rank_density == 0) { 170*b35ce0c4SPankaj Gupta return -EINVAL; 171*b35ce0c4SPankaj Gupta } 172*b35ce0c4SPankaj Gupta 173*b35ce0c4SPankaj Gupta debug("rank_density 0x%llx\n", pdimm->rank_density); 174*b35ce0c4SPankaj Gupta pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; 175*b35ce0c4SPankaj Gupta debug("capacity 0x%llx\n", pdimm->capacity); 176*b35ce0c4SPankaj Gupta pdimm->die_density = spd->density_banks & 0xf; 177*b35ce0c4SPankaj Gupta debug("die density 0x%x\n", pdimm->die_density); 178*b35ce0c4SPankaj Gupta pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7)); 179*b35ce0c4SPankaj Gupta debug("primary_sdram_width %d\n", pdimm->primary_sdram_width); 180*b35ce0c4SPankaj Gupta if (((spd->bus_width >> 3) & 0x3) != 0) { 181*b35ce0c4SPankaj Gupta pdimm->ec_sdram_width = 8; 182*b35ce0c4SPankaj Gupta } else { 183*b35ce0c4SPankaj Gupta pdimm->ec_sdram_width = 0; 184*b35ce0c4SPankaj Gupta } 185*b35ce0c4SPankaj Gupta debug("ec_sdram_width %d\n", pdimm->ec_sdram_width); 186*b35ce0c4SPankaj Gupta pdimm->device_width = 1 << ((spd->organization & 0x7) + 2); 187*b35ce0c4SPankaj Gupta debug("device_width %d\n", pdimm->device_width); 188*b35ce0c4SPankaj Gupta pdimm->package_3ds = (spd->package_type & 0x3) == 0x2 ? 189*b35ce0c4SPankaj Gupta (spd->package_type >> 4) & 0x7 : 0; 190*b35ce0c4SPankaj Gupta debug("package_3ds %d\n", pdimm->package_3ds); 191*b35ce0c4SPankaj Gupta 192*b35ce0c4SPankaj Gupta switch (spd->module_type & DDR4_SPD_MODULETYPE_MASK) { 193*b35ce0c4SPankaj Gupta case DDR4_SPD_RDIMM: 194*b35ce0c4SPankaj Gupta case DDR4_SPD_MINI_RDIMM: 195*b35ce0c4SPankaj Gupta case DDR4_SPD_72B_SO_RDIMM: 196*b35ce0c4SPankaj Gupta pdimm->rdimm = 1; 197*b35ce0c4SPankaj Gupta pdimm->rc = spd->mod_section.registered.ref_raw_card & 0x8f; 198*b35ce0c4SPankaj Gupta if ((spd->mod_section.registered.reg_map & 0x1) != 0) { 199*b35ce0c4SPankaj Gupta pdimm->mirrored_dimm = 1; 200*b35ce0c4SPankaj Gupta } 201*b35ce0c4SPankaj Gupta val = spd->mod_section.registered.ca_stren; 202*b35ce0c4SPankaj Gupta pdimm->rcw[3] = val >> 4; 203*b35ce0c4SPankaj Gupta pdimm->rcw[4] = ((val & 0x3) << 2) | ((val & 0xc) >> 2); 204*b35ce0c4SPankaj Gupta val = spd->mod_section.registered.clk_stren; 205*b35ce0c4SPankaj Gupta pdimm->rcw[5] = ((val & 0x3) << 2) | ((val & 0xc) >> 2); 206*b35ce0c4SPankaj Gupta pdimm->rcw[6] = 0xf; 207*b35ce0c4SPankaj Gupta /* A17 used for 16Gb+, C[2:0] used for 3DS */ 208*b35ce0c4SPankaj Gupta pdimm->rcw[8] = pdimm->die_density >= 0x6 ? 0x0 : 0x8 | 209*b35ce0c4SPankaj Gupta (pdimm->package_3ds > 0x3 ? 0x0 : 210*b35ce0c4SPankaj Gupta (pdimm->package_3ds > 0x1 ? 0x1 : 211*b35ce0c4SPankaj Gupta (pdimm->package_3ds > 0 ? 0x2 : 0x3))); 212*b35ce0c4SPankaj Gupta if (pdimm->package_3ds != 0 || pdimm->n_ranks != 4) { 213*b35ce0c4SPankaj Gupta pdimm->rcw[13] = 0x4; 214*b35ce0c4SPankaj Gupta } else { 215*b35ce0c4SPankaj Gupta pdimm->rcw[13] = 0x5; 216*b35ce0c4SPankaj Gupta } 217*b35ce0c4SPankaj Gupta pdimm->rcw[13] |= pdimm->mirrored_dimm ? 0x8 : 0; 218*b35ce0c4SPankaj Gupta break; 219*b35ce0c4SPankaj Gupta 220*b35ce0c4SPankaj Gupta case DDR4_SPD_UDIMM: 221*b35ce0c4SPankaj Gupta case DDR4_SPD_SO_DIMM: 222*b35ce0c4SPankaj Gupta case DDR4_SPD_MINI_UDIMM: 223*b35ce0c4SPankaj Gupta case DDR4_SPD_72B_SO_UDIMM: 224*b35ce0c4SPankaj Gupta case DDR4_SPD_16B_SO_DIMM: 225*b35ce0c4SPankaj Gupta case DDR4_SPD_32B_SO_DIMM: 226*b35ce0c4SPankaj Gupta pdimm->rc = spd->mod_section.unbuffered.ref_raw_card & 0x8f; 227*b35ce0c4SPankaj Gupta if ((spd->mod_section.unbuffered.addr_mapping & 0x1) != 0) { 228*b35ce0c4SPankaj Gupta pdimm->mirrored_dimm = 1; 229*b35ce0c4SPankaj Gupta } 230*b35ce0c4SPankaj Gupta if ((spd->mod_section.unbuffered.mod_height & 0xe0) == 0 && 231*b35ce0c4SPankaj Gupta (spd->mod_section.unbuffered.ref_raw_card == 0x04)) { 232*b35ce0c4SPankaj Gupta /* Fix SPD error found on DIMMs with raw card E0 */ 233*b35ce0c4SPankaj Gupta for (i = 0; i < 18; i++) { 234*b35ce0c4SPankaj Gupta if (spd->mapping[i] == udimm_rc_e_dq[i]) { 235*b35ce0c4SPankaj Gupta continue; 236*b35ce0c4SPankaj Gupta } 237*b35ce0c4SPankaj Gupta spd_error = 1; 238*b35ce0c4SPankaj Gupta ptr = (unsigned char *)&spd->mapping[i]; 239*b35ce0c4SPankaj Gupta *ptr = udimm_rc_e_dq[i]; 240*b35ce0c4SPankaj Gupta } 241*b35ce0c4SPankaj Gupta if (spd_error != 0) { 242*b35ce0c4SPankaj Gupta INFO("SPD DQ mapping error fixed\n"); 243*b35ce0c4SPankaj Gupta } 244*b35ce0c4SPankaj Gupta } 245*b35ce0c4SPankaj Gupta break; 246*b35ce0c4SPankaj Gupta 247*b35ce0c4SPankaj Gupta default: 248*b35ce0c4SPankaj Gupta ERROR("Unknown module_type 0x%x\n", spd->module_type); 249*b35ce0c4SPankaj Gupta return -EINVAL; 250*b35ce0c4SPankaj Gupta } 251*b35ce0c4SPankaj Gupta debug("rdimm %d\n", pdimm->rdimm); 252*b35ce0c4SPankaj Gupta debug("mirrored_dimm %d\n", pdimm->mirrored_dimm); 253*b35ce0c4SPankaj Gupta debug("rc 0x%x\n", pdimm->rc); 254*b35ce0c4SPankaj Gupta 255*b35ce0c4SPankaj Gupta /* SDRAM device parameters */ 256*b35ce0c4SPankaj Gupta pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12; 257*b35ce0c4SPankaj Gupta debug("n_row_addr %d\n", pdimm->n_row_addr); 258*b35ce0c4SPankaj Gupta pdimm->n_col_addr = (spd->addressing & 0x7) + 9; 259*b35ce0c4SPankaj Gupta debug("n_col_addr %d\n", pdimm->n_col_addr); 260*b35ce0c4SPankaj Gupta pdimm->bank_addr_bits = (spd->density_banks >> 4) & 0x3; 261*b35ce0c4SPankaj Gupta debug("bank_addr_bits %d\n", pdimm->bank_addr_bits); 262*b35ce0c4SPankaj Gupta pdimm->bank_group_bits = (spd->density_banks >> 6) & 0x3; 263*b35ce0c4SPankaj Gupta debug("bank_group_bits %d\n", pdimm->bank_group_bits); 264*b35ce0c4SPankaj Gupta 265*b35ce0c4SPankaj Gupta if (pdimm->ec_sdram_width != 0) { 266*b35ce0c4SPankaj Gupta pdimm->edc_config = 0x02; 267*b35ce0c4SPankaj Gupta } else { 268*b35ce0c4SPankaj Gupta pdimm->edc_config = 0x00; 269*b35ce0c4SPankaj Gupta } 270*b35ce0c4SPankaj Gupta debug("edc_config %d\n", pdimm->edc_config); 271*b35ce0c4SPankaj Gupta 272*b35ce0c4SPankaj Gupta /* DDR4 spec has BL8 -bit3, BC4 -bit2 */ 273*b35ce0c4SPankaj Gupta pdimm->burst_lengths_bitmask = 0x0c; 274*b35ce0c4SPankaj Gupta debug("burst_lengths_bitmask 0x%x\n", pdimm->burst_lengths_bitmask); 275*b35ce0c4SPankaj Gupta 276*b35ce0c4SPankaj Gupta /* MTB - medium timebase 277*b35ce0c4SPankaj Gupta * The MTB in the SPD spec is 125ps, 278*b35ce0c4SPankaj Gupta * 279*b35ce0c4SPankaj Gupta * FTB - fine timebase 280*b35ce0c4SPankaj Gupta * use 1/10th of ps as our unit to avoid floating point 281*b35ce0c4SPankaj Gupta * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps 282*b35ce0c4SPankaj Gupta */ 283*b35ce0c4SPankaj Gupta if ((spd->timebases & 0xf) == 0x0) { 284*b35ce0c4SPankaj Gupta pdimm->mtb_ps = 125; 285*b35ce0c4SPankaj Gupta pdimm->ftb_10th_ps = 10; 286*b35ce0c4SPankaj Gupta 287*b35ce0c4SPankaj Gupta } else { 288*b35ce0c4SPankaj Gupta ERROR("Unknown Timebases\n"); 289*b35ce0c4SPankaj Gupta return -EINVAL; 290*b35ce0c4SPankaj Gupta } 291*b35ce0c4SPankaj Gupta 292*b35ce0c4SPankaj Gupta /* sdram minimum cycle time */ 293*b35ce0c4SPankaj Gupta pdimm->tckmin_x_ps = spd_to_ps(spd->tck_min, spd->fine_tck_min); 294*b35ce0c4SPankaj Gupta debug("tckmin_x_ps %d\n", pdimm->tckmin_x_ps); 295*b35ce0c4SPankaj Gupta 296*b35ce0c4SPankaj Gupta /* sdram max cycle time */ 297*b35ce0c4SPankaj Gupta pdimm->tckmax_ps = spd_to_ps(spd->tck_max, spd->fine_tck_max); 298*b35ce0c4SPankaj Gupta debug("tckmax_ps %d\n", pdimm->tckmax_ps); 299*b35ce0c4SPankaj Gupta 300*b35ce0c4SPankaj Gupta /* 301*b35ce0c4SPankaj Gupta * CAS latency supported 302*b35ce0c4SPankaj Gupta * bit0 - CL7 303*b35ce0c4SPankaj Gupta * bit4 - CL11 304*b35ce0c4SPankaj Gupta * bit8 - CL15 305*b35ce0c4SPankaj Gupta * bit12- CL19 306*b35ce0c4SPankaj Gupta * bit16- CL23 307*b35ce0c4SPankaj Gupta */ 308*b35ce0c4SPankaj Gupta pdimm->caslat_x = (spd->caslat_b1 << 7) | 309*b35ce0c4SPankaj Gupta (spd->caslat_b2 << 15) | 310*b35ce0c4SPankaj Gupta (spd->caslat_b3 << 23); 311*b35ce0c4SPankaj Gupta debug("caslat_x 0x%x\n", pdimm->caslat_x); 312*b35ce0c4SPankaj Gupta 313*b35ce0c4SPankaj Gupta if (spd->caslat_b4 != 0) { 314*b35ce0c4SPankaj Gupta WARN("Unhandled caslat_b4 value\n"); 315*b35ce0c4SPankaj Gupta } 316*b35ce0c4SPankaj Gupta 317*b35ce0c4SPankaj Gupta /* 318*b35ce0c4SPankaj Gupta * min CAS latency time 319*b35ce0c4SPankaj Gupta */ 320*b35ce0c4SPankaj Gupta pdimm->taa_ps = spd_to_ps(spd->taa_min, spd->fine_taa_min); 321*b35ce0c4SPankaj Gupta debug("taa_ps %d\n", pdimm->taa_ps); 322*b35ce0c4SPankaj Gupta 323*b35ce0c4SPankaj Gupta /* 324*b35ce0c4SPankaj Gupta * min RAS to CAS delay time 325*b35ce0c4SPankaj Gupta */ 326*b35ce0c4SPankaj Gupta pdimm->trcd_ps = spd_to_ps(spd->trcd_min, spd->fine_trcd_min); 327*b35ce0c4SPankaj Gupta debug("trcd_ps %d\n", pdimm->trcd_ps); 328*b35ce0c4SPankaj Gupta 329*b35ce0c4SPankaj Gupta /* 330*b35ce0c4SPankaj Gupta * Min Row Precharge Delay Time 331*b35ce0c4SPankaj Gupta */ 332*b35ce0c4SPankaj Gupta pdimm->trp_ps = spd_to_ps(spd->trp_min, spd->fine_trp_min); 333*b35ce0c4SPankaj Gupta debug("trp_ps %d\n", pdimm->trp_ps); 334*b35ce0c4SPankaj Gupta 335*b35ce0c4SPankaj Gupta /* min active to precharge delay time */ 336*b35ce0c4SPankaj Gupta pdimm->tras_ps = (((spd->tras_trc_ext & 0xf) << 8) + 337*b35ce0c4SPankaj Gupta spd->tras_min_lsb) * pdimm->mtb_ps; 338*b35ce0c4SPankaj Gupta debug("tras_ps %d\n", pdimm->tras_ps); 339*b35ce0c4SPankaj Gupta 340*b35ce0c4SPankaj Gupta /* min active to actice/refresh delay time */ 341*b35ce0c4SPankaj Gupta pdimm->trc_ps = spd_to_ps((((spd->tras_trc_ext & 0xf0) << 4) + 342*b35ce0c4SPankaj Gupta spd->trc_min_lsb), spd->fine_trc_min); 343*b35ce0c4SPankaj Gupta debug("trc_ps %d\n", pdimm->trc_ps); 344*b35ce0c4SPankaj Gupta /* Min Refresh Recovery Delay Time */ 345*b35ce0c4SPankaj Gupta pdimm->trfc1_ps = ((spd->trfc1_min_msb << 8) | (spd->trfc1_min_lsb)) * 346*b35ce0c4SPankaj Gupta pdimm->mtb_ps; 347*b35ce0c4SPankaj Gupta debug("trfc1_ps %d\n", pdimm->trfc1_ps); 348*b35ce0c4SPankaj Gupta pdimm->trfc2_ps = ((spd->trfc2_min_msb << 8) | (spd->trfc2_min_lsb)) * 349*b35ce0c4SPankaj Gupta pdimm->mtb_ps; 350*b35ce0c4SPankaj Gupta debug("trfc2_ps %d\n", pdimm->trfc2_ps); 351*b35ce0c4SPankaj Gupta pdimm->trfc4_ps = ((spd->trfc4_min_msb << 8) | (spd->trfc4_min_lsb)) * 352*b35ce0c4SPankaj Gupta pdimm->mtb_ps; 353*b35ce0c4SPankaj Gupta debug("trfc4_ps %d\n", pdimm->trfc4_ps); 354*b35ce0c4SPankaj Gupta /* min four active window delay time */ 355*b35ce0c4SPankaj Gupta pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min) * 356*b35ce0c4SPankaj Gupta pdimm->mtb_ps; 357*b35ce0c4SPankaj Gupta debug("tfaw_ps %d\n", pdimm->tfaw_ps); 358*b35ce0c4SPankaj Gupta 359*b35ce0c4SPankaj Gupta /* min row active to row active delay time, different bank group */ 360*b35ce0c4SPankaj Gupta pdimm->trrds_ps = spd_to_ps(spd->trrds_min, spd->fine_trrds_min); 361*b35ce0c4SPankaj Gupta debug("trrds_ps %d\n", pdimm->trrds_ps); 362*b35ce0c4SPankaj Gupta /* min row active to row active delay time, same bank group */ 363*b35ce0c4SPankaj Gupta pdimm->trrdl_ps = spd_to_ps(spd->trrdl_min, spd->fine_trrdl_min); 364*b35ce0c4SPankaj Gupta debug("trrdl_ps %d\n", pdimm->trrdl_ps); 365*b35ce0c4SPankaj Gupta /* min CAS to CAS Delay Time (tCCD_Lmin), same bank group */ 366*b35ce0c4SPankaj Gupta pdimm->tccdl_ps = spd_to_ps(spd->tccdl_min, spd->fine_tccdl_min); 367*b35ce0c4SPankaj Gupta debug("tccdl_ps %d\n", pdimm->tccdl_ps); 368*b35ce0c4SPankaj Gupta if (pdimm->package_3ds != 0) { 369*b35ce0c4SPankaj Gupta if (pdimm->die_density > 5) { 370*b35ce0c4SPankaj Gupta debug("Unsupported logical rank density 0x%x\n", 371*b35ce0c4SPankaj Gupta pdimm->die_density); 372*b35ce0c4SPankaj Gupta return -EINVAL; 373*b35ce0c4SPankaj Gupta } 374*b35ce0c4SPankaj Gupta pdimm->trfc_slr_ps = (pdimm->die_density <= 4) ? 375*b35ce0c4SPankaj Gupta 260000 : 350000; 376*b35ce0c4SPankaj Gupta } 377*b35ce0c4SPankaj Gupta debug("trfc_slr_ps %d\n", pdimm->trfc_slr_ps); 378*b35ce0c4SPankaj Gupta 379*b35ce0c4SPankaj Gupta /* 15ns for all speed bins */ 380*b35ce0c4SPankaj Gupta pdimm->twr_ps = 15000; 381*b35ce0c4SPankaj Gupta debug("twr_ps %d\n", pdimm->twr_ps); 382*b35ce0c4SPankaj Gupta 383*b35ce0c4SPankaj Gupta /* 384*b35ce0c4SPankaj Gupta * Average periodic refresh interval 385*b35ce0c4SPankaj Gupta * tREFI = 7.8 us at normal temperature range 386*b35ce0c4SPankaj Gupta */ 387*b35ce0c4SPankaj Gupta pdimm->refresh_rate_ps = 7800000; 388*b35ce0c4SPankaj Gupta debug("refresh_rate_ps %d\n", pdimm->refresh_rate_ps); 389*b35ce0c4SPankaj Gupta 390*b35ce0c4SPankaj Gupta for (i = 0; i < 18; i++) { 391*b35ce0c4SPankaj Gupta pdimm->dq_mapping[i] = spd->mapping[i]; 392*b35ce0c4SPankaj Gupta debug("dq_mapping 0x%x\n", pdimm->dq_mapping[i]); 393*b35ce0c4SPankaj Gupta } 394*b35ce0c4SPankaj Gupta 395*b35ce0c4SPankaj Gupta pdimm->dq_mapping_ors = ((spd->mapping[0] >> 6) & 0x3) == 0 ? 1 : 0; 396*b35ce0c4SPankaj Gupta debug("dq_mapping_ors %d\n", pdimm->dq_mapping_ors); 397*b35ce0c4SPankaj Gupta 398*b35ce0c4SPankaj Gupta return 0; 399*b35ce0c4SPankaj Gupta } 400