• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) Marvell International Ltd. and its affiliates
4  */
5 
6 #include "mv_ddr_spd.h"
7 
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 */
11 
12 #define MV_DDR_SPD_SUPPORTED_CLS_NUM	30
13 
14 static unsigned int mv_ddr_spd_supported_cls[MV_DDR_SPD_SUPPORTED_CLS_NUM];
15 
mv_ddr_spd_supported_cls_calc(union mv_ddr_spd_data * spd_data)16 int mv_ddr_spd_supported_cls_calc(union mv_ddr_spd_data *spd_data)
17 {
18 	unsigned int byte, bit, start_cl;
19 
20 	start_cl = (spd_data->all_bytes[23] & 0x8) ? 23 : 7;
21 
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;
26 			else
27 				mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = 0;
28 		}
29 	}
30 
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;
34 		else
35 			mv_ddr_spd_supported_cls[(byte - 20) * 8 + bit] = 0;
36 	}
37 
38 	return 0;
39 }
40 
mv_ddr_spd_supported_cl_get(unsigned int cl)41 unsigned int mv_ddr_spd_supported_cl_get(unsigned int cl)
42 {
43 	unsigned int supported_cl;
44 	int i = 0;
45 
46 	while (i < MV_DDR_SPD_SUPPORTED_CLS_NUM &&
47 		mv_ddr_spd_supported_cls[i] < cl)
48 		i++;
49 
50 	if (i < MV_DDR_SPD_SUPPORTED_CLS_NUM)
51 		supported_cl = mv_ddr_spd_supported_cls[i];
52 	else
53 		supported_cl = 0;
54 
55 	return supported_cl;
56 }
57 
mv_ddr_spd_timing_calc(union mv_ddr_spd_data * spd_data,unsigned int timing_data[])58 int mv_ddr_spd_timing_calc(union mv_ddr_spd_data *spd_data, unsigned int timing_data[])
59 {
60 	int calc_val;
61 
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;
65 	if (calc_val < 0)
66 		return 1;
67 	timing_data[MV_DDR_TCK_AVG_MIN] = calc_val;
68 
69 	/* t aa min, ps */
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;
72 	if (calc_val < 0)
73 		return 1;
74 	timing_data[MV_DDR_TAA_MIN] = calc_val;
75 
76 	/* t rfc1 min, ps */
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;
79 
80 	/* t wr min, ps */
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)) *
83 		MV_DDR_SPD_DATA_MTB;
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;
87 
88 	/* t rcd min, ps */
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;
91 	if (calc_val < 0)
92 		return 1;
93 	timing_data[MV_DDR_TRCD_MIN] = calc_val;
94 
95 	/* t rp min, ps */
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;
98 	if (calc_val < 0)
99 		return 1;
100 	timing_data[MV_DDR_TRP_MIN] = calc_val;
101 
102 	/* t rc min, ps */
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;
107 	if (calc_val < 0)
108 		return 1;
109 	timing_data[MV_DDR_TRC_MIN] = calc_val;
110 
111 	/* t ras min, ps */
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)) *
114 		MV_DDR_SPD_DATA_MTB;
115 
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;
119 	if (calc_val < 0)
120 		return 1;
121 	timing_data[MV_DDR_TRRD_S_MIN] = calc_val;
122 
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;
126 	if (calc_val < 0)
127 		return 1;
128 	timing_data[MV_DDR_TRRD_L_MIN] = calc_val;
129 
130 	/* t faw min, ps */
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)) *
133 		MV_DDR_SPD_DATA_MTB;
134 
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)) *
138 		MV_DDR_SPD_DATA_MTB;
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;
142 
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)) *
146 		MV_DDR_SPD_DATA_MTB;
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;
150 
151 	return 0;
152 }
153 
mv_ddr_spd_dev_width_get(union mv_ddr_spd_data * spd_data)154 enum mv_ddr_dev_width mv_ddr_spd_dev_width_get(union mv_ddr_spd_data *spd_data)
155 {
156 	unsigned char dev_width = spd_data->byte_fields.byte_12.bit_fields.device_width;
157 	enum mv_ddr_dev_width ret_val;
158 
159 	switch (dev_width) {
160 	case 0x00:
161 		ret_val = MV_DDR_DEV_WIDTH_4BIT;
162 		break;
163 	case 0x01:
164 		ret_val = MV_DDR_DEV_WIDTH_8BIT;
165 		break;
166 	case 0x02:
167 		ret_val = MV_DDR_DEV_WIDTH_16BIT;
168 		break;
169 	case 0x03:
170 		ret_val = MV_DDR_DEV_WIDTH_32BIT;
171 		break;
172 	default:
173 		ret_val = MV_DDR_DEV_WIDTH_LAST;
174 	}
175 
176 	return ret_val;
177 }
178 
mv_ddr_spd_die_capacity_get(union mv_ddr_spd_data * spd_data)179 enum mv_ddr_die_capacity mv_ddr_spd_die_capacity_get(union mv_ddr_spd_data *spd_data)
180 {
181 	unsigned char die_cap = spd_data->byte_fields.byte_4.bit_fields.die_capacity;
182 	enum mv_ddr_die_capacity ret_val;
183 
184 	switch (die_cap) {
185 	case 0x00:
186 		ret_val = MV_DDR_DIE_CAP_256MBIT;
187 		break;
188 	case 0x01:
189 		ret_val = MV_DDR_DIE_CAP_512MBIT;
190 		break;
191 	case 0x02:
192 		ret_val = MV_DDR_DIE_CAP_1GBIT;
193 		break;
194 	case 0x03:
195 		ret_val = MV_DDR_DIE_CAP_2GBIT;
196 		break;
197 	case 0x04:
198 		ret_val = MV_DDR_DIE_CAP_4GBIT;
199 		break;
200 	case 0x05:
201 		ret_val = MV_DDR_DIE_CAP_8GBIT;
202 		break;
203 	case 0x06:
204 		ret_val = MV_DDR_DIE_CAP_16GBIT;
205 		break;
206 	case 0x07:
207 		ret_val = MV_DDR_DIE_CAP_32GBIT;
208 		break;
209 	case 0x08:
210 		ret_val = MV_DDR_DIE_CAP_12GBIT;
211 		break;
212 	case 0x09:
213 		ret_val = MV_DDR_DIE_CAP_24GBIT;
214 		break;
215 	default:
216 		ret_val = MV_DDR_DIE_CAP_LAST;
217 	}
218 
219 	return ret_val;
220 }
221 
mv_ddr_spd_mem_mirror_get(union mv_ddr_spd_data * spd_data)222 unsigned char mv_ddr_spd_mem_mirror_get(union mv_ddr_spd_data *spd_data)
223 {
224 	unsigned char mem_mirror = spd_data->byte_fields.byte_131.bit_fields.rank_1_mapping;
225 
226 	return mem_mirror;
227 }
228 
mv_ddr_spd_pri_bus_width_get(union mv_ddr_spd_data * spd_data)229 enum mv_ddr_pkg_rank mv_ddr_spd_pri_bus_width_get(union mv_ddr_spd_data *spd_data)
230 {
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;
233 
234 	switch (pri_bus_width) {
235 	case 0x00:
236 		ret_val = MV_DDR_PRI_BUS_WIDTH_8;
237 		break;
238 	case 0x01:
239 		ret_val = MV_DDR_PRI_BUS_WIDTH_16;
240 		break;
241 	case 0x02:
242 		ret_val = MV_DDR_PRI_BUS_WIDTH_32;
243 		break;
244 	case 0x03:
245 		ret_val = MV_DDR_PRI_BUS_WIDTH_64;
246 		break;
247 	default:
248 		ret_val = MV_DDR_PRI_BUS_WIDTH_LAST;
249 	}
250 
251 	return ret_val;
252 }
253 
mv_ddr_spd_bus_width_ext_get(union mv_ddr_spd_data * spd_data)254 enum mv_ddr_pkg_rank mv_ddr_spd_bus_width_ext_get(union mv_ddr_spd_data *spd_data)
255 {
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;
258 
259 	switch (bus_width_ext) {
260 	case 0x00:
261 		ret_val = MV_DDR_BUS_WIDTH_EXT_0;
262 		break;
263 	case 0x01:
264 		ret_val = MV_DDR_BUS_WIDTH_EXT_8;
265 		break;
266 	default:
267 		ret_val = MV_DDR_BUS_WIDTH_EXT_LAST;
268 	}
269 
270 	return ret_val;
271 }
272 
mv_ddr_spd_pkg_rank_get(union mv_ddr_spd_data * spd_data)273 static enum mv_ddr_pkg_rank mv_ddr_spd_pkg_rank_get(union mv_ddr_spd_data *spd_data)
274 {
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;
277 
278 	switch (pkg_rank) {
279 	case 0x00:
280 		ret_val = MV_DDR_PKG_RANK_1;
281 		break;
282 	case 0x01:
283 		ret_val = MV_DDR_PKG_RANK_2;
284 		break;
285 	case 0x02:
286 		ret_val = MV_DDR_PKG_RANK_3;
287 		break;
288 	case 0x03:
289 		ret_val = MV_DDR_PKG_RANK_4;
290 		break;
291 	case 0x04:
292 		ret_val = MV_DDR_PKG_RANK_5;
293 		break;
294 	case 0x05:
295 		ret_val = MV_DDR_PKG_RANK_6;
296 		break;
297 	case 0x06:
298 		ret_val = MV_DDR_PKG_RANK_7;
299 		break;
300 	case 0x07:
301 		ret_val = MV_DDR_PKG_RANK_8;
302 		break;
303 	default:
304 		ret_val = MV_DDR_PKG_RANK_LAST;
305 	}
306 
307 	return ret_val;
308 }
309 
mv_ddr_spd_die_count_get(union mv_ddr_spd_data * spd_data)310 static enum mv_ddr_die_count mv_ddr_spd_die_count_get(union mv_ddr_spd_data *spd_data)
311 {
312 	unsigned char die_count = spd_data->byte_fields.byte_6.bit_fields.die_count;
313 	enum mv_ddr_die_count ret_val;
314 
315 	switch (die_count) {
316 	case 0x00:
317 		ret_val = MV_DDR_DIE_CNT_1;
318 		break;
319 	case 0x01:
320 		ret_val = MV_DDR_DIE_CNT_2;
321 		break;
322 	case 0x02:
323 		ret_val = MV_DDR_DIE_CNT_3;
324 		break;
325 	case 0x03:
326 		ret_val = MV_DDR_DIE_CNT_4;
327 		break;
328 	case 0x04:
329 		ret_val = MV_DDR_DIE_CNT_5;
330 		break;
331 	case 0x05:
332 		ret_val = MV_DDR_DIE_CNT_6;
333 		break;
334 	case 0x06:
335 		ret_val = MV_DDR_DIE_CNT_7;
336 		break;
337 	case 0x07:
338 		ret_val = MV_DDR_DIE_CNT_8;
339 		break;
340 	default:
341 		ret_val = MV_DDR_DIE_CNT_LAST;
342 	}
343 
344 	return ret_val;
345 }
346 
mv_ddr_spd_cs_bit_mask_get(union mv_ddr_spd_data * spd_data)347 unsigned char mv_ddr_spd_cs_bit_mask_get(union mv_ddr_spd_data *spd_data)
348 {
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);
352 
353 	if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_1)
354 		cs_bit_mask = 0x1;
355 	else if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_2)
356 		cs_bit_mask = 0x3;
357 	else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_1)
358 		cs_bit_mask = 0x3;
359 	else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_2)
360 		cs_bit_mask = 0xf;
361 
362 	return cs_bit_mask;
363 }
364 
mv_ddr_spd_dev_type_get(union mv_ddr_spd_data * spd_data)365 unsigned char mv_ddr_spd_dev_type_get(union mv_ddr_spd_data *spd_data)
366 {
367 	unsigned char dev_type = spd_data->byte_fields.byte_2;
368 
369 	return dev_type;
370 }
371 
mv_ddr_spd_module_type_get(union mv_ddr_spd_data * spd_data)372 unsigned char mv_ddr_spd_module_type_get(union mv_ddr_spd_data *spd_data)
373 {
374 	unsigned char module_type = spd_data->byte_fields.byte_3.bit_fields.module_type;
375 
376 	return module_type;
377 }
378