blob: bda60b8bd78ac4393e614e69cb67186338ce5a84 [file] [log] [blame]
davidhendricks@gmail.comffdc0932012-02-27 23:46:44 +00001/* Copyright 2012, Google Inc.
2 * All rights reserved.
dhendrix@google.com7d320d22011-02-08 22:21:06 +00003 *
davidhendricks@gmail.comffdc0932012-02-27 23:46:44 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
dhendrix@google.com7d320d22011-02-08 22:21:06 +00007 *
davidhendricks@gmail.comffdc0932012-02-27 23:46:44 +00008 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
dhendrix@google.com7d320d22011-02-08 22:21:06 +000017 *
davidhendricks@gmail.comffdc0932012-02-27 23:46:44 +000018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dhendrix@google.com7d320d22011-02-08 22:21:06 +000029 *
30 * DDR3 field access for DDR3 SPDs.
31 */
32
33#include <ctype.h>
34#include <stdint.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <string.h>
38
dhendrix@google.comcc628f52011-09-28 01:20:37 +000039#include <valstr.h>
40
dhendrix@google.com7d320d22011-02-08 22:21:06 +000041#include "mosys/platform.h"
42#include "mosys/kv_pair.h"
43
44#include "lib/string.h"
dhendrix@google.com7d320d22011-02-08 22:21:06 +000045
46#include "lib/ddr3.h"
dhendrix@google.com7d320d22011-02-08 22:21:06 +000047#include "lib/spd.h"
48
dhendrix@google.com1f8bd822011-02-08 22:57:20 +000049#include "jedec_id.h"
50
dhendrix@google.com1b1f1d12011-02-12 00:01:04 +000051static const struct valstr ddr3_module_type_lut[] = {
52 { 0x00, "Undefined" },
53 { 0x01, "RDIMM" },
54 { 0x02, "UDIMM" },
55 { 0x03, "SO-DIMM" },
56 { 0x04, "MICRO-DIMM" },
57 { 0x05, "MINI-RDIMM" },
58 { 0x06, "MINI-UDIMM" },
59 { 0x07, "MINI-CDIMM" },
60 { 0x08, "72b-SO-UDIMM" },
61 { 0x09, "72b-SO-RDIMM" },
62 { 0x0a, "72b-SO-CDIMM" },
63 { 0x0b, "LRDIMM" },
64};
65
dhendrix@google.com7d320d22011-02-08 22:21:06 +000066/*
67 * spd_print_field_ddr3 - add common DDR SPD fields into key=value pair
68 *
69 * @intf: platform interface
70 * @kv: key=value pair
71 * @data: raw spd data
72 * @type: type of field to retrieve
73 *
74 * returns 1 to indicate data added to key=value pair
75 * returns 0 to indicate no data added
76 * returns <0 to indicate error
77 *
78 */
79int spd_print_field_ddr3(struct platform_intf *intf, struct kv_pair *kv,
80 const void *data, enum spd_field_type type)
81{
82 int ret;
83 const uint8_t *byte = data;
84
85 ret = 0;
86 switch (type) {
dhendrix@google.com1b1f1d12011-02-12 00:01:04 +000087 case SPD_GET_DRAM_TYPE:
dhendrix@google.com597d3032011-02-12 00:05:53 +000088 kv_pair_add(kv, "dram", "DDR3");
dhendrix@google.com1b1f1d12011-02-12 00:01:04 +000089 ret = 1;
90 break;
91 case SPD_GET_MODULE_TYPE:
dhendrix@google.com597d3032011-02-12 00:05:53 +000092 kv_pair_add(kv, "module",
dhendrix@google.com1b1f1d12011-02-12 00:01:04 +000093 val2str(byte[DDR3_SPD_REG_MODULE_TYPE],
94 ddr3_module_type_lut));
95 ret = 1;
96 break;
dhendrix@google.com7d320d22011-02-08 22:21:06 +000097 case SPD_GET_MFG_ID:
98 {
99 uint8_t manuf_lsb;
100 uint8_t manuf_msb;
101 const char *tstr;
102
103 manuf_lsb = byte[DDR3_SPD_REG_MODULE_MANUF_JEDEC_ID_LSB] & 0x7f;
dhendrix@google.com2f6879c2011-02-09 04:29:50 +0000104 manuf_msb = byte[DDR3_SPD_REG_MODULE_MANUF_JEDEC_ID_MSB] & 0x7f;
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000105
106 tstr = jedec_manufacturer(manuf_lsb, manuf_msb);
107
108 if (tstr != NULL) {
dhendrix@google.com00d74fc2011-02-09 03:02:11 +0000109 kv_pair_fmt(kv, "module_mfg", "%u-%u: %s", manuf_lsb + 1,
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000110 manuf_msb, tstr);
111 } else {
dhendrix@google.com00d74fc2011-02-09 03:02:11 +0000112 kv_pair_fmt(kv, "module_mfg", "%u-%u", manuf_lsb + 1,
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000113 manuf_msb);
114 }
115 ret = 1;
116 break;
117 }
118
119 case SPD_GET_MFG_ID_DRAM:
120 {
121 uint8_t manuf_lsb;
122 uint8_t manuf_msb;
123 const char *tstr;
124
125 manuf_lsb = byte[DDR3_SPD_REG_DRAM_MANUF_JEDEC_ID_LSB] & 0x7f;
dhendrix@google.com2f6879c2011-02-09 04:29:50 +0000126 manuf_msb = byte[DDR3_SPD_REG_DRAM_MANUF_JEDEC_ID_MSB] & 0x7f;
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000127
128 tstr = jedec_manufacturer(manuf_lsb, manuf_msb);
129
130 if (tstr != NULL) {
dhendrix@google.com00d74fc2011-02-09 03:02:11 +0000131 kv_pair_fmt(kv, "dram_mfg", "%u-%u: %s",
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000132 manuf_lsb + 1, manuf_msb, tstr);
133 } else {
dhendrix@google.com00d74fc2011-02-09 03:02:11 +0000134 kv_pair_fmt(kv, "dram_mfg", "%u-%u",
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000135 manuf_lsb + 1, manuf_msb);
136 }
137 ret = 1;
138 break;
139 }
140
141 case SPD_GET_MFG_LOC:
142 {
143 kv_pair_fmt(kv, "mfg_loc", "0x%02x",
144 byte[DDR3_SPD_REG_MODULE_MANUF_LOC]);
145 ret = 1;
146 break;
147 }
148
149 case SPD_GET_MFG_DATE: /* manufacturing date (BCD values) */
150 {
151 uint8_t year;
152 uint8_t week;
153
154 year = byte[DDR3_SPD_REG_MODULE_MANUF_DATE_YEAR];
155 week = byte[DDR3_SPD_REG_MODULE_MANUF_DATE_YEAR];
156 kv_pair_fmt(kv, "mfg_date", "20%02x-wk%02x", week, year);
157 ret = 1;
158 break;
159 }
160
161 case SPD_GET_SERIAL_NUMBER:
162 {
dhendrix@google.comdac5b422011-02-09 02:43:16 +0000163 kv_pair_fmt(kv, "serial_number", "%02x%02x%02x%02x",
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000164 byte[DDR3_SPD_REG_MODULE_MANUF_SERIAL_0],
165 byte[DDR3_SPD_REG_MODULE_MANUF_SERIAL_1],
166 byte[DDR3_SPD_REG_MODULE_MANUF_SERIAL_2],
167 byte[DDR3_SPD_REG_MODULE_MANUF_SERIAL_3]);
168 ret = 1;
169 break;
170 }
171
172 case SPD_GET_PART_NUMBER:
173 {
174 char part[19];
175
176 memcpy(part, &byte[DDR3_SPD_REG_MODULE_PART_NUM_0], 18);
177 part[18] = '\0';
178 kv_pair_fmt(kv, "part_number", "%s", part);
179
180 ret = 1;
181 break;
182 }
183
184 case SPD_GET_REVISION_CODE:
185 {
186 kv_pair_fmt(kv, "revision_code", "0x%02x%02x",
187 byte[DDR3_SPD_REG_MODULE_REVISION_0],
188 byte[DDR3_SPD_REG_MODULE_REVISION_1]);
189 ret = 1;
190 break;
191 }
192
193 case SPD_GET_SIZE:
194 {
195 /* See "Calculating Module Capacity" section in DDR3 SPD
196 * specification for details. */
David Hendricksae2d5422012-07-18 14:52:41 -0700197 unsigned int size;
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000198
199 /* calculate the total size in MB */
200 size = 256 << (byte[DDR3_SPD_REG_DENSITY_BANKS] & 0xf);
201 size >>= 3; /* in terms of bytes instead of bits. */
202 size *= 8 << (byte[DDR3_SPD_REG_MODULE_BUS_WIDTH] & 0x7);
203 size /= 4 << (byte[DDR3_SPD_REG_MODULE_ORG] & 0x7);
204 size *= 1 + ((byte[DDR3_SPD_REG_MODULE_ORG] >> 3) & 0x7);
205
David Hendricksae2d5422012-07-18 14:52:41 -0700206 kv_pair_fmt(kv, "size_mb", "%u", size);
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000207 ret = 1;
208 break;
209 }
210
211 case SPD_GET_ECC:
212 {
213 uint8_t bus_ext_width = byte[DDR3_SPD_REG_MODULE_BUS_WIDTH];
214 bus_ext_width >>= 3;
215 bus_ext_width &= 0x7;
216 kv_pair_add_bool(kv, "ecc", bus_ext_width);
217 ret = 1;
218 break;
219 }
220
221 case SPD_GET_RANKS:
222 {
223 kv_pair_fmt(kv, "ranks", "%d",
224 1 + ((byte[DDR3_SPD_REG_MODULE_ORG] >> 3) & 0x7));
225 ret = 1;
226 break;
227 }
228
229 case SPD_GET_WIDTH:
230 {
231 /* Total width including ECC. */
232 uint8_t width;
233 width = 8 << (byte[DDR3_SPD_REG_MODULE_BUS_WIDTH] & 0x7);
234 width += 8 * ((byte[DDR3_SPD_REG_MODULE_BUS_WIDTH] >> 3) & 0x7);
235 kv_pair_fmt(kv, "width", "%d", width);
236 ret = 1;
237 break;
238 }
239
240 case SPD_GET_CHECKSUM:
241 {
242 kv_pair_fmt(kv, "checksum", "0x%02x%02x",
243 byte[DDR3_SPD_REG_CRC_1],
244 byte[DDR3_SPD_REG_CRC_0]);
245 ret = 1;
246 break;
247 }
248
249 case SPD_GET_SPEEDS:
250 {
251 int i;
252 int mhz;
253 int one_added;
254 char speeds[128];
255 const struct valstr possible_mhz[] = {
256 { 400, "DDR3-800" },
257 { 533, "DDR3-1066" },
258 { 667, "DDR3-1333" },
259 { 800, "DDR3-1600" },
260 { 0 }
261 };
262
263 mhz = 1000 * byte[DDR3_SPD_REG_MTB_DIVISOR];
264 mhz /= byte[DDR3_SPD_REG_MTB_DIVIDEND];
265 mhz /= byte[DDR3_SPD_REG_TCK_MIN];
266
267 memset(speeds, 0, sizeof(speeds));
268 one_added = 0;
269 for (i = 0; possible_mhz[i].val != 0; i++) {
dhendrix@google.com04cdd4f2011-09-21 22:20:32 +0000270 double min = possible_mhz[i].val * 0.99;
271
272 if (min <= mhz) {
dhendrix@google.com7d320d22011-02-08 22:21:06 +0000273 if (one_added) {
274 strcat(speeds, ", ");
275 }
276 one_added = 1;
277 strcat(speeds, possible_mhz[i].str);
278 }
279 }
280
281 kv_pair_add(kv, "speeds", speeds);
282 ret = 1;
283 break;
284 }
285
286 default:
287 {
288 ret = 0; /* force "we don't handle this here */
289 break;
290 }
291 }
292
293 return ret;
294}