1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) Marvell International Ltd. and its affiliates
6 #include "mv_ddr_spd.h"
8 #define MV_DDR_SPD_DATA_MTB 125 /* medium timebase, ps */
9 #define MV_DDR_SPD_DATA_FTB 1 /* fine timebase, ps */
10 #define MV_DDR_SPD_MSB_OFFS 8 /* most significant byte offset, bits */
12 #define MV_DDR_SPD_SUPPORTED_CLS_NUM 30
14 static unsigned int mv_ddr_spd_supported_cls[MV_DDR_SPD_SUPPORTED_CLS_NUM];
16 int mv_ddr_spd_supported_cls_calc(union mv_ddr_spd_data *spd_data)
18 unsigned int byte, bit, start_cl;
20 start_cl = (spd_data->all_bytes[23] & 0x8) ? 23 : 7;
22 for (byte = 20; byte < 23; byte++) {
23 for (bit = 0; bit < 8; bit++) {
24 if (spd_data->all_bytes[byte] & (1 << bit))
25 mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = start_cl + (byte - 20) * 8 + bit;
27 mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = 0;
31 for (byte = 23, bit = 0; bit < 6; bit++) {
32 if (spd_data->all_bytes[byte] & (1 << bit))
33 mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = start_cl + (byte - 20) * 8 + bit;
35 mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = 0;
41 unsigned int mv_ddr_spd_supported_cl_get(unsigned int cl)
43 unsigned int supported_cl;
46 while (i < MV_DDR_SPD_SUPPORTED_CLS_NUM &&
47 mv_ddr_spd_supported_cls[i] < cl)
50 if (i < MV_DDR_SPD_SUPPORTED_CLS_NUM)
51 supported_cl = mv_ddr_spd_supported_cls[i];
58 int mv_ddr_spd_timing_calc(union mv_ddr_spd_data *spd_data, unsigned int timing_data[])
62 /* t ck avg min, ps */
63 calc_val = spd_data->byte_fields.byte_18 * MV_DDR_SPD_DATA_MTB +
64 (signed char)spd_data->byte_fields.byte_125 * MV_DDR_SPD_DATA_FTB;
67 timing_data[MV_DDR_TCK_AVG_MIN] = calc_val;
70 calc_val = spd_data->byte_fields.byte_24 * MV_DDR_SPD_DATA_MTB +
71 (signed char)spd_data->byte_fields.byte_123 * MV_DDR_SPD_DATA_FTB;
74 timing_data[MV_DDR_TAA_MIN] = calc_val;
77 timing_data[MV_DDR_TRFC1_MIN] = (spd_data->byte_fields.byte_30 +
78 (spd_data->byte_fields.byte_31 << MV_DDR_SPD_MSB_OFFS)) * MV_DDR_SPD_DATA_MTB;
81 timing_data[MV_DDR_TWR_MIN] = (spd_data->byte_fields.byte_42 +
82 (spd_data->byte_fields.byte_41.bit_fields.t_wr_min_msn << MV_DDR_SPD_MSB_OFFS)) *
84 /* FIXME: wa: set twr to a default value, if it's unset on spd */
85 if (timing_data[MV_DDR_TWR_MIN] == 0)
86 timing_data[MV_DDR_TWR_MIN] = 15000;
89 calc_val = spd_data->byte_fields.byte_25 * MV_DDR_SPD_DATA_MTB +
90 (signed char)spd_data->byte_fields.byte_122 * MV_DDR_SPD_DATA_FTB;
93 timing_data[MV_DDR_TRCD_MIN] = calc_val;
96 calc_val = spd_data->byte_fields.byte_26 * MV_DDR_SPD_DATA_MTB +
97 (signed char)spd_data->byte_fields.byte_121 * MV_DDR_SPD_DATA_FTB;
100 timing_data[MV_DDR_TRP_MIN] = calc_val;
103 calc_val = (spd_data->byte_fields.byte_29 +
104 (spd_data->byte_fields.byte_27.bit_fields.t_rc_min_msn << MV_DDR_SPD_MSB_OFFS)) *
105 MV_DDR_SPD_DATA_MTB +
106 (signed char)spd_data->byte_fields.byte_120 * MV_DDR_SPD_DATA_FTB;
109 timing_data[MV_DDR_TRC_MIN] = calc_val;
112 timing_data[MV_DDR_TRAS_MIN] = (spd_data->byte_fields.byte_28 +
113 (spd_data->byte_fields.byte_27.bit_fields.t_ras_min_msn << MV_DDR_SPD_MSB_OFFS)) *
116 /* t rrd s min, ps */
117 calc_val = spd_data->byte_fields.byte_38 * MV_DDR_SPD_DATA_MTB +
118 (signed char)spd_data->byte_fields.byte_119 * MV_DDR_SPD_DATA_FTB;
121 timing_data[MV_DDR_TRRD_S_MIN] = calc_val;
123 /* t rrd l min, ps */
124 calc_val = spd_data->byte_fields.byte_39 * MV_DDR_SPD_DATA_MTB +
125 (signed char)spd_data->byte_fields.byte_118 * MV_DDR_SPD_DATA_FTB;
128 timing_data[MV_DDR_TRRD_L_MIN] = calc_val;
131 timing_data[MV_DDR_TFAW_MIN] = (spd_data->byte_fields.byte_37 +
132 (spd_data->byte_fields.byte_36.bit_fields.t_faw_min_msn << MV_DDR_SPD_MSB_OFFS)) *
135 /* t wtr s min, ps */
136 timing_data[MV_DDR_TWTR_S_MIN] = (spd_data->byte_fields.byte_44 +
137 (spd_data->byte_fields.byte_43.bit_fields.t_wtr_s_min_msn << MV_DDR_SPD_MSB_OFFS)) *
139 /* FIXME: wa: set twtr_s to a default value, if it's unset on spd */
140 if (timing_data[MV_DDR_TWTR_S_MIN] == 0)
141 timing_data[MV_DDR_TWTR_S_MIN] = 2500;
143 /* t wtr l min, ps */
144 timing_data[MV_DDR_TWTR_L_MIN] = (spd_data->byte_fields.byte_45 +
145 (spd_data->byte_fields.byte_43.bit_fields.t_wtr_l_min_msn << MV_DDR_SPD_MSB_OFFS)) *
147 /* FIXME: wa: set twtr_l to a default value, if it's unset on spd */
148 if (timing_data[MV_DDR_TWTR_L_MIN] == 0)
149 timing_data[MV_DDR_TWTR_L_MIN] = 7500;
154 enum mv_ddr_dev_width mv_ddr_spd_dev_width_get(union mv_ddr_spd_data *spd_data)
156 unsigned char dev_width = spd_data->byte_fields.byte_12.bit_fields.device_width;
157 enum mv_ddr_dev_width ret_val;
161 ret_val = MV_DDR_DEV_WIDTH_4BIT;
164 ret_val = MV_DDR_DEV_WIDTH_8BIT;
167 ret_val = MV_DDR_DEV_WIDTH_16BIT;
170 ret_val = MV_DDR_DEV_WIDTH_32BIT;
173 ret_val = MV_DDR_DEV_WIDTH_LAST;
179 enum mv_ddr_die_capacity mv_ddr_spd_die_capacity_get(union mv_ddr_spd_data *spd_data)
181 unsigned char die_cap = spd_data->byte_fields.byte_4.bit_fields.die_capacity;
182 enum mv_ddr_die_capacity ret_val;
186 ret_val = MV_DDR_DIE_CAP_256MBIT;
189 ret_val = MV_DDR_DIE_CAP_512MBIT;
192 ret_val = MV_DDR_DIE_CAP_1GBIT;
195 ret_val = MV_DDR_DIE_CAP_2GBIT;
198 ret_val = MV_DDR_DIE_CAP_4GBIT;
201 ret_val = MV_DDR_DIE_CAP_8GBIT;
204 ret_val = MV_DDR_DIE_CAP_16GBIT;
207 ret_val = MV_DDR_DIE_CAP_32GBIT;
210 ret_val = MV_DDR_DIE_CAP_12GBIT;
213 ret_val = MV_DDR_DIE_CAP_24GBIT;
216 ret_val = MV_DDR_DIE_CAP_LAST;
222 unsigned char mv_ddr_spd_mem_mirror_get(union mv_ddr_spd_data *spd_data)
224 unsigned char mem_mirror = spd_data->byte_fields.byte_131.bit_fields.rank_1_mapping;
229 enum mv_ddr_pkg_rank mv_ddr_spd_pri_bus_width_get(union mv_ddr_spd_data *spd_data)
231 unsigned char pri_bus_width = spd_data->byte_fields.byte_13.bit_fields.primary_bus_width;
232 enum mv_ddr_pri_bus_width ret_val;
234 switch (pri_bus_width) {
236 ret_val = MV_DDR_PRI_BUS_WIDTH_8;
239 ret_val = MV_DDR_PRI_BUS_WIDTH_16;
242 ret_val = MV_DDR_PRI_BUS_WIDTH_32;
245 ret_val = MV_DDR_PRI_BUS_WIDTH_64;
248 ret_val = MV_DDR_PRI_BUS_WIDTH_LAST;
254 enum mv_ddr_pkg_rank mv_ddr_spd_bus_width_ext_get(union mv_ddr_spd_data *spd_data)
256 unsigned char bus_width_ext = spd_data->byte_fields.byte_13.bit_fields.bus_width_ext;
257 enum mv_ddr_bus_width_ext ret_val;
259 switch (bus_width_ext) {
261 ret_val = MV_DDR_BUS_WIDTH_EXT_0;
264 ret_val = MV_DDR_BUS_WIDTH_EXT_8;
267 ret_val = MV_DDR_BUS_WIDTH_EXT_LAST;
273 static enum mv_ddr_pkg_rank mv_ddr_spd_pkg_rank_get(union mv_ddr_spd_data *spd_data)
275 unsigned char pkg_rank = spd_data->byte_fields.byte_12.bit_fields.dimm_pkg_ranks_num;
276 enum mv_ddr_pkg_rank ret_val;
280 ret_val = MV_DDR_PKG_RANK_1;
283 ret_val = MV_DDR_PKG_RANK_2;
286 ret_val = MV_DDR_PKG_RANK_3;
289 ret_val = MV_DDR_PKG_RANK_4;
292 ret_val = MV_DDR_PKG_RANK_5;
295 ret_val = MV_DDR_PKG_RANK_6;
298 ret_val = MV_DDR_PKG_RANK_7;
301 ret_val = MV_DDR_PKG_RANK_8;
304 ret_val = MV_DDR_PKG_RANK_LAST;
310 static enum mv_ddr_die_count mv_ddr_spd_die_count_get(union mv_ddr_spd_data *spd_data)
312 unsigned char die_count = spd_data->byte_fields.byte_6.bit_fields.die_count;
313 enum mv_ddr_die_count ret_val;
317 ret_val = MV_DDR_DIE_CNT_1;
320 ret_val = MV_DDR_DIE_CNT_2;
323 ret_val = MV_DDR_DIE_CNT_3;
326 ret_val = MV_DDR_DIE_CNT_4;
329 ret_val = MV_DDR_DIE_CNT_5;
332 ret_val = MV_DDR_DIE_CNT_6;
335 ret_val = MV_DDR_DIE_CNT_7;
338 ret_val = MV_DDR_DIE_CNT_8;
341 ret_val = MV_DDR_DIE_CNT_LAST;
347 unsigned char mv_ddr_spd_cs_bit_mask_get(union mv_ddr_spd_data *spd_data)
349 unsigned char cs_bit_mask = 0x0;
350 enum mv_ddr_pkg_rank pkg_rank = mv_ddr_spd_pkg_rank_get(spd_data);
351 enum mv_ddr_die_count die_cnt = mv_ddr_spd_die_count_get(spd_data);
353 if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_1)
355 else if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_2)
357 else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_1)
359 else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_2)
365 unsigned char mv_ddr_spd_dev_type_get(union mv_ddr_spd_data *spd_data)
367 unsigned char dev_type = spd_data->byte_fields.byte_2;
372 unsigned char mv_ddr_spd_module_type_get(union mv_ddr_spd_data *spd_data)
374 unsigned char module_type = spd_data->byte_fields.byte_3.bit_fields.module_type;