• 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 
85 	/* t rcd min, ps */
86 	calc_val = spd_data->byte_fields.byte_25 * MV_DDR_SPD_DATA_MTB +
87 		(signed char)spd_data->byte_fields.byte_122 * MV_DDR_SPD_DATA_FTB;
88 	if (calc_val < 0)
89 		return 1;
90 	timing_data[MV_DDR_TRCD_MIN] = calc_val;
91 
92 	/* t rp min, ps */
93 	calc_val = spd_data->byte_fields.byte_26 * MV_DDR_SPD_DATA_MTB +
94 		(signed char)spd_data->byte_fields.byte_121 * MV_DDR_SPD_DATA_FTB;
95 	if (calc_val < 0)
96 		return 1;
97 	timing_data[MV_DDR_TRP_MIN] = calc_val;
98 
99 	/* t rc min, ps */
100 	calc_val = (spd_data->byte_fields.byte_29 +
101 		(spd_data->byte_fields.byte_27.bit_fields.t_rc_min_msn << MV_DDR_SPD_MSB_OFFS)) *
102 		MV_DDR_SPD_DATA_MTB +
103 		(signed char)spd_data->byte_fields.byte_120 * MV_DDR_SPD_DATA_FTB;
104 	if (calc_val < 0)
105 		return 1;
106 	timing_data[MV_DDR_TRC_MIN] = calc_val;
107 
108 	/* t ras min, ps */
109 	timing_data[MV_DDR_TRAS_MIN] = (spd_data->byte_fields.byte_28 +
110 		(spd_data->byte_fields.byte_27.bit_fields.t_ras_min_msn << MV_DDR_SPD_MSB_OFFS)) *
111 		MV_DDR_SPD_DATA_MTB;
112 
113 	/* t rrd s min, ps */
114 	calc_val = spd_data->byte_fields.byte_38 * MV_DDR_SPD_DATA_MTB +
115 		(signed char)spd_data->byte_fields.byte_119 * MV_DDR_SPD_DATA_FTB;
116 	if (calc_val < 0)
117 		return 1;
118 	timing_data[MV_DDR_TRRD_S_MIN] = calc_val;
119 
120 	/* t rrd l min, ps */
121 	calc_val = spd_data->byte_fields.byte_39 * MV_DDR_SPD_DATA_MTB +
122 		(signed char)spd_data->byte_fields.byte_118 * MV_DDR_SPD_DATA_FTB;
123 	if (calc_val < 0)
124 		return 1;
125 	timing_data[MV_DDR_TRRD_L_MIN] = calc_val;
126 
127 	/* t ccd l min, ps */
128 	calc_val = spd_data->byte_fields.byte_40 * MV_DDR_SPD_DATA_MTB +
129 		(signed char)spd_data->byte_fields.byte_117 * MV_DDR_SPD_DATA_FTB;
130 	if (calc_val < 0)
131 		return 1;
132 	timing_data[MV_DDR_TCCD_L_MIN] = calc_val;
133 
134 	/* t faw min, ps */
135 	timing_data[MV_DDR_TFAW_MIN] = (spd_data->byte_fields.byte_37 +
136 		(spd_data->byte_fields.byte_36.bit_fields.t_faw_min_msn << MV_DDR_SPD_MSB_OFFS)) *
137 		MV_DDR_SPD_DATA_MTB;
138 
139 	/* t wtr s min, ps */
140 	timing_data[MV_DDR_TWTR_S_MIN] = (spd_data->byte_fields.byte_44 +
141 		(spd_data->byte_fields.byte_43.bit_fields.t_wtr_s_min_msn << MV_DDR_SPD_MSB_OFFS)) *
142 		MV_DDR_SPD_DATA_MTB;
143 
144 	/* t wtr l min, ps */
145 	timing_data[MV_DDR_TWTR_L_MIN] = (spd_data->byte_fields.byte_45 +
146 		(spd_data->byte_fields.byte_43.bit_fields.t_wtr_l_min_msn << MV_DDR_SPD_MSB_OFFS)) *
147 		MV_DDR_SPD_DATA_MTB;
148 
149 	return 0;
150 }
151 
mv_ddr_spd_dev_width_get(union mv_ddr_spd_data * spd_data)152 enum mv_ddr_dev_width mv_ddr_spd_dev_width_get(union mv_ddr_spd_data *spd_data)
153 {
154 	unsigned char dev_width = spd_data->byte_fields.byte_12.bit_fields.device_width;
155 	enum mv_ddr_dev_width ret_val;
156 
157 	switch (dev_width) {
158 	case 0x00:
159 		ret_val = MV_DDR_DEV_WIDTH_4BIT;
160 		break;
161 	case 0x01:
162 		ret_val = MV_DDR_DEV_WIDTH_8BIT;
163 		break;
164 	case 0x02:
165 		ret_val = MV_DDR_DEV_WIDTH_16BIT;
166 		break;
167 	case 0x03:
168 		ret_val = MV_DDR_DEV_WIDTH_32BIT;
169 		break;
170 	default:
171 		ret_val = MV_DDR_DEV_WIDTH_LAST;
172 	}
173 
174 	return ret_val;
175 }
176 
mv_ddr_spd_die_capacity_get(union mv_ddr_spd_data * spd_data)177 enum mv_ddr_die_capacity mv_ddr_spd_die_capacity_get(union mv_ddr_spd_data *spd_data)
178 {
179 	unsigned char die_cap = spd_data->byte_fields.byte_4.bit_fields.die_capacity;
180 	enum mv_ddr_die_capacity ret_val;
181 
182 	switch (die_cap) {
183 	case 0x00:
184 		ret_val = MV_DDR_DIE_CAP_256MBIT;
185 		break;
186 	case 0x01:
187 		ret_val = MV_DDR_DIE_CAP_512MBIT;
188 		break;
189 	case 0x02:
190 		ret_val = MV_DDR_DIE_CAP_1GBIT;
191 		break;
192 	case 0x03:
193 		ret_val = MV_DDR_DIE_CAP_2GBIT;
194 		break;
195 	case 0x04:
196 		ret_val = MV_DDR_DIE_CAP_4GBIT;
197 		break;
198 	case 0x05:
199 		ret_val = MV_DDR_DIE_CAP_8GBIT;
200 		break;
201 	case 0x06:
202 		ret_val = MV_DDR_DIE_CAP_16GBIT;
203 		break;
204 	case 0x07:
205 		ret_val = MV_DDR_DIE_CAP_32GBIT;
206 		break;
207 	case 0x08:
208 		ret_val = MV_DDR_DIE_CAP_12GBIT;
209 		break;
210 	case 0x09:
211 		ret_val = MV_DDR_DIE_CAP_24GBIT;
212 		break;
213 	default:
214 		ret_val = MV_DDR_DIE_CAP_LAST;
215 	}
216 
217 	return ret_val;
218 }
219 
mv_ddr_spd_mem_mirror_get(union mv_ddr_spd_data * spd_data)220 unsigned char mv_ddr_spd_mem_mirror_get(union mv_ddr_spd_data *spd_data)
221 {
222 	unsigned char mem_mirror = spd_data->byte_fields.byte_131.bit_fields.rank_1_mapping;
223 
224 	return mem_mirror;
225 }
226 
mv_ddr_spd_pri_bus_width_get(union mv_ddr_spd_data * spd_data)227 enum mv_ddr_pkg_rank mv_ddr_spd_pri_bus_width_get(union mv_ddr_spd_data *spd_data)
228 {
229 	unsigned char pri_bus_width = spd_data->byte_fields.byte_13.bit_fields.primary_bus_width;
230 	enum mv_ddr_pri_bus_width ret_val;
231 
232 	switch (pri_bus_width) {
233 	case 0x00:
234 		ret_val = MV_DDR_PRI_BUS_WIDTH_8;
235 		break;
236 	case 0x01:
237 		ret_val = MV_DDR_PRI_BUS_WIDTH_16;
238 		break;
239 	case 0x02:
240 		ret_val = MV_DDR_PRI_BUS_WIDTH_32;
241 		break;
242 	case 0x03:
243 		ret_val = MV_DDR_PRI_BUS_WIDTH_64;
244 		break;
245 	default:
246 		ret_val = MV_DDR_PRI_BUS_WIDTH_LAST;
247 	}
248 
249 	return ret_val;
250 }
251 
mv_ddr_spd_bus_width_ext_get(union mv_ddr_spd_data * spd_data)252 enum mv_ddr_pkg_rank mv_ddr_spd_bus_width_ext_get(union mv_ddr_spd_data *spd_data)
253 {
254 	unsigned char bus_width_ext = spd_data->byte_fields.byte_13.bit_fields.bus_width_ext;
255 	enum mv_ddr_bus_width_ext ret_val;
256 
257 	switch (bus_width_ext) {
258 	case 0x00:
259 		ret_val = MV_DDR_BUS_WIDTH_EXT_0;
260 		break;
261 	case 0x01:
262 		ret_val = MV_DDR_BUS_WIDTH_EXT_8;
263 		break;
264 	default:
265 		ret_val = MV_DDR_BUS_WIDTH_EXT_LAST;
266 	}
267 
268 	return ret_val;
269 }
270 
mv_ddr_spd_pkg_rank_get(union mv_ddr_spd_data * spd_data)271 static enum mv_ddr_pkg_rank mv_ddr_spd_pkg_rank_get(union mv_ddr_spd_data *spd_data)
272 {
273 	unsigned char pkg_rank = spd_data->byte_fields.byte_12.bit_fields.dimm_pkg_ranks_num;
274 	enum mv_ddr_pkg_rank ret_val;
275 
276 	switch (pkg_rank) {
277 	case 0x00:
278 		ret_val = MV_DDR_PKG_RANK_1;
279 		break;
280 	case 0x01:
281 		ret_val = MV_DDR_PKG_RANK_2;
282 		break;
283 	case 0x02:
284 		ret_val = MV_DDR_PKG_RANK_3;
285 		break;
286 	case 0x03:
287 		ret_val = MV_DDR_PKG_RANK_4;
288 		break;
289 	case 0x04:
290 		ret_val = MV_DDR_PKG_RANK_5;
291 		break;
292 	case 0x05:
293 		ret_val = MV_DDR_PKG_RANK_6;
294 		break;
295 	case 0x06:
296 		ret_val = MV_DDR_PKG_RANK_7;
297 		break;
298 	case 0x07:
299 		ret_val = MV_DDR_PKG_RANK_8;
300 		break;
301 	default:
302 		ret_val = MV_DDR_PKG_RANK_LAST;
303 	}
304 
305 	return ret_val;
306 }
307 
mv_ddr_spd_die_count_get(union mv_ddr_spd_data * spd_data)308 static enum mv_ddr_die_count mv_ddr_spd_die_count_get(union mv_ddr_spd_data *spd_data)
309 {
310 	unsigned char die_count = spd_data->byte_fields.byte_6.bit_fields.die_count;
311 	enum mv_ddr_die_count ret_val;
312 
313 	switch (die_count) {
314 	case 0x00:
315 		ret_val = MV_DDR_DIE_CNT_1;
316 		break;
317 	case 0x01:
318 		ret_val = MV_DDR_DIE_CNT_2;
319 		break;
320 	case 0x02:
321 		ret_val = MV_DDR_DIE_CNT_3;
322 		break;
323 	case 0x03:
324 		ret_val = MV_DDR_DIE_CNT_4;
325 		break;
326 	case 0x04:
327 		ret_val = MV_DDR_DIE_CNT_5;
328 		break;
329 	case 0x05:
330 		ret_val = MV_DDR_DIE_CNT_6;
331 		break;
332 	case 0x06:
333 		ret_val = MV_DDR_DIE_CNT_7;
334 		break;
335 	case 0x07:
336 		ret_val = MV_DDR_DIE_CNT_8;
337 		break;
338 	default:
339 		ret_val = MV_DDR_DIE_CNT_LAST;
340 	}
341 
342 	return ret_val;
343 }
344 
mv_ddr_spd_cs_bit_mask_get(union mv_ddr_spd_data * spd_data)345 unsigned char mv_ddr_spd_cs_bit_mask_get(union mv_ddr_spd_data *spd_data)
346 {
347 	unsigned char cs_bit_mask = 0x0;
348 	enum mv_ddr_pkg_rank pkg_rank = mv_ddr_spd_pkg_rank_get(spd_data);
349 	enum mv_ddr_die_count die_cnt = mv_ddr_spd_die_count_get(spd_data);
350 
351 	if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_1)
352 		cs_bit_mask = 0x1;
353 	else if (pkg_rank == MV_DDR_PKG_RANK_1 && die_cnt == MV_DDR_DIE_CNT_2)
354 		cs_bit_mask = 0x3;
355 	else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_1)
356 		cs_bit_mask = 0x3;
357 	else if (pkg_rank == MV_DDR_PKG_RANK_2 && die_cnt == MV_DDR_DIE_CNT_2)
358 		cs_bit_mask = 0xf;
359 
360 	return cs_bit_mask;
361 }
362 
mv_ddr_spd_dev_type_get(union mv_ddr_spd_data * spd_data)363 unsigned char mv_ddr_spd_dev_type_get(union mv_ddr_spd_data *spd_data)
364 {
365 	unsigned char dev_type = spd_data->byte_fields.byte_2;
366 
367 	return dev_type;
368 }
369 
mv_ddr_spd_module_type_get(union mv_ddr_spd_data * spd_data)370 unsigned char mv_ddr_spd_module_type_get(union mv_ddr_spd_data *spd_data)
371 {
372 	unsigned char module_type = spd_data->byte_fields.byte_3.bit_fields.module_type;
373 
374 	return module_type;
375 }
376