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