blob: 04dbfe94d668eef53fbf8279f897a71f5b1b4445 [file] [log] [blame]
Chris Packham1a07d212018-05-10 13:28:29 +12001// 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
14static unsigned int mv_ddr_spd_supported_cls[MV_DDR_SPD_SUPPORTED_CLS_NUM];
15
16int 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
41unsigned 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
58int 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;
Chris Packham1a07d212018-05-10 13:28:29 +120084
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
Chris Packham4bf81db2018-12-03 14:26:49 +1300127 /* 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
Chris Packham1a07d212018-05-10 13:28:29 +1200134 /* 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;
Chris Packham1a07d212018-05-10 13:28:29 +1200143
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;
Chris Packham1a07d212018-05-10 13:28:29 +1200148
149 return 0;
150}
151
152enum 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
177enum 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
220unsigned 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
227enum 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
252enum 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
271static 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
308static 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
345unsigned 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
363unsigned 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
370unsigned 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}