spdmem.c revision 1.1.2.2 1 1.1.2.2 uebayasi /* $NetBSD: spdmem.c,v 1.1.2.2 2010/04/30 14:43:23 uebayasi Exp $ */
2 1.1.2.2 uebayasi
3 1.1.2.2 uebayasi /*
4 1.1.2.2 uebayasi * Copyright (c) 2007 Nicolas Joly
5 1.1.2.2 uebayasi * Copyright (c) 2007 Paul Goyette
6 1.1.2.2 uebayasi * Copyright (c) 2007 Tobias Nygren
7 1.1.2.2 uebayasi * All rights reserved.
8 1.1.2.2 uebayasi *
9 1.1.2.2 uebayasi * Redistribution and use in source and binary forms, with or without
10 1.1.2.2 uebayasi * modification, are permitted provided that the following conditions
11 1.1.2.2 uebayasi * are met:
12 1.1.2.2 uebayasi * 1. Redistributions of source code must retain the above copyright
13 1.1.2.2 uebayasi * notice, this list of conditions and the following disclaimer.
14 1.1.2.2 uebayasi * 2. Redistributions in binary form must reproduce the above copyright
15 1.1.2.2 uebayasi * notice, this list of conditions and the following disclaimer in the
16 1.1.2.2 uebayasi * documentation and/or other materials provided with the distribution.
17 1.1.2.2 uebayasi * 3. The name of the author may not be used to endorse or promote products
18 1.1.2.2 uebayasi * derived from this software without specific prior written permission.
19 1.1.2.2 uebayasi *
20 1.1.2.2 uebayasi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
21 1.1.2.2 uebayasi * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.1.2.2 uebayasi * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.1.2.2 uebayasi * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.1.2.2 uebayasi * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.1.2.2 uebayasi * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.1.2.2 uebayasi * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.1.2.2 uebayasi * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1.2.2 uebayasi * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1.2.2 uebayasi * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.1.2.2 uebayasi * POSSIBILITY OF SUCH DAMAGE.
31 1.1.2.2 uebayasi */
32 1.1.2.2 uebayasi
33 1.1.2.2 uebayasi /*
34 1.1.2.2 uebayasi * Serial Presence Detect (SPD) memory identification
35 1.1.2.2 uebayasi */
36 1.1.2.2 uebayasi
37 1.1.2.2 uebayasi #include <sys/cdefs.h>
38 1.1.2.2 uebayasi __KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.1.2.2 2010/04/30 14:43:23 uebayasi Exp $");
39 1.1.2.2 uebayasi
40 1.1.2.2 uebayasi #include <sys/param.h>
41 1.1.2.2 uebayasi #include <sys/device.h>
42 1.1.2.2 uebayasi #include <sys/endian.h>
43 1.1.2.2 uebayasi #include <sys/sysctl.h>
44 1.1.2.2 uebayasi #include <machine/bswap.h>
45 1.1.2.2 uebayasi
46 1.1.2.2 uebayasi #include <dev/i2c/i2cvar.h>
47 1.1.2.2 uebayasi #include <dev/ic/spdmemreg.h>
48 1.1.2.2 uebayasi #include <dev/ic/spdmemvar.h>
49 1.1.2.2 uebayasi
50 1.1.2.2 uebayasi SYSCTL_SETUP_PROTO(sysctl_spdmem_setup);
51 1.1.2.2 uebayasi
52 1.1.2.2 uebayasi /* Routines for decoding spd data */
53 1.1.2.2 uebayasi static void decode_edofpm(const struct sysctlnode *, device_t, struct spdmem *);
54 1.1.2.2 uebayasi static void decode_rom(const struct sysctlnode *, device_t, struct spdmem *);
55 1.1.2.2 uebayasi static void decode_sdram(const struct sysctlnode *, device_t, struct spdmem *,
56 1.1.2.2 uebayasi int);
57 1.1.2.2 uebayasi static void decode_ddr(const struct sysctlnode *, device_t, struct spdmem *);
58 1.1.2.2 uebayasi static void decode_ddr2(const struct sysctlnode *, device_t, struct spdmem *);
59 1.1.2.2 uebayasi static void decode_ddr3(const struct sysctlnode *, device_t, struct spdmem *);
60 1.1.2.2 uebayasi static void decode_fbdimm(const struct sysctlnode *, device_t, struct spdmem *);
61 1.1.2.2 uebayasi
62 1.1.2.2 uebayasi static void decode_size_speed(const struct sysctlnode *, int, int, int, int,
63 1.1.2.2 uebayasi bool, const char *, int);
64 1.1.2.2 uebayasi static void decode_voltage_refresh(device_t, struct spdmem *);
65 1.1.2.2 uebayasi
66 1.1.2.2 uebayasi #define IS_RAMBUS_TYPE (s->sm_len < 4)
67 1.1.2.2 uebayasi
68 1.1.2.2 uebayasi static const char* spdmem_basic_types[] = {
69 1.1.2.2 uebayasi "unknown",
70 1.1.2.2 uebayasi "FPM",
71 1.1.2.2 uebayasi "EDO",
72 1.1.2.2 uebayasi "Pipelined Nibble",
73 1.1.2.2 uebayasi "SDRAM",
74 1.1.2.2 uebayasi "ROM",
75 1.1.2.2 uebayasi "DDR SGRAM",
76 1.1.2.2 uebayasi "DDR SDRAM",
77 1.1.2.2 uebayasi "DDR2 SDRAM",
78 1.1.2.2 uebayasi "DDR2 SDRAM FB",
79 1.1.2.2 uebayasi "DDR2 SDRAM FB Probe",
80 1.1.2.2 uebayasi "DDR3 SDRAM"
81 1.1.2.2 uebayasi };
82 1.1.2.2 uebayasi
83 1.1.2.2 uebayasi static const char* spdmem_superset_types[] = {
84 1.1.2.2 uebayasi "unknown",
85 1.1.2.2 uebayasi "ESDRAM",
86 1.1.2.2 uebayasi "DDR ESDRAM",
87 1.1.2.2 uebayasi "PEM EDO",
88 1.1.2.2 uebayasi "PEM SDRAM"
89 1.1.2.2 uebayasi };
90 1.1.2.2 uebayasi
91 1.1.2.2 uebayasi static const char* spdmem_voltage_types[] = {
92 1.1.2.2 uebayasi "TTL (5V tolerant)",
93 1.1.2.2 uebayasi "LvTTL (not 5V tolerant)",
94 1.1.2.2 uebayasi "HSTL 1.5V",
95 1.1.2.2 uebayasi "SSTL 3.3V",
96 1.1.2.2 uebayasi "SSTL 2.5V",
97 1.1.2.2 uebayasi "SSTL 1.8V"
98 1.1.2.2 uebayasi };
99 1.1.2.2 uebayasi
100 1.1.2.2 uebayasi static const char* spdmem_refresh_types[] = {
101 1.1.2.2 uebayasi "15.625us",
102 1.1.2.2 uebayasi "3.9us",
103 1.1.2.2 uebayasi "7.8us",
104 1.1.2.2 uebayasi "31.3us",
105 1.1.2.2 uebayasi "62.5us",
106 1.1.2.2 uebayasi "125us"
107 1.1.2.2 uebayasi };
108 1.1.2.2 uebayasi
109 1.1.2.2 uebayasi static const char* spdmem_parity_types[] = {
110 1.1.2.2 uebayasi "no parity or ECC",
111 1.1.2.2 uebayasi "data parity",
112 1.1.2.2 uebayasi "data ECC",
113 1.1.2.2 uebayasi "data parity and ECC",
114 1.1.2.2 uebayasi "cmd/addr parity",
115 1.1.2.2 uebayasi "cmd/addr/data parity",
116 1.1.2.2 uebayasi "cmd/addr parity, data ECC",
117 1.1.2.2 uebayasi "cmd/addr/data parity, data ECC"
118 1.1.2.2 uebayasi };
119 1.1.2.2 uebayasi
120 1.1.2.2 uebayasi /* Cycle time fractional values (units of .001 ns) for DDR2 SDRAM */
121 1.1.2.2 uebayasi static const uint16_t spdmem_cycle_frac[] = {
122 1.1.2.2 uebayasi 0, 100, 200, 300, 400, 500, 600, 700, 800, 900,
123 1.1.2.2 uebayasi 250, 333, 667, 750, 999, 999
124 1.1.2.2 uebayasi };
125 1.1.2.2 uebayasi
126 1.1.2.2 uebayasi /* Format string for timing info */
127 1.1.2.2 uebayasi static const char* latency="tAA-tRCD-tRP-tRAS: %d-%d-%d-%d\n";
128 1.1.2.2 uebayasi
129 1.1.2.2 uebayasi /* sysctl stuff */
130 1.1.2.2 uebayasi static int hw_node = CTL_EOL;
131 1.1.2.2 uebayasi
132 1.1.2.2 uebayasi /* CRC functions used for certain memory types */
133 1.1.2.2 uebayasi
134 1.1.2.2 uebayasi static uint16_t spdcrc16 (struct spdmem_softc *sc, int count)
135 1.1.2.2 uebayasi {
136 1.1.2.2 uebayasi uint16_t crc;
137 1.1.2.2 uebayasi int i, j;
138 1.1.2.2 uebayasi uint8_t val;
139 1.1.2.2 uebayasi crc = 0;
140 1.1.2.2 uebayasi for (j = 0; j <= count; j++) {
141 1.1.2.2 uebayasi val = (sc->sc_read)(sc, j);
142 1.1.2.2 uebayasi crc = crc ^ val << 8;
143 1.1.2.2 uebayasi for (i = 0; i < 8; ++i)
144 1.1.2.2 uebayasi if (crc & 0x8000)
145 1.1.2.2 uebayasi crc = crc << 1 ^ 0x1021;
146 1.1.2.2 uebayasi else
147 1.1.2.2 uebayasi crc = crc << 1;
148 1.1.2.2 uebayasi }
149 1.1.2.2 uebayasi return (crc & 0xFFFF);
150 1.1.2.2 uebayasi }
151 1.1.2.2 uebayasi
152 1.1.2.2 uebayasi int
153 1.1.2.2 uebayasi spdmem_common_probe(struct spdmem_softc *sc)
154 1.1.2.2 uebayasi {
155 1.1.2.2 uebayasi int cksum = 0;
156 1.1.2.2 uebayasi uint8_t i, val, spd_type;
157 1.1.2.2 uebayasi int spd_len, spd_crc_cover;
158 1.1.2.2 uebayasi uint16_t crc_calc, crc_spd;
159 1.1.2.2 uebayasi
160 1.1.2.2 uebayasi spd_type = (sc->sc_read)(sc, 2);
161 1.1.2.2 uebayasi
162 1.1.2.2 uebayasi /* For older memory types, validate the checksum over 1st 63 bytes */
163 1.1.2.2 uebayasi if (spd_type <= SPDMEM_MEMTYPE_DDR2SDRAM) {
164 1.1.2.2 uebayasi for (i = 0; i < 63; i++)
165 1.1.2.2 uebayasi cksum += (sc->sc_read)(sc, i);
166 1.1.2.2 uebayasi
167 1.1.2.2 uebayasi val = (sc->sc_read)(sc, 63);
168 1.1.2.2 uebayasi
169 1.1.2.2 uebayasi if (cksum == 0 || (cksum & 0xff) != val) {
170 1.1.2.2 uebayasi aprint_debug("spd checksum failed, calc = 0x%02x, "
171 1.1.2.2 uebayasi "spd = 0x%02x\n", cksum, val);
172 1.1.2.2 uebayasi return 0;
173 1.1.2.2 uebayasi } else
174 1.1.2.2 uebayasi return 1;
175 1.1.2.2 uebayasi }
176 1.1.2.2 uebayasi
177 1.1.2.2 uebayasi /* For DDR3 and FBDIMM, verify the CRC */
178 1.1.2.2 uebayasi else if (spd_type <= SPDMEM_MEMTYPE_DDR3SDRAM) {
179 1.1.2.2 uebayasi spd_len = (sc->sc_read)(sc, 0);
180 1.1.2.2 uebayasi if (spd_len && SPDMEM_SPDCRC_116)
181 1.1.2.2 uebayasi spd_crc_cover = 116;
182 1.1.2.2 uebayasi else
183 1.1.2.2 uebayasi spd_crc_cover = 125;
184 1.1.2.2 uebayasi switch (spd_len & SPDMEM_SPDLEN_MASK) {
185 1.1.2.2 uebayasi case SPDMEM_SPDLEN_128:
186 1.1.2.2 uebayasi spd_len = 128;
187 1.1.2.2 uebayasi break;
188 1.1.2.2 uebayasi case SPDMEM_SPDLEN_176:
189 1.1.2.2 uebayasi spd_len = 176;
190 1.1.2.2 uebayasi break;
191 1.1.2.2 uebayasi case SPDMEM_SPDLEN_256:
192 1.1.2.2 uebayasi spd_len = 256;
193 1.1.2.2 uebayasi break;
194 1.1.2.2 uebayasi default:
195 1.1.2.2 uebayasi return 0;
196 1.1.2.2 uebayasi }
197 1.1.2.2 uebayasi if (spd_crc_cover > spd_len)
198 1.1.2.2 uebayasi return 0;
199 1.1.2.2 uebayasi crc_calc = spdcrc16(sc, spd_crc_cover);
200 1.1.2.2 uebayasi crc_spd = (sc->sc_read)(sc, 127) << 8;
201 1.1.2.2 uebayasi crc_spd |= (sc->sc_read)(sc, 126);
202 1.1.2.2 uebayasi if (crc_calc != crc_spd) {
203 1.1.2.2 uebayasi aprint_debug("crc16 failed, covers %d bytes, "
204 1.1.2.2 uebayasi "calc = 0x%04x, spd = 0x%04x\n",
205 1.1.2.2 uebayasi spd_crc_cover, crc_calc, crc_spd);
206 1.1.2.2 uebayasi return 0;
207 1.1.2.2 uebayasi }
208 1.1.2.2 uebayasi return 1;
209 1.1.2.2 uebayasi }
210 1.1.2.2 uebayasi
211 1.1.2.2 uebayasi /* For unrecognized memory types, don't match at all */
212 1.1.2.2 uebayasi return 0;
213 1.1.2.2 uebayasi }
214 1.1.2.2 uebayasi
215 1.1.2.2 uebayasi void
216 1.1.2.2 uebayasi spdmem_common_attach(struct spdmem_softc *sc, device_t self)
217 1.1.2.2 uebayasi {
218 1.1.2.2 uebayasi struct spdmem *s = &(sc->sc_spd_data);
219 1.1.2.2 uebayasi const char *type;
220 1.1.2.2 uebayasi const char *rambus_rev = "Reserved";
221 1.1.2.2 uebayasi int dimm_size;
222 1.1.2.2 uebayasi int i;
223 1.1.2.2 uebayasi unsigned int spd_len, spd_size;
224 1.1.2.2 uebayasi const struct sysctlnode *node = NULL;
225 1.1.2.2 uebayasi
226 1.1.2.2 uebayasi /*
227 1.1.2.2 uebayasi * FBDIMM and DDR3 (and probably all newer) have a different
228 1.1.2.2 uebayasi * encoding of the SPD EEPROM used/total sizes
229 1.1.2.2 uebayasi */
230 1.1.2.2 uebayasi s->sm_len = (sc->sc_read)(sc, 0);
231 1.1.2.2 uebayasi s->sm_size = (sc->sc_read)(sc, 1);
232 1.1.2.2 uebayasi s->sm_type = (sc->sc_read)(sc, 2);
233 1.1.2.2 uebayasi
234 1.1.2.2 uebayasi if (s->sm_type >= SPDMEM_MEMTYPE_FBDIMM) {
235 1.1.2.2 uebayasi spd_size = 64 << (s->sm_len & SPDMEM_SPDSIZE_MASK);
236 1.1.2.2 uebayasi switch (s->sm_len & SPDMEM_SPDLEN_MASK) {
237 1.1.2.2 uebayasi case SPDMEM_SPDLEN_128:
238 1.1.2.2 uebayasi spd_len = 128;
239 1.1.2.2 uebayasi break;
240 1.1.2.2 uebayasi case SPDMEM_SPDLEN_176:
241 1.1.2.2 uebayasi spd_len = 176;
242 1.1.2.2 uebayasi break;
243 1.1.2.2 uebayasi case SPDMEM_SPDLEN_256:
244 1.1.2.2 uebayasi spd_len = 256;
245 1.1.2.2 uebayasi break;
246 1.1.2.2 uebayasi default:
247 1.1.2.2 uebayasi spd_len = 64;
248 1.1.2.2 uebayasi break;
249 1.1.2.2 uebayasi }
250 1.1.2.2 uebayasi } else {
251 1.1.2.2 uebayasi spd_size = 1 << s->sm_size;
252 1.1.2.2 uebayasi spd_len = s->sm_len;
253 1.1.2.2 uebayasi if (spd_len < 64)
254 1.1.2.2 uebayasi spd_len = 64;
255 1.1.2.2 uebayasi }
256 1.1.2.2 uebayasi if (spd_len > spd_size)
257 1.1.2.2 uebayasi spd_len = spd_size;
258 1.1.2.2 uebayasi if (spd_len > sizeof(struct spdmem))
259 1.1.2.2 uebayasi spd_len = sizeof(struct spdmem);
260 1.1.2.2 uebayasi for (i = 3; i < spd_len; i++)
261 1.1.2.2 uebayasi ((uint8_t *)s)[i] = (sc->sc_read)(sc, i);
262 1.1.2.2 uebayasi
263 1.1.2.2 uebayasi #ifdef DEBUG
264 1.1.2.2 uebayasi for (i = 0; i < spd_len; i += 16) {
265 1.1.2.2 uebayasi int j, k;
266 1.1.2.2 uebayasi aprint_debug("\n");
267 1.1.2.2 uebayasi aprint_debug_dev(self, "0x%02x:", i);
268 1.1.2.2 uebayasi k = (spd_len > i + 16) ? spd_len : i + 16;
269 1.1.2.2 uebayasi for (j = i; j < k; j++)
270 1.1.2.2 uebayasi aprint_debug(" %02x", ((uint8_t *)s)[j]);
271 1.1.2.2 uebayasi }
272 1.1.2.2 uebayasi aprint_debug("\n");
273 1.1.2.2 uebayasi aprint_debug_dev(self, "");
274 1.1.2.2 uebayasi #endif
275 1.1.2.2 uebayasi
276 1.1.2.2 uebayasi /*
277 1.1.2.2 uebayasi * Setup our sysctl subtree, hw.spdmemN
278 1.1.2.2 uebayasi */
279 1.1.2.2 uebayasi if (hw_node != CTL_EOL)
280 1.1.2.2 uebayasi sysctl_createv(NULL, 0, NULL, &node,
281 1.1.2.2 uebayasi 0, CTLTYPE_NODE,
282 1.1.2.2 uebayasi device_xname(self), NULL, NULL, 0, NULL, 0,
283 1.1.2.2 uebayasi CTL_HW, CTL_CREATE, CTL_EOL);
284 1.1.2.2 uebayasi if (node != NULL && spd_len != 0)
285 1.1.2.2 uebayasi sysctl_createv(NULL, 0, NULL, NULL,
286 1.1.2.2 uebayasi 0,
287 1.1.2.2 uebayasi CTLTYPE_STRUCT, "spd_data",
288 1.1.2.2 uebayasi SYSCTL_DESCR("raw spd data"), NULL,
289 1.1.2.2 uebayasi 0, s, spd_len,
290 1.1.2.2 uebayasi CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
291 1.1.2.2 uebayasi
292 1.1.2.2 uebayasi /*
293 1.1.2.2 uebayasi * Decode and print key SPD contents
294 1.1.2.2 uebayasi */
295 1.1.2.2 uebayasi if (IS_RAMBUS_TYPE) {
296 1.1.2.2 uebayasi if (s->sm_type == SPDMEM_MEMTYPE_RAMBUS)
297 1.1.2.2 uebayasi type = "Rambus";
298 1.1.2.2 uebayasi else if (s->sm_type == SPDMEM_MEMTYPE_DIRECTRAMBUS)
299 1.1.2.2 uebayasi type = "Direct Rambus";
300 1.1.2.2 uebayasi else
301 1.1.2.2 uebayasi type = "Rambus (unknown)";
302 1.1.2.2 uebayasi
303 1.1.2.2 uebayasi switch (s->sm_len) {
304 1.1.2.2 uebayasi case 0:
305 1.1.2.2 uebayasi rambus_rev = "Invalid";
306 1.1.2.2 uebayasi break;
307 1.1.2.2 uebayasi case 1:
308 1.1.2.2 uebayasi rambus_rev = "0.7";
309 1.1.2.2 uebayasi break;
310 1.1.2.2 uebayasi case 2:
311 1.1.2.2 uebayasi rambus_rev = "1.0";
312 1.1.2.2 uebayasi break;
313 1.1.2.2 uebayasi default:
314 1.1.2.2 uebayasi rambus_rev = "Reserved";
315 1.1.2.2 uebayasi break;
316 1.1.2.2 uebayasi }
317 1.1.2.2 uebayasi } else {
318 1.1.2.2 uebayasi if (s->sm_type < __arraycount(spdmem_basic_types))
319 1.1.2.2 uebayasi type = spdmem_basic_types[s->sm_type];
320 1.1.2.2 uebayasi else
321 1.1.2.2 uebayasi type = "unknown memory type";
322 1.1.2.2 uebayasi
323 1.1.2.2 uebayasi if (s->sm_type == SPDMEM_MEMTYPE_EDO &&
324 1.1.2.2 uebayasi s->sm_fpm.fpm_superset == SPDMEM_SUPERSET_EDO_PEM)
325 1.1.2.2 uebayasi type = spdmem_superset_types[SPDMEM_SUPERSET_EDO_PEM];
326 1.1.2.2 uebayasi if (s->sm_type == SPDMEM_MEMTYPE_SDRAM &&
327 1.1.2.2 uebayasi s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_SDRAM_PEM)
328 1.1.2.2 uebayasi type = spdmem_superset_types[SPDMEM_SUPERSET_SDRAM_PEM];
329 1.1.2.2 uebayasi if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM &&
330 1.1.2.2 uebayasi s->sm_ddr.ddr_superset == SPDMEM_SUPERSET_DDR_ESDRAM)
331 1.1.2.2 uebayasi type =
332 1.1.2.2 uebayasi spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM];
333 1.1.2.2 uebayasi if (s->sm_type == SPDMEM_MEMTYPE_SDRAM &&
334 1.1.2.2 uebayasi s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_ESDRAM) {
335 1.1.2.2 uebayasi type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM];
336 1.1.2.2 uebayasi }
337 1.1.2.2 uebayasi }
338 1.1.2.2 uebayasi
339 1.1.2.2 uebayasi aprint_naive("\n");
340 1.1.2.2 uebayasi aprint_normal("\n");
341 1.1.2.2 uebayasi aprint_normal_dev(self, "%s", type);
342 1.1.2.2 uebayasi strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN);
343 1.1.2.2 uebayasi if (node != NULL)
344 1.1.2.2 uebayasi sysctl_createv(NULL, 0, NULL, NULL,
345 1.1.2.2 uebayasi 0,
346 1.1.2.2 uebayasi CTLTYPE_STRING, "mem_type",
347 1.1.2.2 uebayasi SYSCTL_DESCR("memory module type"), NULL,
348 1.1.2.2 uebayasi 0, sc->sc_type, 0,
349 1.1.2.2 uebayasi CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
350 1.1.2.2 uebayasi
351 1.1.2.2 uebayasi if (IS_RAMBUS_TYPE) {
352 1.1.2.2 uebayasi aprint_normal(", SPD Revision %s", rambus_rev);
353 1.1.2.2 uebayasi dimm_size = 1 << (s->sm_rdr.rdr_rows + s->sm_rdr.rdr_cols - 13);
354 1.1.2.2 uebayasi if (dimm_size >= 1024)
355 1.1.2.2 uebayasi aprint_normal(", %dGB\n", dimm_size / 1024);
356 1.1.2.2 uebayasi else
357 1.1.2.2 uebayasi aprint_normal(", %dMB\n", dimm_size);
358 1.1.2.2 uebayasi
359 1.1.2.2 uebayasi /* No further decode for RAMBUS memory */
360 1.1.2.2 uebayasi return;
361 1.1.2.2 uebayasi }
362 1.1.2.2 uebayasi switch (s->sm_type) {
363 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_EDO:
364 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_FPM:
365 1.1.2.2 uebayasi decode_edofpm(node, self, s);
366 1.1.2.2 uebayasi break;
367 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_ROM:
368 1.1.2.2 uebayasi decode_rom(node, self, s);
369 1.1.2.2 uebayasi break;
370 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_SDRAM:
371 1.1.2.2 uebayasi decode_sdram(node, self, s, spd_len);
372 1.1.2.2 uebayasi break;
373 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_DDRSDRAM:
374 1.1.2.2 uebayasi decode_ddr(node, self, s);
375 1.1.2.2 uebayasi break;
376 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_DDR2SDRAM:
377 1.1.2.2 uebayasi decode_ddr2(node, self, s);
378 1.1.2.2 uebayasi break;
379 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_DDR3SDRAM:
380 1.1.2.2 uebayasi decode_ddr3(node, self, s);
381 1.1.2.2 uebayasi break;
382 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_FBDIMM:
383 1.1.2.2 uebayasi case SPDMEM_MEMTYPE_FBDIMM_PROBE:
384 1.1.2.2 uebayasi decode_fbdimm(node, self, s);
385 1.1.2.2 uebayasi break;
386 1.1.2.2 uebayasi }
387 1.1.2.2 uebayasi }
388 1.1.2.2 uebayasi
389 1.1.2.2 uebayasi SYSCTL_SETUP(sysctl_spdmem_setup, "sysctl hw.spdmem subtree setup")
390 1.1.2.2 uebayasi {
391 1.1.2.2 uebayasi const struct sysctlnode *node;
392 1.1.2.2 uebayasi
393 1.1.2.2 uebayasi if (sysctl_createv(clog, 0, NULL, &node,
394 1.1.2.2 uebayasi CTLFLAG_PERMANENT,
395 1.1.2.2 uebayasi CTLTYPE_NODE, "hw", NULL,
396 1.1.2.2 uebayasi NULL, 0, NULL, 0,
397 1.1.2.2 uebayasi CTL_HW, CTL_EOL) != 0)
398 1.1.2.2 uebayasi return;
399 1.1.2.2 uebayasi
400 1.1.2.2 uebayasi hw_node = node->sysctl_num;
401 1.1.2.2 uebayasi }
402 1.1.2.2 uebayasi
403 1.1.2.2 uebayasi static void
404 1.1.2.2 uebayasi decode_size_speed(const struct sysctlnode *node, int dimm_size, int cycle_time,
405 1.1.2.2 uebayasi int d_clk, int bits, bool round, const char *ddr_type_string,
406 1.1.2.2 uebayasi int speed)
407 1.1.2.2 uebayasi {
408 1.1.2.2 uebayasi int p_clk;
409 1.1.2.2 uebayasi
410 1.1.2.2 uebayasi if (dimm_size < 1024)
411 1.1.2.2 uebayasi aprint_normal("%dMB", dimm_size);
412 1.1.2.2 uebayasi else
413 1.1.2.2 uebayasi aprint_normal("%dGB", dimm_size / 1024);
414 1.1.2.2 uebayasi if (node != NULL)
415 1.1.2.2 uebayasi sysctl_createv(NULL, 0, NULL, NULL,
416 1.1.2.2 uebayasi CTLFLAG_IMMEDIATE,
417 1.1.2.2 uebayasi CTLTYPE_INT, "size",
418 1.1.2.2 uebayasi SYSCTL_DESCR("module size in MB"), NULL,
419 1.1.2.2 uebayasi dimm_size, NULL, 0,
420 1.1.2.2 uebayasi CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
421 1.1.2.2 uebayasi
422 1.1.2.2 uebayasi if (cycle_time == 0) {
423 1.1.2.2 uebayasi aprint_normal("\n");
424 1.1.2.2 uebayasi return;
425 1.1.2.2 uebayasi }
426 1.1.2.2 uebayasi
427 1.1.2.2 uebayasi /*
428 1.1.2.2 uebayasi * Calculate p_clk first, since for DDR3 we need maximum significance.
429 1.1.2.2 uebayasi * DDR3 rating is not rounded to a multiple of 100. This results in
430 1.1.2.2 uebayasi * cycle_time of 1.5ns displayed as PC3-10666.
431 1.1.2.2 uebayasi *
432 1.1.2.2 uebayasi * For SDRAM, the speed is provided by the caller so we use it.
433 1.1.2.2 uebayasi */
434 1.1.2.2 uebayasi d_clk *= 1000 * 1000;
435 1.1.2.2 uebayasi if (speed)
436 1.1.2.2 uebayasi p_clk = speed;
437 1.1.2.2 uebayasi else
438 1.1.2.2 uebayasi p_clk = (d_clk * bits) / 8 / cycle_time;
439 1.1.2.2 uebayasi d_clk = ((d_clk + cycle_time / 2) ) / cycle_time;
440 1.1.2.2 uebayasi if (round) {
441 1.1.2.2 uebayasi if ((p_clk % 100) >= 50)
442 1.1.2.2 uebayasi p_clk += 50;
443 1.1.2.2 uebayasi p_clk -= p_clk % 100;
444 1.1.2.2 uebayasi }
445 1.1.2.2 uebayasi aprint_normal(", %dMHz (%s-%d)\n",
446 1.1.2.2 uebayasi d_clk, ddr_type_string, p_clk);
447 1.1.2.2 uebayasi if (node != NULL)
448 1.1.2.2 uebayasi sysctl_createv(NULL, 0, NULL, NULL,
449 1.1.2.2 uebayasi CTLFLAG_IMMEDIATE,
450 1.1.2.2 uebayasi CTLTYPE_INT, "speed",
451 1.1.2.2 uebayasi SYSCTL_DESCR("memory speed in MHz"),
452 1.1.2.2 uebayasi NULL, d_clk, NULL, 0,
453 1.1.2.2 uebayasi CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL);
454 1.1.2.2 uebayasi }
455 1.1.2.2 uebayasi
456 1.1.2.2 uebayasi static void
457 1.1.2.2 uebayasi decode_voltage_refresh(device_t self, struct spdmem *s)
458 1.1.2.2 uebayasi {
459 1.1.2.2 uebayasi const char *voltage, *refresh;
460 1.1.2.2 uebayasi
461 1.1.2.2 uebayasi if (s->sm_voltage < __arraycount(spdmem_voltage_types))
462 1.1.2.2 uebayasi voltage = spdmem_voltage_types[s->sm_voltage];
463 1.1.2.2 uebayasi else
464 1.1.2.2 uebayasi voltage = "unknown";
465 1.1.2.2 uebayasi
466 1.1.2.2 uebayasi if (s->sm_refresh < __arraycount(spdmem_refresh_types))
467 1.1.2.2 uebayasi refresh = spdmem_refresh_types[s->sm_refresh];
468 1.1.2.2 uebayasi else
469 1.1.2.2 uebayasi refresh = "unknown";
470 1.1.2.2 uebayasi
471 1.1.2.2 uebayasi aprint_verbose_dev(self, "voltage %s, refresh time %s%s\n",
472 1.1.2.2 uebayasi voltage, refresh,
473 1.1.2.2 uebayasi s->sm_selfrefresh?" (self-refreshing)":"");
474 1.1.2.2 uebayasi }
475 1.1.2.2 uebayasi
476 1.1.2.2 uebayasi static void
477 1.1.2.2 uebayasi decode_edofpm(const struct sysctlnode *node, device_t self, struct spdmem *s) {
478 1.1.2.2 uebayasi aprint_normal("\n");
479 1.1.2.2 uebayasi aprint_verbose_dev(self,
480 1.1.2.2 uebayasi "%d rows, %d cols, %d banks, %dns tRAC, %dns tCAC\n",
481 1.1.2.2 uebayasi s->sm_fpm.fpm_rows, s->sm_fpm.fpm_cols, s->sm_fpm.fpm_banks,
482 1.1.2.2 uebayasi s->sm_fpm.fpm_tRAC, s->sm_fpm.fpm_tCAC);
483 1.1.2.2 uebayasi }
484 1.1.2.2 uebayasi
485 1.1.2.2 uebayasi static void
486 1.1.2.2 uebayasi decode_rom(const struct sysctlnode *node, device_t self, struct spdmem *s) {
487 1.1.2.2 uebayasi aprint_normal("\n");
488 1.1.2.2 uebayasi aprint_verbose_dev(self, "%d rows, %d cols, %d banks\n",
489 1.1.2.2 uebayasi s->sm_rom.rom_rows, s->sm_rom.rom_cols, s->sm_rom.rom_banks);
490 1.1.2.2 uebayasi }
491 1.1.2.2 uebayasi
492 1.1.2.2 uebayasi static void
493 1.1.2.2 uebayasi decode_sdram(const struct sysctlnode *node, device_t self, struct spdmem *s,
494 1.1.2.2 uebayasi int spd_len) {
495 1.1.2.2 uebayasi int dimm_size, cycle_time, bits, tAA, i, speed, freq;
496 1.1.2.2 uebayasi
497 1.1.2.2 uebayasi aprint_normal("%s, %s, ",
498 1.1.2.2 uebayasi (s->sm_sdr.sdr_mod_attrs & SPDMEM_SDR_MASK_REG)?
499 1.1.2.2 uebayasi " (registered)":"",
500 1.1.2.2 uebayasi (s->sm_config < __arraycount(spdmem_parity_types))?
501 1.1.2.2 uebayasi spdmem_parity_types[s->sm_config]:"invalid parity");
502 1.1.2.2 uebayasi
503 1.1.2.2 uebayasi dimm_size = 1 << (s->sm_sdr.sdr_rows + s->sm_sdr.sdr_cols - 17);
504 1.1.2.2 uebayasi dimm_size *= s->sm_sdr.sdr_banks * s->sm_sdr.sdr_banks_per_chip;
505 1.1.2.2 uebayasi
506 1.1.2.2 uebayasi cycle_time = s->sm_sdr.sdr_cycle_whole * 1000 +
507 1.1.2.2 uebayasi s->sm_sdr.sdr_cycle_tenths * 100;
508 1.1.2.2 uebayasi bits = le16toh(s->sm_sdr.sdr_datawidth);
509 1.1.2.2 uebayasi if (s->sm_config == 1 || s->sm_config == 2)
510 1.1.2.2 uebayasi bits -= 8;
511 1.1.2.2 uebayasi
512 1.1.2.2 uebayasi /* Calculate speed here - from OpenBSD */
513 1.1.2.2 uebayasi if (spd_len >= 128)
514 1.1.2.2 uebayasi freq = ((uint8_t *)s)[126];
515 1.1.2.2 uebayasi else
516 1.1.2.2 uebayasi freq = 0;
517 1.1.2.2 uebayasi switch (freq) {
518 1.1.2.2 uebayasi /*
519 1.1.2.2 uebayasi * Must check cycle time since some PC-133 DIMMs
520 1.1.2.2 uebayasi * actually report PC-100
521 1.1.2.2 uebayasi */
522 1.1.2.2 uebayasi case 100:
523 1.1.2.2 uebayasi case 133:
524 1.1.2.2 uebayasi if (cycle_time < 8000)
525 1.1.2.2 uebayasi speed = 133;
526 1.1.2.2 uebayasi else
527 1.1.2.2 uebayasi speed = 100;
528 1.1.2.2 uebayasi break;
529 1.1.2.2 uebayasi case 0x66: /* Legacy DIMMs use _hex_ 66! */
530 1.1.2.2 uebayasi default:
531 1.1.2.2 uebayasi speed = 66;
532 1.1.2.2 uebayasi }
533 1.1.2.2 uebayasi decode_size_speed(node, dimm_size, cycle_time, 1, bits, FALSE, "PC",
534 1.1.2.2 uebayasi speed);
535 1.1.2.2 uebayasi
536 1.1.2.2 uebayasi aprint_verbose_dev(self,
537 1.1.2.2 uebayasi "%d rows, %d cols, %d banks, %d banks/chip, %d.%dns cycle time\n",
538 1.1.2.2 uebayasi s->sm_sdr.sdr_rows, s->sm_sdr.sdr_cols, s->sm_sdr.sdr_banks,
539 1.1.2.2 uebayasi s->sm_sdr.sdr_banks_per_chip, cycle_time/1000,
540 1.1.2.2 uebayasi (cycle_time % 1000) / 100);
541 1.1.2.2 uebayasi
542 1.1.2.2 uebayasi tAA = 0;
543 1.1.2.2 uebayasi for (i = 0; i < 8; i++)
544 1.1.2.2 uebayasi if (s->sm_sdr.sdr_tCAS & (1 << i))
545 1.1.2.2 uebayasi tAA = i;
546 1.1.2.2 uebayasi tAA++;
547 1.1.2.2 uebayasi aprint_verbose_dev(self, latency, tAA, s->sm_sdr.sdr_tRCD,
548 1.1.2.2 uebayasi s->sm_sdr.sdr_tRP, s->sm_sdr.sdr_tRAS);
549 1.1.2.2 uebayasi
550 1.1.2.2 uebayasi decode_voltage_refresh(self, s);
551 1.1.2.2 uebayasi }
552 1.1.2.2 uebayasi
553 1.1.2.2 uebayasi static void
554 1.1.2.2 uebayasi decode_ddr(const struct sysctlnode *node, device_t self, struct spdmem *s) {
555 1.1.2.2 uebayasi int dimm_size, cycle_time, bits, tAA, i;
556 1.1.2.2 uebayasi
557 1.1.2.2 uebayasi aprint_normal("%s, %s, ",
558 1.1.2.2 uebayasi (s->sm_ddr.ddr_mod_attrs & SPDMEM_DDR_MASK_REG)?
559 1.1.2.2 uebayasi " (registered)":"",
560 1.1.2.2 uebayasi (s->sm_config < __arraycount(spdmem_parity_types))?
561 1.1.2.2 uebayasi spdmem_parity_types[s->sm_config]:"invalid parity");
562 1.1.2.2 uebayasi
563 1.1.2.2 uebayasi dimm_size = 1 << (s->sm_ddr.ddr_rows + s->sm_ddr.ddr_cols - 17);
564 1.1.2.2 uebayasi dimm_size *= s->sm_ddr.ddr_ranks * s->sm_ddr.ddr_banks_per_chip;
565 1.1.2.2 uebayasi
566 1.1.2.2 uebayasi cycle_time = s->sm_ddr.ddr_cycle_whole * 1000 +
567 1.1.2.2 uebayasi spdmem_cycle_frac[s->sm_ddr.ddr_cycle_tenths];
568 1.1.2.2 uebayasi bits = le16toh(s->sm_ddr.ddr_datawidth);
569 1.1.2.2 uebayasi if (s->sm_config == 1 || s->sm_config == 2)
570 1.1.2.2 uebayasi bits -= 8;
571 1.1.2.2 uebayasi decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC", 0);
572 1.1.2.2 uebayasi
573 1.1.2.2 uebayasi aprint_verbose_dev(self,
574 1.1.2.2 uebayasi "%d rows, %d cols, %d ranks, %d banks/chip, %d.%dns cycle time\n",
575 1.1.2.2 uebayasi s->sm_ddr.ddr_rows, s->sm_ddr.ddr_cols, s->sm_ddr.ddr_ranks,
576 1.1.2.2 uebayasi s->sm_ddr.ddr_banks_per_chip, cycle_time/1000,
577 1.1.2.2 uebayasi (cycle_time % 1000 + 50) / 100);
578 1.1.2.2 uebayasi
579 1.1.2.2 uebayasi tAA = 0;
580 1.1.2.2 uebayasi for (i = 2; i < 8; i++)
581 1.1.2.2 uebayasi if (s->sm_ddr.ddr_tCAS & (1 << i))
582 1.1.2.2 uebayasi tAA = i;
583 1.1.2.2 uebayasi tAA /= 2;
584 1.1.2.2 uebayasi
585 1.1.2.2 uebayasi #define __DDR_ROUND(scale, field) \
586 1.1.2.2 uebayasi ((scale * s->sm_ddr.field + cycle_time - 1) / cycle_time)
587 1.1.2.2 uebayasi
588 1.1.2.2 uebayasi aprint_verbose_dev(self, latency, tAA, __DDR_ROUND(250, ddr_tRCD),
589 1.1.2.2 uebayasi __DDR_ROUND(250, ddr_tRP), __DDR_ROUND(1000, ddr_tRAS));
590 1.1.2.2 uebayasi
591 1.1.2.2 uebayasi #undef __DDR_ROUND
592 1.1.2.2 uebayasi
593 1.1.2.2 uebayasi decode_voltage_refresh(self, s);
594 1.1.2.2 uebayasi }
595 1.1.2.2 uebayasi
596 1.1.2.2 uebayasi static void
597 1.1.2.2 uebayasi decode_ddr2(const struct sysctlnode *node, device_t self, struct spdmem *s) {
598 1.1.2.2 uebayasi int dimm_size, cycle_time, bits, tAA, i;
599 1.1.2.2 uebayasi
600 1.1.2.2 uebayasi aprint_normal("%s, %s, ",
601 1.1.2.2 uebayasi (s->sm_ddr2.ddr2_mod_attrs & SPDMEM_DDR2_MASK_REG)?
602 1.1.2.2 uebayasi " (registered)":"",
603 1.1.2.2 uebayasi (s->sm_config < __arraycount(spdmem_parity_types))?
604 1.1.2.2 uebayasi spdmem_parity_types[s->sm_config]:"invalid parity");
605 1.1.2.2 uebayasi
606 1.1.2.2 uebayasi dimm_size = 1 << (s->sm_ddr2.ddr2_rows + s->sm_ddr2.ddr2_cols - 17);
607 1.1.2.2 uebayasi dimm_size *= (s->sm_ddr2.ddr2_ranks + 1) *
608 1.1.2.2 uebayasi s->sm_ddr2.ddr2_banks_per_chip;
609 1.1.2.2 uebayasi
610 1.1.2.2 uebayasi cycle_time = s->sm_ddr2.ddr2_cycle_whole * 1000 +
611 1.1.2.2 uebayasi spdmem_cycle_frac[s->sm_ddr2.ddr2_cycle_frac];
612 1.1.2.2 uebayasi bits = s->sm_ddr2.ddr2_datawidth;
613 1.1.2.2 uebayasi if ((s->sm_config & 0x03) != 0)
614 1.1.2.2 uebayasi bits -= 8;
615 1.1.2.2 uebayasi decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC2", 0);
616 1.1.2.2 uebayasi
617 1.1.2.2 uebayasi aprint_verbose_dev(self,
618 1.1.2.2 uebayasi "%d rows, %d cols, %d ranks, %d banks/chip, %d.%02dns cycle time\n",
619 1.1.2.2 uebayasi s->sm_ddr2.ddr2_rows, s->sm_ddr2.ddr2_cols,
620 1.1.2.2 uebayasi s->sm_ddr2.ddr2_ranks + 1, s->sm_ddr2.ddr2_banks_per_chip,
621 1.1.2.2 uebayasi cycle_time / 1000, (cycle_time % 1000 + 5) /10 );
622 1.1.2.2 uebayasi
623 1.1.2.2 uebayasi tAA = 0;
624 1.1.2.2 uebayasi for (i = 2; i < 8; i++)
625 1.1.2.2 uebayasi if (s->sm_ddr2.ddr2_tCAS & (1 << i))
626 1.1.2.2 uebayasi tAA = i;
627 1.1.2.2 uebayasi
628 1.1.2.2 uebayasi #define __DDR2_ROUND(scale, field) \
629 1.1.2.2 uebayasi ((scale * s->sm_ddr2.field + cycle_time - 1) / cycle_time)
630 1.1.2.2 uebayasi
631 1.1.2.2 uebayasi aprint_verbose_dev(self, latency, tAA, __DDR2_ROUND(250, ddr2_tRCD),
632 1.1.2.2 uebayasi __DDR2_ROUND(250, ddr2_tRP), __DDR2_ROUND(1000, ddr2_tRAS));
633 1.1.2.2 uebayasi
634 1.1.2.2 uebayasi #undef __DDR_ROUND
635 1.1.2.2 uebayasi
636 1.1.2.2 uebayasi decode_voltage_refresh(self, s);
637 1.1.2.2 uebayasi }
638 1.1.2.2 uebayasi
639 1.1.2.2 uebayasi static void
640 1.1.2.2 uebayasi decode_ddr3(const struct sysctlnode *node, device_t self, struct spdmem *s) {
641 1.1.2.2 uebayasi int dimm_size, cycle_time, bits;
642 1.1.2.2 uebayasi
643 1.1.2.2 uebayasi if (s->sm_ddr3.ddr3_mod_type ==
644 1.1.2.2 uebayasi SPDMEM_DDR3_TYPE_MINI_RDIMM ||
645 1.1.2.2 uebayasi s->sm_ddr3.ddr3_mod_type == SPDMEM_DDR3_TYPE_RDIMM)
646 1.1.2.2 uebayasi aprint_normal(" (registered)");
647 1.1.2.2 uebayasi aprint_normal(", %sECC, %stemp-sensor, ",
648 1.1.2.2 uebayasi (s->sm_ddr3.ddr3_hasECC)?"":"no ",
649 1.1.2.2 uebayasi (s->sm_ddr3.ddr3_has_therm_sensor)?"":"no ");
650 1.1.2.2 uebayasi
651 1.1.2.2 uebayasi /*
652 1.1.2.2 uebayasi * DDR3 size specification is quite different from others
653 1.1.2.2 uebayasi *
654 1.1.2.2 uebayasi * Module capacity is defined as
655 1.1.2.2 uebayasi * Chip_Capacity_in_bits / 8bits-per-byte *
656 1.1.2.2 uebayasi * external_bus_width / internal_bus_width
657 1.1.2.2 uebayasi * We further divide by 2**20 to get our answer in MB
658 1.1.2.2 uebayasi */
659 1.1.2.2 uebayasi dimm_size = (s->sm_ddr3.ddr3_chipsize + 28 - 20) - 3 +
660 1.1.2.2 uebayasi (s->sm_ddr3.ddr3_datawidth + 3) -
661 1.1.2.2 uebayasi (s->sm_ddr3.ddr3_chipwidth + 2);
662 1.1.2.2 uebayasi dimm_size = (1 << dimm_size) * (s->sm_ddr3.ddr3_physbanks + 1);
663 1.1.2.2 uebayasi
664 1.1.2.2 uebayasi cycle_time = (1000 * s->sm_ddr3.ddr3_mtb_dividend +
665 1.1.2.2 uebayasi (s->sm_ddr3.ddr3_mtb_divisor / 2)) /
666 1.1.2.2 uebayasi s->sm_ddr3.ddr3_mtb_divisor;
667 1.1.2.2 uebayasi cycle_time *= s->sm_ddr3.ddr3_tCKmin;
668 1.1.2.2 uebayasi bits = 1 << (s->sm_ddr3.ddr3_datawidth + 3);
669 1.1.2.2 uebayasi decode_size_speed(node, dimm_size, cycle_time, 2, bits, FALSE, "PC3", 0);
670 1.1.2.2 uebayasi
671 1.1.2.2 uebayasi aprint_verbose_dev(self,
672 1.1.2.2 uebayasi "%d rows, %d cols, %d log. banks, %d phys. banks, "
673 1.1.2.2 uebayasi "%d.%03dns cycle time\n",
674 1.1.2.2 uebayasi s->sm_ddr3.ddr3_rows + 9, s->sm_ddr3.ddr3_cols + 12,
675 1.1.2.2 uebayasi 1 << (s->sm_ddr3.ddr3_logbanks + 3),
676 1.1.2.2 uebayasi s->sm_ddr3.ddr3_physbanks + 1,
677 1.1.2.2 uebayasi cycle_time/1000, cycle_time % 1000);
678 1.1.2.2 uebayasi
679 1.1.2.2 uebayasi #define __DDR3_CYCLES(field) (s->sm_ddr3.field / s->sm_ddr3.ddr3_tCKmin)
680 1.1.2.2 uebayasi
681 1.1.2.2 uebayasi aprint_verbose_dev(self, latency, __DDR3_CYCLES(ddr3_tAAmin),
682 1.1.2.2 uebayasi __DDR3_CYCLES(ddr3_tRCDmin), __DDR3_CYCLES(ddr3_tRPmin),
683 1.1.2.2 uebayasi (s->sm_ddr3.ddr3_tRAS_msb * 256 + s->sm_ddr3.ddr3_tRAS_lsb) /
684 1.1.2.2 uebayasi s->sm_ddr3.ddr3_tCKmin);
685 1.1.2.2 uebayasi
686 1.1.2.2 uebayasi #undef __DDR3_CYCLES
687 1.1.2.2 uebayasi }
688 1.1.2.2 uebayasi
689 1.1.2.2 uebayasi static void
690 1.1.2.2 uebayasi decode_fbdimm(const struct sysctlnode *node, device_t self, struct spdmem *s) {
691 1.1.2.2 uebayasi int dimm_size, cycle_time, bits;
692 1.1.2.2 uebayasi
693 1.1.2.2 uebayasi /*
694 1.1.2.2 uebayasi * FB-DIMM module size calculation is very much like DDR3
695 1.1.2.2 uebayasi */
696 1.1.2.2 uebayasi dimm_size = s->sm_fbd.fbdimm_rows + 12 +
697 1.1.2.2 uebayasi s->sm_fbd.fbdimm_cols + 9 - 20 - 3;
698 1.1.2.2 uebayasi dimm_size = (1 << dimm_size) * (1 << (s->sm_fbd.fbdimm_banks + 2));
699 1.1.2.2 uebayasi
700 1.1.2.2 uebayasi cycle_time = (1000 * s->sm_fbd.fbdimm_mtb_dividend +
701 1.1.2.2 uebayasi (s->sm_fbd.fbdimm_mtb_divisor / 2)) /
702 1.1.2.2 uebayasi s->sm_fbd.fbdimm_mtb_divisor;
703 1.1.2.2 uebayasi bits = 1 << (s->sm_fbd.fbdimm_dev_width + 2);
704 1.1.2.2 uebayasi decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC2", 0);
705 1.1.2.2 uebayasi
706 1.1.2.2 uebayasi aprint_verbose_dev(self,
707 1.1.2.2 uebayasi "%d rows, %d cols, %d banks, %d.%02dns cycle time\n",
708 1.1.2.2 uebayasi s->sm_fbd.fbdimm_rows, s->sm_fbd.fbdimm_cols,
709 1.1.2.2 uebayasi 1 << (s->sm_fbd.fbdimm_banks + 2),
710 1.1.2.2 uebayasi cycle_time / 1000, (cycle_time % 1000 + 5) /10 );
711 1.1.2.2 uebayasi
712 1.1.2.2 uebayasi #define __FBDIMM_CYCLES(field) (s->sm_fbd.field / s->sm_fbd.fbdimm_tCKmin)
713 1.1.2.2 uebayasi
714 1.1.2.2 uebayasi aprint_verbose_dev(self, latency, __FBDIMM_CYCLES(fbdimm_tAAmin),
715 1.1.2.2 uebayasi __FBDIMM_CYCLES(fbdimm_tRCDmin), __FBDIMM_CYCLES(fbdimm_tRPmin),
716 1.1.2.2 uebayasi (s->sm_fbd.fbdimm_tRAS_msb * 256 +
717 1.1.2.2 uebayasi s->sm_fbd.fbdimm_tRAS_lsb) /
718 1.1.2.2 uebayasi s->sm_fbd.fbdimm_tCKmin);
719 1.1.2.2 uebayasi
720 1.1.2.2 uebayasi #undef __FBDIMM_CYCLES
721 1.1.2.2 uebayasi
722 1.1.2.2 uebayasi decode_voltage_refresh(self, s);
723 1.1.2.2 uebayasi }
724