File: | dev/spdmem.c |
Warning: | line 721, column 3 Value stored to 'd_clk' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: spdmem.c,v 1.7 2019/12/21 12:33:03 kettenis Exp $ */ |
2 | /* $NetBSD: spdmem.c,v 1.3 2007/09/20 23:09:59 xtraeme Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 2007 Jonathan Gray <jsg@openbsd.org> |
6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. |
10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ |
19 | |
20 | /* |
21 | * Copyright (c) 2007 Nicolas Joly |
22 | * Copyright (c) 2007 Paul Goyette |
23 | * Copyright (c) 2007 Tobias Nygren |
24 | * All rights reserved. |
25 | * |
26 | * Redistribution and use in source and binary forms, with or without |
27 | * modification, are permitted provided that the following conditions |
28 | * are met: |
29 | * 1. Redistributions of source code must retain the above copyright |
30 | * notice, this list of conditions and the following disclaimer. |
31 | * 2. Redistributions in binary form must reproduce the above copyright |
32 | * notice, this list of conditions and the following disclaimer in the |
33 | * documentation and/or other materials provided with the distribution. |
34 | * 3. The name of the author may not be used to endorse or promote products |
35 | * derived from this software without specific prior written permission. |
36 | * |
37 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS |
38 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
39 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
40 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
41 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
42 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
43 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
44 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
45 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
46 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
47 | * POSSIBILITY OF SUCH DAMAGE. |
48 | */ |
49 | |
50 | /* |
51 | * Serial Presence Detect (SPD) memory identification |
52 | */ |
53 | |
54 | #include <sys/param.h> |
55 | #include <sys/systm.h> |
56 | #include <sys/device.h> |
57 | |
58 | #include <dev/spdmemvar.h> |
59 | |
60 | /* Encodings of the size used/total byte for certain memory types */ |
61 | #define SPDMEM_SPDSIZE_MASK0x0F 0x0F /* SPD EEPROM Size */ |
62 | |
63 | #define SPDMEM_SPDLEN_1280x00 0x00 /* SPD EEPROM Sizes */ |
64 | #define SPDMEM_SPDLEN_1760x10 0x10 |
65 | #define SPDMEM_SPDLEN_2560x20 0x20 |
66 | #define SPDMEM_SPDLEN_MASK0x70 0x70 /* Bits 4 - 6 */ |
67 | |
68 | #define SPDMEM_DDR4_SPDLEN_1280x01 0x01 /* SPD EEPROM Sizes */ |
69 | #define SPDMEM_DDR4_SPDLEN_2560x02 0x02 |
70 | #define SPDMEM_DDR4_SPDLEN_3840x03 0x03 |
71 | #define SPDMEM_DDR4_SPDLEN_5120x04 0x04 |
72 | #define SPDMEM_DDR4_SPDLEN_MASK0x0f 0x0f /* Bits 4 - 6 */ |
73 | |
74 | #define SPDMEM_SPDCRC_1160x80 0x80 /* CRC Bytes covered */ |
75 | #define SPDMEM_SPDCRC_1250x00 0x00 |
76 | #define SPDMEM_SPDCRC_MASK0x80 0x80 /* Bit 7 */ |
77 | |
78 | /* possible values for the memory type */ |
79 | #define SPDMEM_MEMTYPE_FPM0x01 0x01 |
80 | #define SPDMEM_MEMTYPE_EDO0x02 0x02 |
81 | #define SPDMEM_MEMTYPE_PIPE_NIBBLE0x03 0x03 |
82 | #define SPDMEM_MEMTYPE_SDRAM0x04 0x04 |
83 | #define SPDMEM_MEMTYPE_ROM0x05 0x05 |
84 | #define SPDMEM_MEMTYPE_DDRSGRAM0x06 0x06 |
85 | #define SPDMEM_MEMTYPE_DDRSDRAM0x07 0x07 |
86 | #define SPDMEM_MEMTYPE_DDR2SDRAM0x08 0x08 |
87 | #define SPDMEM_MEMTYPE_FBDIMM0x09 0x09 |
88 | #define SPDMEM_MEMTYPE_FBDIMM_PROBE0x0a 0x0a |
89 | #define SPDMEM_MEMTYPE_DDR3SDRAM0x0b 0x0b |
90 | #define SPDMEM_MEMTYPE_DDR4SDRAM0x0c 0x0c |
91 | /* 0xd reserved */ |
92 | #define SPDMEM_MEMTYPE_DDR4ESDRAM0x0e 0x0e |
93 | #define SPDMEM_MEMTYPE_LPDDR3SDRAM0x0f 0x0f |
94 | #define SPDMEM_MEMTYPE_LPDDR4SDRAM0x10 0x10 |
95 | #define SPDMEM_MEMTYPE_LPDDR4XSDRAM0x11 0x11 |
96 | #define SPDMEM_MEMTYPE_DDR5SDRAM0x12 0x12 |
97 | #define SPDMEM_MEMTYPE_LPDDR5SDRAM0x13 0x13 |
98 | |
99 | #define SPDMEM_MEMTYPE_NONE0xff 0xff |
100 | |
101 | #define SPDMEM_MEMTYPE_DIRECT_RAMBUS0x01 0x01 |
102 | #define SPDMEM_MEMTYPE_RAMBUS0x11 0x11 |
103 | |
104 | /* possible values for the supply voltage */ |
105 | #define SPDMEM_VOLTAGE_TTL_5V0x00 0x00 |
106 | #define SPDMEM_VOLTAGE_TTL_LV0x01 0x01 |
107 | #define SPDMEM_VOLTAGE_HSTTL_1_5V0x02 0x02 |
108 | #define SPDMEM_VOLTAGE_SSTL_3_3V0x03 0x03 |
109 | #define SPDMEM_VOLTAGE_SSTL_2_5V0x04 0x04 |
110 | #define SPDMEM_VOLTAGE_SSTL_1_8V0x05 0x05 |
111 | |
112 | /* possible values for module configuration */ |
113 | #define SPDMEM_MODCONFIG_PARITY0x01 0x01 |
114 | #define SPDMEM_MODCONFIG_ECC0x02 0x02 |
115 | |
116 | /* for DDR2, module configuration is a bit-mask field */ |
117 | #define SPDMEM_MODCONFIG_HAS_DATA_PARITY0x01 0x01 |
118 | #define SPDMEM_MODCONFIG_HAS_DATA_ECC0x02 0x02 |
119 | #define SPDMEM_MODCONFIG_HAS_ADDR_CMD_PARITY0x04 0x04 |
120 | |
121 | /* possible values for the refresh field */ |
122 | #define SPDMEM_REFRESH_STD0x00 0x00 |
123 | #define SPDMEM_REFRESH_QUARTER0x01 0x01 |
124 | #define SPDMEM_REFRESH_HALF0x02 0x02 |
125 | #define SPDMEM_REFRESH_TWOX0x03 0x03 |
126 | #define SPDMEM_REFRESH_FOURX0x04 0x04 |
127 | #define SPDMEM_REFRESH_EIGHTX0x05 0x05 |
128 | #define SPDMEM_REFRESH_SELFREFRESH0x80 0x80 |
129 | |
130 | /* superset types */ |
131 | #define SPDMEM_SUPERSET_ESDRAM0x01 0x01 |
132 | #define SPDMEM_SUPERSET_DDR_ESDRAM0x02 0x02 |
133 | #define SPDMEM_SUPERSET_EDO_PEM0x03 0x03 |
134 | #define SPDMEM_SUPERSET_SDR_PEM0x04 0x04 |
135 | |
136 | /* FPM and EDO DIMMS */ |
137 | #define SPDMEM_FPM_ROWS0x00 0x00 |
138 | #define SPDMEM_FPM_COLS0x01 0x01 |
139 | #define SPDMEM_FPM_BANKS0x02 0x02 |
140 | #define SPDMEM_FPM_CONFIG0x08 0x08 |
141 | #define SPDMEM_FPM_REFRESH0x09 0x09 |
142 | #define SPDMEM_FPM_SUPERSET0x0c 0x0c |
143 | |
144 | /* PC66/PC100/PC133 SDRAM */ |
145 | #define SPDMEM_SDR_ROWS0x00 0x00 |
146 | #define SPDMEM_SDR_COLS0x01 0x01 |
147 | #define SPDMEM_SDR_BANKS0x02 0x02 |
148 | #define SPDMEM_SDR_CYCLE0x06 0x06 |
149 | #define SPDMEM_SDR_BANKS_PER_CHIP0x0e 0x0e |
150 | #define SPDMEM_SDR_MOD_ATTRIB0x12 0x12 |
151 | #define SPDMEM_SDR_SUPERSET0x1d 0x1d |
152 | |
153 | #define SPDMEM_SDR_FREQUENCY126 126 |
154 | #define SPDMEM_SDR_CAS127 127 |
155 | #define SPDMEM_SDR_FREQ_660x66 0x66 |
156 | #define SPDMEM_SDR_FREQ_1000x64 0x64 |
157 | #define SPDMEM_SDR_FREQ_1330x85 0x85 |
158 | #define SPDMEM_SDR_CAS2(1 << 1) (1 << 1) |
159 | #define SPDMEM_SDR_CAS3(1 << 2) (1 << 2) |
160 | |
161 | /* Rambus Direct DRAM */ |
162 | #define SPDMEM_RDR_MODULE_TYPE0x00 0x00 |
163 | #define SPDMEM_RDR_ROWS_COLS0x01 0x01 |
164 | #define SPDMEM_RDR_BANK0x02 0x02 |
165 | |
166 | #define SPDMEM_RDR_TYPE_RIMM1 1 |
167 | #define SPDMEM_RDR_TYPE_SORIMM2 2 |
168 | #define SPDMEM_RDR_TYPE_EMBED3 3 |
169 | #define SPDMEM_RDR_TYPE_RIMM324 4 |
170 | |
171 | /* Dual Data Rate SDRAM */ |
172 | #define SPDMEM_DDR_ROWS0x00 0x00 |
173 | #define SPDMEM_DDR_COLS0x01 0x01 |
174 | #define SPDMEM_DDR_RANKS0x02 0x02 |
175 | #define SPDMEM_DDR_DATAWIDTH0x03 0x03 |
176 | #define SPDMEM_DDR_VOLTAGE0x05 0x05 |
177 | #define SPDMEM_DDR_CYCLE0x06 0x06 |
178 | #define SPDMEM_DDR_REFRESH0x09 0x09 |
179 | #define SPDMEM_DDR_BANKS_PER_CHIP0x0e 0x0e |
180 | #define SPDMEM_DDR_CAS0x0f 0x0f |
181 | #define SPDMEM_DDR_MOD_ATTRIB0x12 0x12 |
182 | #define SPDMEM_DDR_SUPERSET0x1d 0x1d |
183 | |
184 | #define SPDMEM_DDR_ATTRIB_REG(1 << 1) (1 << 1) |
185 | |
186 | /* Dual Data Rate 2 SDRAM */ |
187 | #define SPDMEM_DDR2_ROWS0x00 0x00 |
188 | #define SPDMEM_DDR2_COLS0x01 0x01 |
189 | #define SPDMEM_DDR2_RANKS0x02 0x02 |
190 | #define SPDMEM_DDR2_DATAWIDTH0x03 0x03 |
191 | #define SPDMEM_DDR2_VOLTAGE0x05 0x05 |
192 | #define SPDMEM_DDR2_CYCLE0x06 0x06 |
193 | #define SPDMEM_DDR2_DIMMTYPE0x11 0x11 |
194 | #define SPDMEM_DDR2_RANK_DENSITY0x1c 0x1c |
195 | |
196 | #define SPDMEM_DDR2_TYPE_REGMASK((1 << 4) | (1 << 0)) ((1 << 4) | (1 << 0)) |
197 | #define SPDMEM_DDR2_SODIMM(1 << 2) (1 << 2) |
198 | #define SPDMEM_DDR2_MICRO_DIMM(1 << 3) (1 << 3) |
199 | #define SPDMEM_DDR2_MINI_RDIMM(1 << 4) (1 << 4) |
200 | #define SPDMEM_DDR2_MINI_UDIMM(1 << 5) (1 << 5) |
201 | |
202 | /* DDR2 FB-DIMM SDRAM */ |
203 | #define SPDMEM_FBDIMM_ADDR0x01 0x01 |
204 | #define SPDMEM_FBDIMM_RANKS0x04 0x04 |
205 | #define SPDMEM_FBDIMM_MTB_DIVIDEND0x06 0x06 |
206 | #define SPDMEM_FBDIMM_MTB_DIVISOR0x07 0x07 |
207 | #define SPDMEM_FBDIMM_PROTO0x4e 0x4e |
208 | |
209 | #define SPDMEM_FBDIMM_RANKS_WIDTH0x07 0x07 |
210 | #define SPDMEM_FBDIMM_ADDR_BANKS0x02 0x02 |
211 | #define SPDMEM_FBDIMM_ADDR_COL0x0c 0x0c |
212 | #define SPDMEM_FBDIMM_ADDR_COL_SHIFT2 2 |
213 | #define SPDMEM_FBDIMM_ADDR_ROW0xe0 0xe0 |
214 | #define SPDMEM_FBDIMM_ADDR_ROW_SHIFT5 5 |
215 | #define SPDMEM_FBDIMM_PROTO_ECC(1 << 1) (1 << 1) |
216 | |
217 | |
218 | /* Dual Data Rate 3 SDRAM */ |
219 | #define SPDMEM_DDR3_MODTYPE0x00 0x00 |
220 | #define SPDMEM_DDR3_DENSITY0x01 0x01 |
221 | #define SPDMEM_DDR3_MOD_ORG0x04 0x04 |
222 | #define SPDMEM_DDR3_DATAWIDTH0x05 0x05 |
223 | #define SPDMEM_DDR3_MTB_DIVIDEND0x07 0x07 |
224 | #define SPDMEM_DDR3_MTB_DIVISOR0x08 0x08 |
225 | #define SPDMEM_DDR3_TCKMIN0x09 0x09 |
226 | #define SPDMEM_DDR3_THERMAL0x1d 0x1d |
227 | |
228 | #define SPDMEM_DDR3_DENSITY_CAPMASK0x0f 0x0f |
229 | #define SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK0x07 0x07 |
230 | #define SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT3 3 |
231 | #define SPDMEM_DDR3_MOD_ORG_BANKS_MASK0x07 0x07 |
232 | #define SPDMEM_DDR3_DATAWIDTH_ECCMASK(1 << 3) (1 << 3) |
233 | #define SPDMEM_DDR3_DATAWIDTH_PRIMASK0x07 0x07 |
234 | #define SPDMEM_DDR3_THERMAL_PRESENT(1 << 7) (1 << 7) |
235 | |
236 | #define SPDMEM_DDR3_RDIMM0x01 0x01 |
237 | #define SPDMEM_DDR3_UDIMM0x02 0x02 |
238 | #define SPDMEM_DDR3_SODIMM0x03 0x03 |
239 | #define SPDMEM_DDR3_MICRO_DIMM0x04 0x04 |
240 | #define SPDMEM_DDR3_MINI_RDIMM0x05 0x05 |
241 | #define SPDMEM_DDR3_MINI_UDIMM0x06 0x06 |
242 | |
243 | /* Dual Data Rate 4 SDRAM */ |
244 | #define SPDMEM_DDR4_MODTYPE0x00 0x00 |
245 | #define SPDMEM_DDR4_DENSITY0x01 0x01 |
246 | #define SPDMEM_DDR4_PACK_TYPE0x03 0x03 |
247 | #define SPDMEM_DDR4_MOD_ORG0x09 0x09 |
248 | #define SPDMEM_DDR4_DATAWIDTH0x0a 0x0a |
249 | #define SPDMEM_DDR4_THERMAL0x0b 0x0b |
250 | #define SPDMEM_DDR4_TCKMIN_MTB0x0f 0x0f |
251 | #define SPDMEM_DDR4_TCKMIN_FTB0x7d 0x7d /* not offset by 3 */ |
252 | |
253 | #define SPDMEM_DDR4_DENSITY_CAPMASK0x0f 0x0f |
254 | #define SPDMEM_DDR4_PACK_TYPE_SIG_LOAD_MASK0x03 0x03 |
255 | #define SPDMEM_DDR4_PACK_TYPE_SIG_SINGLE_LOAD0x02 0x02 |
256 | #define SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_SHIFT4 4 |
257 | #define SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_MASK0x07 0x07 |
258 | #define SPDMEM_DDR4_MOD_ORG_CHIPWIDTH_MASK0x07 0x07 |
259 | #define SPDMEM_DDR4_MOD_ORG_BANKS_SHIFT3 3 |
260 | #define SPDMEM_DDR4_MOD_ORG_BANKS_MASK0x07 0x07 |
261 | #define SPDMEM_DDR4_DATAWIDTH_ECCMASK(1 << 3) (1 << 3) |
262 | #define SPDMEM_DDR4_DATAWIDTH_PRIMASK0x07 0x07 |
263 | #define SPDMEM_DDR4_THERMAL_PRESENT(1 << 7) (1 << 7) |
264 | |
265 | #define SPDMEM_DDR4_RDIMM0x01 0x01 |
266 | #define SPDMEM_DDR4_UDIMM0x02 0x02 |
267 | #define SPDMEM_DDR4_SODIMM0x03 0x03 |
268 | #define SPDMEM_DDR4_LRDIMM0x04 0x04 |
269 | #define SPDMEM_DDR4_MINI_RDIMM0x05 0x05 |
270 | #define SPDMEM_DDR4_MINI_UDIMM0x06 0x06 |
271 | #define SPDMEM_DDR4_LP_DIMM0x07 0x07 |
272 | #define SPDMEM_DDR4_72B_SO_RDIMM0x08 0x08 |
273 | #define SPDMEM_DDR4_72B_SO_UDIMM0x09 0x09 |
274 | #define SPDMEM_DDR4_16B_SO_DIMM0x0c 0x0c |
275 | #define SPDMEM_DDR4_32B_SO_DIMM0x0d 0x0d |
276 | #define SPDMEM_DDR4_NON_DIMM0x0e 0x0e |
277 | #define SPDMEM_DDR4_MODTYPE_MASK0x0f 0x0f |
278 | #define SPDMEM_DDR4_MODTYPE_HYBRID0x80 0x80 |
279 | |
280 | static const uint8_t ddr2_cycle_tenths[] = { |
281 | 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 25, 33, 66, 75, 0, 0 |
282 | }; |
283 | |
284 | #define SPDMEM_TYPE_MAXLEN16 16 |
285 | |
286 | uint16_t spdmem_crc16(struct spdmem_softc *, int); |
287 | static inline |
288 | uint8_t spdmem_read(struct spdmem_softc *, uint8_t); |
289 | void spdmem_sdram_decode(struct spdmem_softc *, struct spdmem *); |
290 | void spdmem_rdr_decode(struct spdmem_softc *, struct spdmem *); |
291 | void spdmem_ddr_decode(struct spdmem_softc *, struct spdmem *); |
292 | void spdmem_ddr2_decode(struct spdmem_softc *, struct spdmem *); |
293 | void spdmem_fbdimm_decode(struct spdmem_softc *, struct spdmem *); |
294 | void spdmem_ddr3_decode(struct spdmem_softc *, struct spdmem *); |
295 | |
296 | struct cfdriver spdmem_cd = { |
297 | NULL((void *)0), "spdmem", DV_DULL |
298 | }; |
299 | |
300 | #define IS_RAMBUS_TYPE(s->sm_len < 4) (s->sm_len < 4) |
301 | |
302 | static const char *spdmem_basic_types[] = { |
303 | "unknown", |
304 | "FPM", |
305 | "EDO", |
306 | "Pipelined Nibble", |
307 | "SDRAM", |
308 | "ROM", |
309 | "DDR SGRAM", |
310 | "DDR SDRAM", |
311 | "DDR2 SDRAM", |
312 | "DDR2 SDRAM FB-DIMM", |
313 | "DDR2 SDRAM FB-DIMM Probe", |
314 | "DDR3 SDRAM", |
315 | "DDR4 SDRAM", |
316 | "unknown", |
317 | "DDR4E SDRAM", |
318 | "LPDDR3 SDRAM", |
319 | "LPDDR4 SDRAM", |
320 | "LPDDR4X SDRAM", |
321 | "DDR5 SDRAM", |
322 | "LPDDR5 SDRAM" |
323 | }; |
324 | |
325 | static const char *spdmem_superset_types[] = { |
326 | "unknown", |
327 | "ESDRAM", |
328 | "DDR ESDRAM", |
329 | "PEM EDO", |
330 | "PEM SDRAM" |
331 | }; |
332 | |
333 | static const char *spdmem_parity_types[] = { |
334 | "non-parity", |
335 | "data parity", |
336 | "ECC", |
337 | "data parity and ECC", |
338 | "cmd/addr parity", |
339 | "cmd/addr/data parity", |
340 | "cmd/addr parity, data ECC", |
341 | "cmd/addr/data parity, data ECC" |
342 | }; |
343 | |
344 | static inline uint8_t |
345 | spdmem_read(struct spdmem_softc *sc, uint8_t reg) |
346 | { |
347 | return (*sc->sc_read)(sc, reg); |
348 | } |
349 | |
350 | /* CRC functions used for certain memory types */ |
351 | uint16_t |
352 | spdmem_crc16(struct spdmem_softc *sc, int count) |
353 | { |
354 | uint16_t crc; |
355 | int i, j; |
356 | uint8_t val; |
357 | crc = 0; |
358 | for (j = 0; j <= count; j++) { |
359 | val = spdmem_read(sc, j); |
360 | crc = crc ^ val << 8; |
361 | for (i = 0; i < 8; ++i) |
362 | if (crc & 0x8000) |
363 | crc = crc << 1 ^ 0x1021; |
364 | else |
365 | crc = crc << 1; |
366 | } |
367 | return (crc & 0xFFFF); |
368 | } |
369 | |
370 | void |
371 | spdmem_sdram_decode(struct spdmem_softc *sc, struct spdmem *s) |
372 | { |
373 | const char *type; |
374 | int dimm_size, p_clk; |
375 | int num_banks, per_chip; |
376 | uint8_t rows, cols; |
377 | |
378 | type = spdmem_basic_types[s->sm_type]; |
379 | |
380 | if (s->sm_data[SPDMEM_SDR_SUPERSET0x1d] == SPDMEM_SUPERSET_SDR_PEM0x04) |
381 | type = spdmem_superset_types[SPDMEM_SUPERSET_SDR_PEM0x04]; |
382 | if (s->sm_data[SPDMEM_SDR_SUPERSET0x1d] == SPDMEM_SUPERSET_ESDRAM0x01) |
383 | type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM0x01]; |
384 | |
385 | num_banks = s->sm_data[SPDMEM_SDR_BANKS0x02]; |
386 | per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP0x0e]; |
387 | rows = s->sm_data[SPDMEM_SDR_ROWS0x00] & 0x0f; |
388 | cols = s->sm_data[SPDMEM_SDR_COLS0x01] & 0x0f; |
389 | dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip; |
390 | |
391 | if (dimm_size > 0) { |
392 | if (dimm_size < 1024) |
393 | printf(" %dMB", dimm_size); |
394 | else |
395 | printf(" %dGB", dimm_size / 1024); |
396 | } |
397 | |
398 | printf(" %s", type); |
399 | |
400 | if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB0x12] & SPDMEM_DDR_ATTRIB_REG(1 << 1)) |
401 | printf(" registered"); |
402 | |
403 | if (s->sm_data[SPDMEM_FPM_CONFIG0x08] < 8) |
404 | printf(" %s", |
405 | spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG0x08]]); |
406 | |
407 | p_clk = 66; |
408 | if (s->sm_len >= 128) { |
409 | switch (spdmem_read(sc, SPDMEM_SDR_FREQUENCY126)) { |
410 | case SPDMEM_SDR_FREQ_1000x64: |
411 | case SPDMEM_SDR_FREQ_1330x85: |
412 | /* We need to check ns to decide here */ |
413 | if (s->sm_data[SPDMEM_SDR_CYCLE0x06] < 0x80) |
414 | p_clk = 133; |
415 | else |
416 | p_clk = 100; |
417 | break; |
418 | case SPDMEM_SDR_FREQ_660x66: |
419 | default: |
420 | p_clk = 66; |
421 | break; |
422 | } |
423 | } |
424 | printf(" PC%d", p_clk); |
425 | |
426 | /* Print CAS latency */ |
427 | if (s->sm_len < 128) |
428 | return; |
429 | if (spdmem_read(sc, SPDMEM_SDR_CAS127) & SPDMEM_SDR_CAS2(1 << 1)) |
430 | printf("CL2"); |
431 | else if (spdmem_read(sc, SPDMEM_SDR_CAS127) & SPDMEM_SDR_CAS3(1 << 2)) |
432 | printf("CL3"); |
433 | } |
434 | |
435 | void |
436 | spdmem_rdr_decode(struct spdmem_softc *sc, struct spdmem *s) |
437 | { |
438 | int rimm_size; |
439 | uint8_t row_bits, col_bits, bank_bits; |
440 | |
441 | row_bits = s->sm_data[SPDMEM_RDR_ROWS_COLS0x01] >> 4; |
442 | col_bits = s->sm_data[SPDMEM_RDR_ROWS_COLS0x01] & 0x0f; |
443 | bank_bits = s->sm_data[SPDMEM_RDR_BANK0x02] & 0x07; |
444 | |
445 | /* subtracting 13 here is a cheaper way of dividing by 8k later */ |
446 | rimm_size = 1 << (row_bits + col_bits + bank_bits - 13); |
447 | |
448 | if (rimm_size < 1024) |
449 | printf(" %dMB ", rimm_size); |
450 | else |
451 | printf(" %dGB ", rimm_size / 1024); |
452 | |
453 | switch(s->sm_data[SPDMEM_RDR_MODULE_TYPE0x00]) { |
454 | case SPDMEM_RDR_TYPE_RIMM1: |
455 | printf("RIMM"); |
456 | break; |
457 | case SPDMEM_RDR_TYPE_SORIMM2: |
458 | printf("SO-RIMM"); |
459 | break; |
460 | case SPDMEM_RDR_TYPE_EMBED3: |
461 | printf("Embedded Rambus"); |
462 | break; |
463 | case SPDMEM_RDR_TYPE_RIMM324: |
464 | printf("RIMM32"); |
465 | break; |
466 | } |
467 | } |
468 | |
469 | void |
470 | spdmem_ddr_decode(struct spdmem_softc *sc, struct spdmem *s) |
471 | { |
472 | const char *type; |
473 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
474 | int i, num_banks, per_chip; |
475 | uint8_t config, rows, cols, cl; |
476 | |
477 | type = spdmem_basic_types[s->sm_type]; |
478 | |
479 | if (s->sm_data[SPDMEM_DDR_SUPERSET0x1d] == SPDMEM_SUPERSET_DDR_ESDRAM0x02) |
480 | type = spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM0x02]; |
481 | |
482 | num_banks = s->sm_data[SPDMEM_SDR_BANKS0x02]; |
483 | per_chip = s->sm_data[SPDMEM_SDR_BANKS_PER_CHIP0x0e]; |
484 | rows = s->sm_data[SPDMEM_SDR_ROWS0x00] & 0x0f; |
485 | cols = s->sm_data[SPDMEM_SDR_COLS0x01] & 0x0f; |
486 | dimm_size = (1 << (rows + cols - 17)) * num_banks * per_chip; |
487 | |
488 | if (dimm_size > 0) { |
489 | if (dimm_size < 1024) |
490 | printf(" %dMB", dimm_size); |
491 | else |
492 | printf(" %dGB", dimm_size / 1024); |
493 | } |
494 | |
495 | printf(" %s", type); |
496 | |
497 | if (s->sm_data[SPDMEM_DDR_MOD_ATTRIB0x12] & SPDMEM_DDR_ATTRIB_REG(1 << 1)) |
498 | printf(" registered"); |
499 | |
500 | if (s->sm_data[SPDMEM_FPM_CONFIG0x08] < 8) |
501 | printf(" %s", |
502 | spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG0x08]]); |
503 | |
504 | /* cycle_time is expressed in units of 0.01 ns */ |
505 | cycle_time = (s->sm_data[SPDMEM_DDR_CYCLE0x06] >> 4) * 100 + |
506 | (s->sm_data[SPDMEM_DDR_CYCLE0x06] & 0x0f) * 10; |
507 | |
508 | if (cycle_time != 0) { |
509 | /* |
510 | * cycle time is scaled by a factor of 100 to avoid using |
511 | * floating point. Calculate memory speed as the number |
512 | * of cycles per microsecond. |
513 | * DDR uses dual-pumped clock |
514 | */ |
515 | d_clk = 100 * 1000 * 2; |
516 | config = s->sm_data[SPDMEM_FPM_CONFIG0x08]; |
517 | bits = s->sm_data[SPDMEM_DDR_DATAWIDTH0x03] | |
518 | (s->sm_data[SPDMEM_DDR_DATAWIDTH0x03 + 1] << 8); |
519 | if (config == 1 || config == 2) |
520 | bits -= 8; |
521 | |
522 | d_clk /= cycle_time; |
523 | p_clk = d_clk * bits / 8; |
524 | if ((p_clk % 100) >= 50) |
525 | p_clk += 50; |
526 | p_clk -= p_clk % 100; |
527 | printf(" PC%d", p_clk); |
528 | } |
529 | |
530 | /* Print CAS latency */ |
531 | for (i = 6; i >= 0; i--) { |
532 | if (s->sm_data[SPDMEM_DDR_CAS0x0f] & (1 << i)) { |
533 | cl = ((i * 10) / 2) + 10; |
534 | printf("CL%d.%d", cl / 10, cl % 10); |
535 | break; |
536 | } |
537 | } |
538 | } |
539 | |
540 | void |
541 | spdmem_ddr2_decode(struct spdmem_softc *sc, struct spdmem *s) |
542 | { |
543 | const char *type; |
544 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
545 | int i, num_ranks, density; |
546 | uint8_t config; |
547 | |
548 | type = spdmem_basic_types[s->sm_type]; |
549 | |
550 | num_ranks = (s->sm_data[SPDMEM_DDR2_RANKS0x02] & 0x7) + 1; |
551 | density = (s->sm_data[SPDMEM_DDR2_RANK_DENSITY0x1c] & 0xf0) | |
552 | ((s->sm_data[SPDMEM_DDR2_RANK_DENSITY0x1c] & 0x0f) << 8); |
553 | dimm_size = num_ranks * density * 4; |
554 | |
555 | if (dimm_size > 0) { |
556 | if (dimm_size < 1024) |
557 | printf(" %dMB", dimm_size); |
558 | else |
559 | printf(" %dGB", dimm_size / 1024); |
560 | } |
561 | |
562 | printf(" %s", type); |
563 | |
564 | if (s->sm_data[SPDMEM_DDR2_DIMMTYPE0x11] & SPDMEM_DDR2_TYPE_REGMASK((1 << 4) | (1 << 0))) |
565 | printf(" registered"); |
566 | |
567 | if (s->sm_data[SPDMEM_FPM_CONFIG0x08] < 8) |
568 | printf(" %s", |
569 | spdmem_parity_types[s->sm_data[SPDMEM_FPM_CONFIG0x08]]); |
570 | |
571 | /* cycle_time is expressed in units of 0.01 ns */ |
572 | cycle_time = (s->sm_data[SPDMEM_DDR2_CYCLE0x06] >> 4) * 100 + |
573 | ddr2_cycle_tenths[(s->sm_data[SPDMEM_DDR2_CYCLE0x06] & 0x0f)]; |
574 | |
575 | if (cycle_time != 0) { |
576 | /* |
577 | * cycle time is scaled by a factor of 100 to avoid using |
578 | * floating point. Calculate memory speed as the number |
579 | * of cycles per microsecond. |
580 | * DDR2 uses quad-pumped clock |
581 | */ |
582 | d_clk = 100 * 1000 * 4; |
583 | config = s->sm_data[SPDMEM_FPM_CONFIG0x08]; |
584 | bits = s->sm_data[SPDMEM_DDR2_DATAWIDTH0x03]; |
585 | if ((config & 0x03) != 0) |
586 | bits -= 8; |
587 | d_clk /= cycle_time; |
588 | d_clk = (d_clk + 1) / 2; |
589 | p_clk = d_clk * bits / 8; |
590 | p_clk -= p_clk % 100; |
591 | printf(" PC2-%d", p_clk); |
592 | } |
593 | |
594 | /* Print CAS latency */ |
595 | for (i = 7; i >= 2; i--) { |
596 | if (s->sm_data[SPDMEM_DDR_CAS0x0f] & (1 << i)) { |
597 | printf("CL%d", i); |
598 | break; |
599 | } |
600 | } |
601 | |
602 | switch (s->sm_data[SPDMEM_DDR2_DIMMTYPE0x11]) { |
603 | case SPDMEM_DDR2_SODIMM(1 << 2): |
604 | printf(" SO-DIMM"); |
605 | break; |
606 | case SPDMEM_DDR2_MICRO_DIMM(1 << 3): |
607 | printf(" Micro-DIMM"); |
608 | break; |
609 | case SPDMEM_DDR2_MINI_RDIMM(1 << 4): |
610 | case SPDMEM_DDR2_MINI_UDIMM(1 << 5): |
611 | printf(" Mini-DIMM"); |
612 | break; |
613 | } |
614 | } |
615 | |
616 | void |
617 | spdmem_fbdimm_decode(struct spdmem_softc *sc, struct spdmem *s) |
618 | { |
619 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
620 | uint8_t rows, cols, dividend, divisor; |
621 | /* |
622 | * FB-DIMM is very much like DDR3 |
623 | */ |
624 | |
625 | cols = (s->sm_data[SPDMEM_FBDIMM_ADDR0x01] & SPDMEM_FBDIMM_ADDR_COL0x0c) >> |
626 | SPDMEM_FBDIMM_ADDR_COL_SHIFT2; |
627 | rows = (s->sm_data[SPDMEM_FBDIMM_ADDR0x01] & SPDMEM_FBDIMM_ADDR_ROW0xe0) >> |
628 | SPDMEM_FBDIMM_ADDR_ROW_SHIFT5; |
629 | dimm_size = rows + 12 + cols + 9 - 20 - 3; |
630 | |
631 | if (dimm_size < 1024) |
632 | printf(" %dMB", dimm_size); |
633 | else |
634 | printf(" %dGB", dimm_size / 1024); |
635 | |
636 | dividend = s->sm_data[SPDMEM_FBDIMM_MTB_DIVIDEND0x06]; |
637 | divisor = s->sm_data[SPDMEM_FBDIMM_MTB_DIVISOR0x07]; |
638 | |
639 | cycle_time = (1000 * dividend + (divisor / 2)) / divisor; |
640 | |
641 | if (cycle_time != 0) { |
642 | /* |
643 | * cycle time is scaled by a factor of 1000 to avoid using |
644 | * floating point. Calculate memory speed as the number |
645 | * of cycles per microsecond. |
646 | */ |
647 | d_clk = 1000 * 1000; |
648 | |
649 | /* DDR2 FB-DIMM uses a dual-pumped clock */ |
650 | d_clk *= 2; |
651 | bits = 1 << ((s->sm_data[SPDMEM_FBDIMM_RANKS0x04] & |
652 | SPDMEM_FBDIMM_RANKS_WIDTH0x07) + 2); |
653 | |
654 | p_clk = (d_clk * bits) / 8 / cycle_time; |
655 | p_clk -= p_clk % 100; |
656 | printf(" PC2-%d", p_clk); |
657 | } |
658 | } |
659 | |
660 | void |
661 | spdmem_ddr3_decode(struct spdmem_softc *sc, struct spdmem *s) |
662 | { |
663 | const char *type; |
664 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
665 | uint8_t mtype, chipsize, dividend, divisor; |
666 | uint8_t datawidth, chipwidth, physbanks; |
667 | |
668 | type = spdmem_basic_types[s->sm_type]; |
669 | |
670 | chipsize = s->sm_data[SPDMEM_DDR3_DENSITY0x01] & |
671 | SPDMEM_DDR3_DENSITY_CAPMASK0x0f; |
672 | datawidth = s->sm_data[SPDMEM_DDR3_DATAWIDTH0x05] & |
673 | SPDMEM_DDR3_DATAWIDTH_PRIMASK0x07; |
674 | chipwidth = s->sm_data[SPDMEM_DDR3_MOD_ORG0x04] & |
675 | SPDMEM_DDR3_MOD_ORG_CHIPWIDTH_MASK0x07; |
676 | physbanks = (s->sm_data[SPDMEM_DDR3_MOD_ORG0x04] >> |
677 | SPDMEM_DDR3_MOD_ORG_BANKS_SHIFT3) & SPDMEM_DDR3_MOD_ORG_BANKS_MASK0x07; |
678 | |
679 | dimm_size = (chipsize + 28 - 20) - 3 + (datawidth + 3) - |
680 | (chipwidth + 2); |
681 | dimm_size = (1 << dimm_size) * (physbanks + 1); |
682 | |
683 | if (dimm_size < 1024) |
684 | printf(" %dMB", dimm_size); |
685 | else |
686 | printf(" %dGB", dimm_size / 1024); |
687 | |
688 | printf(" %s", type); |
689 | |
690 | mtype = s->sm_data[SPDMEM_DDR3_MODTYPE0x00]; |
691 | if (mtype == SPDMEM_DDR3_RDIMM0x01 || mtype == SPDMEM_DDR3_MINI_RDIMM0x05) |
692 | printf(" registered"); |
693 | |
694 | if (s->sm_data[SPDMEM_DDR3_DATAWIDTH0x05] & SPDMEM_DDR3_DATAWIDTH_ECCMASK(1 << 3)) |
695 | printf(" ECC"); |
696 | |
697 | dividend = s->sm_data[SPDMEM_DDR3_MTB_DIVIDEND0x07]; |
698 | divisor = s->sm_data[SPDMEM_DDR3_MTB_DIVISOR0x08]; |
699 | cycle_time = (1000 * dividend + (divisor / 2)) / divisor; |
700 | cycle_time *= s->sm_data[SPDMEM_DDR3_TCKMIN0x09]; |
701 | |
702 | if (cycle_time != 0) { |
703 | /* |
704 | * cycle time is scaled by a factor of 1000 to avoid using |
705 | * floating point. Calculate memory speed as the number |
706 | * of cycles per microsecond. |
707 | * DDR3 uses a dual-pumped clock |
708 | */ |
709 | d_clk = 1000 * 1000; |
710 | d_clk *= 2; |
711 | bits = 1 << ((s->sm_data[SPDMEM_DDR3_DATAWIDTH0x05] & |
712 | SPDMEM_DDR3_DATAWIDTH_PRIMASK0x07) + 3); |
713 | /* |
714 | * Calculate p_clk first, since for DDR3 we need maximum |
715 | * significance. DDR3 rating is not rounded to a multiple |
716 | * of 100. This results in cycle_time of 1.5ns displayed |
717 | * as p_clk PC3-10666 (d_clk DDR3-1333) |
718 | */ |
719 | p_clk = (d_clk * bits) / 8 / cycle_time; |
720 | p_clk -= (p_clk % 100); |
721 | d_clk = ((d_clk + cycle_time / 2) ) / cycle_time; |
Value stored to 'd_clk' is never read | |
722 | printf(" PC3-%d", p_clk); |
723 | } |
724 | |
725 | switch (s->sm_data[SPDMEM_DDR3_MODTYPE0x00]) { |
726 | case SPDMEM_DDR3_SODIMM0x03: |
727 | printf(" SO-DIMM"); |
728 | break; |
729 | case SPDMEM_DDR3_MICRO_DIMM0x04: |
730 | printf(" Micro-DIMM"); |
731 | break; |
732 | case SPDMEM_DDR3_MINI_RDIMM0x05: |
733 | case SPDMEM_DDR3_MINI_UDIMM0x06: |
734 | printf(" Mini-DIMM"); |
735 | break; |
736 | } |
737 | |
738 | if (s->sm_data[SPDMEM_DDR3_THERMAL0x1d] & SPDMEM_DDR3_THERMAL_PRESENT(1 << 7)) |
739 | printf(" with thermal sensor"); |
740 | } |
741 | |
742 | void |
743 | spdmem_ddr4_decode(struct spdmem_softc *sc, struct spdmem *s) |
744 | { |
745 | static const int ddr4_chipsize[16] = { 256, 512, 1024, 2048, 4096, |
746 | 8 * 1024, 16 * 1024, 32 * 1024, 12 * 1024, 24 * 1024, |
747 | 3 * 1024, 6 * 1024, 18 * 1024 }; |
748 | const char *type; |
749 | int dimm_size, cycle_time, d_clk, p_clk, bits; |
750 | uint8_t mtype, chipsize, mtb; |
751 | int8_t ftb; |
752 | uint8_t datawidth, chipwidth, physbanks, diecount = 0; |
753 | |
754 | type = spdmem_basic_types[s->sm_type]; |
755 | |
756 | chipsize = s->sm_data[SPDMEM_DDR4_DENSITY0x01] & |
757 | SPDMEM_DDR4_DENSITY_CAPMASK0x0f; |
758 | datawidth = s->sm_data[SPDMEM_DDR4_DATAWIDTH0x0a] & |
759 | SPDMEM_DDR4_DATAWIDTH_PRIMASK0x07; |
760 | chipwidth = s->sm_data[SPDMEM_DDR4_MOD_ORG0x09] & |
761 | SPDMEM_DDR4_MOD_ORG_CHIPWIDTH_MASK0x07; |
762 | physbanks = (s->sm_data[SPDMEM_DDR4_MOD_ORG0x09] >> |
763 | SPDMEM_DDR4_MOD_ORG_BANKS_SHIFT3) & SPDMEM_DDR4_MOD_ORG_BANKS_MASK0x07; |
764 | |
765 | if ((s->sm_data[SPDMEM_DDR4_PACK_TYPE0x03] & |
766 | SPDMEM_DDR4_PACK_TYPE_SIG_LOAD_MASK0x03) == |
767 | SPDMEM_DDR4_PACK_TYPE_SIG_SINGLE_LOAD0x02) { |
768 | diecount = (s->sm_data[SPDMEM_DDR4_PACK_TYPE0x03] >> |
769 | SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_SHIFT4) & |
770 | SPDMEM_DDR4_PACK_TYPE_DIE_COUNT_MASK0x07; |
771 | } |
772 | |
773 | dimm_size = (datawidth + 3) - (chipwidth + 2); |
774 | dimm_size = (ddr4_chipsize[chipsize] / 8) * (1 << dimm_size) * |
775 | (physbanks + 1) * (diecount + 1); |
776 | |
777 | if (dimm_size < 1024) |
778 | printf(" %dMB", dimm_size); |
779 | else |
780 | printf(" %dGB", dimm_size / 1024); |
781 | |
782 | printf(" %s", type); |
783 | |
784 | mtype = s->sm_data[SPDMEM_DDR4_MODTYPE0x00]; |
785 | if (mtype & SPDMEM_DDR4_MODTYPE_HYBRID0x80) |
786 | printf(" hybrid"); |
787 | mtype &= SPDMEM_DDR4_MODTYPE_MASK0x0f; |
788 | if (mtype == SPDMEM_DDR4_RDIMM0x01 || mtype == SPDMEM_DDR4_MINI_RDIMM0x05 || |
789 | mtype == SPDMEM_DDR4_72B_SO_RDIMM0x08) |
790 | printf(" registered"); |
791 | if (mtype == SPDMEM_DDR4_72B_SO_UDIMM0x09 || |
792 | mtype == SPDMEM_DDR4_72B_SO_RDIMM0x08) |
793 | printf(" 72-bit"); |
794 | if (mtype == SPDMEM_DDR4_32B_SO_DIMM0x0d) |
795 | printf(" 32-bit"); |
796 | if (mtype == SPDMEM_DDR4_16B_SO_DIMM0x0c) |
797 | printf(" 16-bit"); |
798 | |
799 | if (s->sm_data[SPDMEM_DDR4_DATAWIDTH0x0a] & SPDMEM_DDR4_DATAWIDTH_ECCMASK(1 << 3)) |
800 | printf(" ECC"); |
801 | |
802 | mtb = s->sm_data[SPDMEM_DDR4_TCKMIN_MTB0x0f]; |
803 | /* SPDMEM_DDR4_TCKMIN_FTB (addr 125) is outside of s->sm_data */ |
804 | ftb = spdmem_read(sc, SPDMEM_DDR4_TCKMIN_FTB0x7d); |
805 | cycle_time = mtb * 125 + ftb; /* in ps */ |
806 | |
807 | if (cycle_time != 0) { |
808 | /* |
809 | * cycle time is scaled by a factor of 1000 to avoid using |
810 | * floating point. Calculate memory speed as the number |
811 | * of cycles per microsecond. |
812 | * DDR4 uses a dual-pumped clock |
813 | */ |
814 | d_clk = 1000 * 1000; |
815 | d_clk *= 2; |
816 | bits = 1 << ((s->sm_data[SPDMEM_DDR4_DATAWIDTH0x0a] & |
817 | SPDMEM_DDR4_DATAWIDTH_PRIMASK0x07) + 3); |
818 | |
819 | p_clk = (d_clk * bits) / 8 / cycle_time; |
820 | p_clk -= (p_clk % 100); |
821 | printf(" PC4-%d", p_clk); |
822 | } |
823 | |
824 | switch (s->sm_data[SPDMEM_DDR4_MODTYPE0x00] & SPDMEM_DDR4_MODTYPE_MASK0x0f) { |
825 | case SPDMEM_DDR4_SODIMM0x03: |
826 | case SPDMEM_DDR4_72B_SO_RDIMM0x08: |
827 | case SPDMEM_DDR4_72B_SO_UDIMM0x09: |
828 | case SPDMEM_DDR4_16B_SO_DIMM0x0c: |
829 | case SPDMEM_DDR4_32B_SO_DIMM0x0d: |
830 | printf(" SO-DIMM"); |
831 | break; |
832 | case SPDMEM_DDR4_LRDIMM0x04: |
833 | printf(" LR-DIMM"); |
834 | break; |
835 | case SPDMEM_DDR4_MINI_RDIMM0x05: |
836 | case SPDMEM_DDR4_MINI_UDIMM0x06: |
837 | printf(" Mini-DIMM"); |
838 | break; |
839 | case SPDMEM_DDR4_LP_DIMM0x07: |
840 | printf(" LP-DIMM"); |
841 | break; |
842 | case SPDMEM_DDR4_NON_DIMM0x0e: |
843 | printf(" non-DIMM solution"); |
844 | break; |
845 | } |
846 | |
847 | if (s->sm_data[SPDMEM_DDR4_THERMAL0x0b] & SPDMEM_DDR4_THERMAL_PRESENT(1 << 7)) |
848 | printf(" with thermal sensor"); |
849 | } |
850 | |
851 | int |
852 | spdmem_probe(struct spdmem_softc *sc) |
853 | { |
854 | uint8_t i, val, type; |
855 | int cksum = 0; |
856 | int spd_len, spd_crc_cover; |
857 | uint16_t crc_calc, crc_spd; |
858 | |
859 | type = spdmem_read(sc, 2); |
860 | /* For older memory types, validate the checksum over 1st 63 bytes */ |
861 | if (type <= SPDMEM_MEMTYPE_DDR2SDRAM0x08) { |
862 | for (i = 0; i < 63; i++) |
863 | cksum += spdmem_read(sc, i); |
864 | |
865 | val = spdmem_read(sc, 63); |
866 | |
867 | if (cksum == 0 || (cksum & 0xff) != val) { |
868 | return 0; |
869 | } else |
870 | return 1; |
871 | } |
872 | |
873 | /* For DDR3 and FBDIMM, verify the CRC */ |
874 | else if (type <= SPDMEM_MEMTYPE_DDR3SDRAM0x0b) { |
875 | spd_len = spdmem_read(sc, 0); |
876 | if (spd_len & SPDMEM_SPDCRC_1160x80) |
877 | spd_crc_cover = 116; |
878 | else |
879 | spd_crc_cover = 125; |
880 | switch (spd_len & SPDMEM_SPDLEN_MASK0x70) { |
881 | case SPDMEM_SPDLEN_1280x00: |
882 | spd_len = 128; |
883 | break; |
884 | case SPDMEM_SPDLEN_1760x10: |
885 | spd_len = 176; |
886 | break; |
887 | case SPDMEM_SPDLEN_2560x20: |
888 | spd_len = 256; |
889 | break; |
890 | default: |
891 | return 0; |
892 | } |
893 | calc_crc: |
894 | if (spd_crc_cover > spd_len) |
895 | return 0; |
896 | crc_calc = spdmem_crc16(sc, spd_crc_cover); |
897 | crc_spd = spdmem_read(sc, 127) << 8; |
898 | crc_spd |= spdmem_read(sc, 126); |
899 | if (crc_calc != crc_spd) { |
900 | return 0; |
901 | } |
902 | return 1; |
903 | } else if (type <= SPDMEM_MEMTYPE_LPDDR4SDRAM0x10) { |
904 | spd_len = spdmem_read(sc, 0); |
905 | spd_crc_cover = 125; |
906 | switch (spd_len & SPDMEM_DDR4_SPDLEN_MASK0x0f) { |
907 | case SPDMEM_DDR4_SPDLEN_1280x01: |
908 | spd_len = 128; |
909 | break; |
910 | case SPDMEM_DDR4_SPDLEN_2560x02: |
911 | spd_len = 256; |
912 | break; |
913 | case SPDMEM_DDR4_SPDLEN_3840x03: |
914 | spd_len = 384; |
915 | break; |
916 | case SPDMEM_DDR4_SPDLEN_5120x04: |
917 | spd_len = 512; |
918 | break; |
919 | default: |
920 | return 0; |
921 | } |
922 | goto calc_crc; |
923 | } |
924 | |
925 | return 0; |
926 | } |
927 | |
928 | void |
929 | spdmem_attach_common(struct spdmem_softc *sc) |
930 | { |
931 | struct spdmem *s = &(sc->sc_spd_data); |
932 | int i; |
933 | |
934 | /* All SPD have at least 64 bytes of data including checksum */ |
935 | for (i = 0; i < 64; i++) { |
936 | ((uint8_t *)s)[i] = spdmem_read(sc, i); |
937 | } |
938 | |
939 | /* |
940 | * Decode and print SPD contents |
941 | */ |
942 | if (s->sm_len < 4) { |
943 | if (s->sm_type == SPDMEM_MEMTYPE_DIRECT_RAMBUS0x01) |
944 | spdmem_rdr_decode(sc, s); |
945 | else |
946 | printf(" no decode method for Rambus memory"); |
947 | } else { |
948 | switch(s->sm_type) { |
949 | case SPDMEM_MEMTYPE_EDO0x02: |
950 | case SPDMEM_MEMTYPE_SDRAM0x04: |
951 | spdmem_sdram_decode(sc, s); |
952 | break; |
953 | case SPDMEM_MEMTYPE_DDRSDRAM0x07: |
954 | spdmem_ddr_decode(sc, s); |
955 | break; |
956 | case SPDMEM_MEMTYPE_DDR2SDRAM0x08: |
957 | spdmem_ddr2_decode(sc, s); |
958 | break; |
959 | case SPDMEM_MEMTYPE_FBDIMM0x09: |
960 | case SPDMEM_MEMTYPE_FBDIMM_PROBE0x0a: |
961 | spdmem_fbdimm_decode(sc, s); |
962 | break; |
963 | case SPDMEM_MEMTYPE_DDR3SDRAM0x0b: |
964 | spdmem_ddr3_decode(sc, s); |
965 | break; |
966 | case SPDMEM_MEMTYPE_DDR4SDRAM0x0c: |
967 | case SPDMEM_MEMTYPE_DDR4ESDRAM0x0e: |
968 | case SPDMEM_MEMTYPE_LPDDR3SDRAM0x0f: |
969 | case SPDMEM_MEMTYPE_LPDDR4SDRAM0x10: |
970 | spdmem_ddr4_decode(sc, s); |
971 | break; |
972 | case SPDMEM_MEMTYPE_NONE0xff: |
973 | printf(" no EEPROM found"); |
974 | break; |
975 | default: |
976 | if (s->sm_type <= SPDMEM_MEMTYPE_LPDDR5SDRAM0x13) |
977 | printf(" no decode method for %s memory", |
978 | spdmem_basic_types[s->sm_type]); |
979 | else |
980 | printf(" unknown memory type %d", s->sm_type); |
981 | break; |
982 | } |
983 | } |
984 | |
985 | printf("\n"); |
986 | } |