xref: /illumos-gate/usr/src/lib/libjedec/common/libjedec_spd_ddr3.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
1*8119dad8SRobert Mustacchi /*
2*8119dad8SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*8119dad8SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*8119dad8SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*8119dad8SRobert Mustacchi  * 1.0 of the CDDL.
6*8119dad8SRobert Mustacchi  *
7*8119dad8SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*8119dad8SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*8119dad8SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*8119dad8SRobert Mustacchi  */
11*8119dad8SRobert Mustacchi 
12*8119dad8SRobert Mustacchi /*
13*8119dad8SRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14*8119dad8SRobert Mustacchi  */
15*8119dad8SRobert Mustacchi 
16*8119dad8SRobert Mustacchi /*
17*8119dad8SRobert Mustacchi  * DDR3-specific SPD processing logic. For an overview of the processing design
18*8119dad8SRobert Mustacchi  * please see libjedec_spd.c.
19*8119dad8SRobert Mustacchi  */
20*8119dad8SRobert Mustacchi 
21*8119dad8SRobert Mustacchi #include <sys/sysmacros.h>
22*8119dad8SRobert Mustacchi #include <sys/debug.h>
23*8119dad8SRobert Mustacchi #include "libjedec_spd.h"
24*8119dad8SRobert Mustacchi 
25*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_nbytes_used_map[] = {
26*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_USED_UNDEF, 0, true },
27*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_USED_128, 128, false },
28*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_USED_176, 176, false },
29*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_USED_256, 256, false },
30*8119dad8SRobert Mustacchi };
31*8119dad8SRobert Mustacchi 
32*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_nbytes_total_map[] = {
33*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_TOTAL_UNDEF, 0, true },
34*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_TOTAL_256, 256, false }
35*8119dad8SRobert Mustacchi };
36*8119dad8SRobert Mustacchi 
37*8119dad8SRobert Mustacchi /*
38*8119dad8SRobert Mustacchi  * The macro values represent the last byte covered therefore the number of
39*8119dad8SRobert Mustacchi  * bytes is that plus one.
40*8119dad8SRobert Mustacchi  */
41*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_crc_map[] = {
42*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_CRC_125, 126, false },
43*8119dad8SRobert Mustacchi 	{ SPD_DDR3_NBYTES_CRC_116, 117, false }
44*8119dad8SRobert Mustacchi };
45*8119dad8SRobert Mustacchi 
46*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_nbytes(spd_info_t * si,uint32_t off,uint32_t len,const char * key)47*8119dad8SRobert Mustacchi spd_parse_ddr3_nbytes(spd_info_t *si, uint32_t off, uint32_t len,
48*8119dad8SRobert Mustacchi     const char *key)
49*8119dad8SRobert Mustacchi {
50*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
51*8119dad8SRobert Mustacchi 	const uint8_t used = SPD_DDR3_NBYTES_USED(data);
52*8119dad8SRobert Mustacchi 	const uint8_t total = SPD_DDR3_NBYTES_TOTAL(data);
53*8119dad8SRobert Mustacchi 	const uint8_t crc = SPD_DDR3_NBYTES_CRC(data);
54*8119dad8SRobert Mustacchi 
55*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_NBYTES_USED, used, spd_ddr3_nbytes_used_map,
56*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_nbytes_used_map));
57*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_NBYTES_TOTAL, total,
58*8119dad8SRobert Mustacchi 	    spd_ddr3_nbytes_total_map, ARRAY_SIZE(spd_ddr3_nbytes_total_map));
59*8119dad8SRobert Mustacchi 
60*8119dad8SRobert Mustacchi 	/*
61*8119dad8SRobert Mustacchi 	 * Unlike DDR5, there is no specific definition to indicate that the SPD
62*8119dad8SRobert Mustacchi 	 * is present or what type of device it is. There is only one standard
63*8119dad8SRobert Mustacchi 	 * DDR3 EEPROM, EE1002, so we note that it's here when we process this.
64*8119dad8SRobert Mustacchi 	 */
65*8119dad8SRobert Mustacchi 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_SPD);
66*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_DEV_SPD_TYPE, SPD_SPD_T_EE1002);
67*8119dad8SRobert Mustacchi 
68*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_CRC_DDR3_LEN, crc, spd_ddr3_crc_map,
69*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_crc_map));
70*8119dad8SRobert Mustacchi }
71*8119dad8SRobert Mustacchi 
72*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_mod_type_map[] = {
73*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_UNDEF, UINT32_MAX, true },
74*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_RDIMM, SPD_MOD_TYPE_RDIMM, false },
75*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_UDIMM, SPD_MOD_TYPE_UDIMM, false },
76*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_SODIMM, SPD_MOD_TYPE_SODIMM, false },
77*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_MICRO_DIMM, SPD_MOD_TYPE_MICRO_DIMM, false },
78*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_MINI_RDIMM, SPD_MOD_TYPE_MINI_RDIMM, false },
79*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_MINI_UDIMM, SPD_MOD_TYPE_MINI_UDIMM, false },
80*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_MINI_CDIMM, SPD_MOD_TYPE_MINI_CDIMM, false },
81*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_72b_SORDIMM, SPD_MOD_TYPE_72b_SO_RDIMM,
82*8119dad8SRobert Mustacchi 	    false },
83*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_72b_SOUDIMM, SPD_MOD_TYPE_72b_SO_UDIMM,
84*8119dad8SRobert Mustacchi 	    false },
85*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_72b_SOCDIMM, SPD_MOD_TYPE_72b_SO_CDIMM,
86*8119dad8SRobert Mustacchi 	    false },
87*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_LRDIMM, SPD_MOD_TYPE_LRDIMM, false },
88*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_16b_SODIMM, SPD_MOD_TYPE_16b_SO_DIMM, false },
89*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_TYPE_TYPE_32b_SODIMM, SPD_MOD_TYPE_32b_SO_DIMM, false },
90*8119dad8SRobert Mustacchi };
91*8119dad8SRobert Mustacchi 
92*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_mod_type(spd_info_t * si,uint32_t off,uint32_t len,const char * key)93*8119dad8SRobert Mustacchi spd_parse_ddr3_mod_type(spd_info_t *si, uint32_t off, uint32_t len,
94*8119dad8SRobert Mustacchi     const char *key)
95*8119dad8SRobert Mustacchi {
96*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
97*8119dad8SRobert Mustacchi 	const uint8_t type = SPD_DDR3_MOD_TYPE_TYPE(data);
98*8119dad8SRobert Mustacchi 
99*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_TYPE, type, spd_ddr3_mod_type_map,
100*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_mod_type_map));
101*8119dad8SRobert Mustacchi }
102*8119dad8SRobert Mustacchi 
103*8119dad8SRobert Mustacchi static const spd_value_range_t spd_ddr3_nba_range = {
104*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR3_DENSITY_NBA_BITS_MAX,
105*8119dad8SRobert Mustacchi 	.svr_base = SPD_DDR3_DENSITY_NBA_BITS_BASE
106*8119dad8SRobert Mustacchi };
107*8119dad8SRobert Mustacchi 
108*8119dad8SRobert Mustacchi static const spd_value_map64_t spd_ddr3_density_map[] = {
109*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_256Mb, 256ULL * 1024ULL * 1024ULL, false },
110*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_512Mb, 512ULL * 1024ULL * 1024ULL, false },
111*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_1Gb, 1ULL * 1024ULL * 1024ULL * 1024ULL,
112*8119dad8SRobert Mustacchi 	    false },
113*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_2Gb, 2ULL * 1024ULL * 1024ULL * 1024ULL,
114*8119dad8SRobert Mustacchi 	    false },
115*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_4Gb, 4ULL * 1024ULL * 1024ULL * 1024ULL,
116*8119dad8SRobert Mustacchi 	    false },
117*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_8Gb, 8ULL * 1024ULL * 1024ULL * 1024ULL,
118*8119dad8SRobert Mustacchi 	    false },
119*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_16Gb, 16ULL * 1024ULL * 1024ULL * 1024ULL,
120*8119dad8SRobert Mustacchi 	    false },
121*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_32Gb, 32ULL * 1024ULL * 1024ULL * 1024ULL,
122*8119dad8SRobert Mustacchi 	    false },
123*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_12Gb, 12ULL * 1024ULL * 1024ULL * 1024ULL,
124*8119dad8SRobert Mustacchi 	    false },
125*8119dad8SRobert Mustacchi 	{SPD_DDR3_DENSITY_DENSITY_24Gb, 24ULL * 1024ULL * 1024ULL * 1024ULL,
126*8119dad8SRobert Mustacchi 	    false },
127*8119dad8SRobert Mustacchi };
128*8119dad8SRobert Mustacchi 
129*8119dad8SRobert Mustacchi /*
130*8119dad8SRobert Mustacchi  * DDR3 does not define bank groups, hence when we insert the bank address bits
131*8119dad8SRobert Mustacchi  * we come back and set bank group bits to 0.
132*8119dad8SRobert Mustacchi  */
133*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_density(spd_info_t * si,uint32_t off,uint32_t len,const char * key)134*8119dad8SRobert Mustacchi spd_parse_ddr3_density(spd_info_t *si, uint32_t off, uint32_t len,
135*8119dad8SRobert Mustacchi     const char *key)
136*8119dad8SRobert Mustacchi {
137*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
138*8119dad8SRobert Mustacchi 	const uint8_t dens = SPD_DDR3_DENSITY_DENSITY(data);
139*8119dad8SRobert Mustacchi 	const uint8_t nba = SPD_DDR3_DENSITY_NBA_BITS(data);
140*8119dad8SRobert Mustacchi 
141*8119dad8SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_NBANK_BITS, nba, &spd_ddr3_nba_range);
142*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_NBGRP_BITS, 0);
143*8119dad8SRobert Mustacchi 	spd_insert_map64(si, SPD_KEY_DIE_SIZE, dens, spd_ddr3_density_map,
144*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_density_map));
145*8119dad8SRobert Mustacchi }
146*8119dad8SRobert Mustacchi 
147*8119dad8SRobert Mustacchi static const spd_value_range_t spd_ddr3_nrow_range = {
148*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR3_ADDR_NROWS_MAX,
149*8119dad8SRobert Mustacchi 	.svr_base = SPD_DDR3_ADDR_NROWS_BASE
150*8119dad8SRobert Mustacchi };
151*8119dad8SRobert Mustacchi 
152*8119dad8SRobert Mustacchi static const spd_value_range_t spd_ddr3_ncol_range = {
153*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR3_ADDR_NCOLS_MAX,
154*8119dad8SRobert Mustacchi 	.svr_base = SPD_DDR3_ADDR_NCOLS_BASE
155*8119dad8SRobert Mustacchi };
156*8119dad8SRobert Mustacchi 
157*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_addr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)158*8119dad8SRobert Mustacchi spd_parse_ddr3_addr(spd_info_t *si, uint32_t off, uint32_t len,
159*8119dad8SRobert Mustacchi     const char *key)
160*8119dad8SRobert Mustacchi {
161*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
162*8119dad8SRobert Mustacchi 	const uint8_t nrows = SPD_DDR3_ADDR_NROWS(data);
163*8119dad8SRobert Mustacchi 	const uint8_t ncols = SPD_DDR3_ADDR_NCOLS(data);
164*8119dad8SRobert Mustacchi 
165*8119dad8SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_NROW_BITS, nrows, &spd_ddr3_nrow_range);
166*8119dad8SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_NCOL_BITS, ncols, &spd_ddr3_ncol_range);
167*8119dad8SRobert Mustacchi }
168*8119dad8SRobert Mustacchi 
169*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_volt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)170*8119dad8SRobert Mustacchi spd_parse_ddr3_volt(spd_info_t *si, uint32_t off, uint32_t len,
171*8119dad8SRobert Mustacchi     const char *key)
172*8119dad8SRobert Mustacchi {
173*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
174*8119dad8SRobert Mustacchi 	uint32_t volts[3];
175*8119dad8SRobert Mustacchi 	uint_t nvolt = 0;
176*8119dad8SRobert Mustacchi 
177*8119dad8SRobert Mustacchi 	/*
178*8119dad8SRobert Mustacchi 	 * DDR3 came out with 1.5V support initially meaning a value of zero
179*8119dad8SRobert Mustacchi 	 * indicates that 1.5V is supported. Affirmative values came later.
180*8119dad8SRobert Mustacchi 	 */
181*8119dad8SRobert Mustacchi 	if (SPD_DDR3_VOLT_V1P5_OPER(data) == 0) {
182*8119dad8SRobert Mustacchi 		volts[nvolt] = 1500;
183*8119dad8SRobert Mustacchi 		nvolt++;
184*8119dad8SRobert Mustacchi 	}
185*8119dad8SRobert Mustacchi 
186*8119dad8SRobert Mustacchi 	if (SPD_DDR3_VOLT_V1P35_OPER(data) != 0) {
187*8119dad8SRobert Mustacchi 		volts[nvolt] = 1350;
188*8119dad8SRobert Mustacchi 		nvolt++;
189*8119dad8SRobert Mustacchi 	}
190*8119dad8SRobert Mustacchi 
191*8119dad8SRobert Mustacchi 	if (SPD_DDR3_VOLT_V1P25_OPER(data) != 0) {
192*8119dad8SRobert Mustacchi 		volts[nvolt] = 1250;
193*8119dad8SRobert Mustacchi 		nvolt++;
194*8119dad8SRobert Mustacchi 	}
195*8119dad8SRobert Mustacchi 
196*8119dad8SRobert Mustacchi 	if (nvolt > 0) {
197*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32_array(si, key, volts, nvolt);
198*8119dad8SRobert Mustacchi 	}
199*8119dad8SRobert Mustacchi }
200*8119dad8SRobert Mustacchi 
201*8119dad8SRobert Mustacchi static const spd_value_range_t spd_ddr3_width_range = {
202*8119dad8SRobert Mustacchi 	.svr_base = SPD_DDR3_MOD_ORG_WIDTH_BASE,
203*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR3_MOD_ORG_WIDTH_MAX,
204*8119dad8SRobert Mustacchi 	.svr_exp = true
205*8119dad8SRobert Mustacchi };
206*8119dad8SRobert Mustacchi 
207*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_nranks[] = {
208*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_ORG_NRANKS_1, 1, false },
209*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_ORG_NRANKS_2, 2, false },
210*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_ORG_NRANKS_3, 3, false },
211*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_ORG_NRANKS_4, 4, false },
212*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MOD_ORG_NRANKS_8, 8, false }
213*8119dad8SRobert Mustacchi };
214*8119dad8SRobert Mustacchi 
215*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_mod_org(spd_info_t * si,uint32_t off,uint32_t len,const char * key)216*8119dad8SRobert Mustacchi spd_parse_ddr3_mod_org(spd_info_t *si, uint32_t off, uint32_t len,
217*8119dad8SRobert Mustacchi     const char *key)
218*8119dad8SRobert Mustacchi {
219*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
220*8119dad8SRobert Mustacchi 	const uint8_t nranks = SPD_DDR4_MOD_ORG_NPKG_RANK(data);
221*8119dad8SRobert Mustacchi 	const uint8_t width = SPD_DDR4_MOD_ORG_WIDTH(data);
222*8119dad8SRobert Mustacchi 
223*8119dad8SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_DRAM_WIDTH, width, &spd_ddr3_width_range);
224*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_NRANKS, nranks, spd_ddr3_nranks,
225*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_nranks));
226*8119dad8SRobert Mustacchi }
227*8119dad8SRobert Mustacchi 
228*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_ext_width[] = {
229*8119dad8SRobert Mustacchi 	{ SPD_DDR4_MOD_BUS_WIDTH_EXT_NONE, 0, false },
230*8119dad8SRobert Mustacchi 	{ SPD_DDR4_MOD_BUS_WIDTH_EXT_8b, 8, false }
231*8119dad8SRobert Mustacchi };
232*8119dad8SRobert Mustacchi 
233*8119dad8SRobert Mustacchi static const spd_value_range_t spd_ddr3_pri_range = {
234*8119dad8SRobert Mustacchi 	.svr_base = SPD_DDR3_BUS_WIDTH_PRI_BASE,
235*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR3_BUS_WIDTH_PRI_MAX,
236*8119dad8SRobert Mustacchi 	.svr_exp = true
237*8119dad8SRobert Mustacchi };
238*8119dad8SRobert Mustacchi 
239*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_bus_width(spd_info_t * si,uint32_t off,uint32_t len,const char * key)240*8119dad8SRobert Mustacchi spd_parse_ddr3_bus_width(spd_info_t *si, uint32_t off, uint32_t len,
241*8119dad8SRobert Mustacchi     const char *key)
242*8119dad8SRobert Mustacchi {
243*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
244*8119dad8SRobert Mustacchi 	const uint8_t ext = SPD_DDR3_BUS_WIDTH_EXT(data);
245*8119dad8SRobert Mustacchi 	const uint8_t pri = SPD_DDR3_BUS_WIDTH_PRI(data);
246*8119dad8SRobert Mustacchi 
247*8119dad8SRobert Mustacchi 	/*
248*8119dad8SRobert Mustacchi 	 * DDR3 only has a single channel and subchanne. Record that reality
249*8119dad8SRobert Mustacchi 	 * here.
250*8119dad8SRobert Mustacchi 	 */
251*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_NSUBCHAN, 1);
252*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_DRAM_NCHAN, 1);
253*8119dad8SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_DATA_WIDTH, pri, &spd_ddr3_pri_range);
254*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_ECC_WIDTH, ext, spd_ddr3_ext_width,
255*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_ext_width));
256*8119dad8SRobert Mustacchi }
257*8119dad8SRobert Mustacchi 
258*8119dad8SRobert Mustacchi /*
259*8119dad8SRobert Mustacchi  * We only currently support a 1 ps FTB. The DDR3 spec has examples of 2.5ps and
260*8119dad8SRobert Mustacchi  * 5ps versions. 1p was the magic number required for DDR4 and LPDDR3-5. For now
261*8119dad8SRobert Mustacchi  * we admit we don't support processing it and will cross the bridge when it
262*8119dad8SRobert Mustacchi  * becomes important for consumers.
263*8119dad8SRobert Mustacchi  */
264*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_ftb(spd_info_t * si,uint32_t off,uint32_t len,const char * key)265*8119dad8SRobert Mustacchi spd_parse_ddr3_ftb(spd_info_t *si, uint32_t off, uint32_t len,
266*8119dad8SRobert Mustacchi     const char *key)
267*8119dad8SRobert Mustacchi {
268*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
269*8119dad8SRobert Mustacchi 
270*8119dad8SRobert Mustacchi 	if (SPD_DDR3_FTB_DIVIDEND(data) != 1 ||
271*8119dad8SRobert Mustacchi 	    SPD_DDR3_FTB_DIVISOR(data) != 1) {
272*8119dad8SRobert Mustacchi 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, "library cannot "
273*8119dad8SRobert Mustacchi 		    "handle FTB value that's not 1ps, found divisor and "
274*8119dad8SRobert Mustacchi 		    "dividend %u/%u", SPD_DDR3_FTB_DIVISOR(data),
275*8119dad8SRobert Mustacchi 		    SPD_DDR3_FTB_DIVIDEND(data));
276*8119dad8SRobert Mustacchi 		return;
277*8119dad8SRobert Mustacchi 	}
278*8119dad8SRobert Mustacchi 
279*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, key, SPD_DDR3_FTB_PS);
280*8119dad8SRobert Mustacchi }
281*8119dad8SRobert Mustacchi 
282*8119dad8SRobert Mustacchi /*
283*8119dad8SRobert Mustacchi  * There are two bytes that represent the divisor and dividend; however, only a
284*8119dad8SRobert Mustacchi  * value that results in 125ps is supported by the spec.
285*8119dad8SRobert Mustacchi  */
286*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_mtb(spd_info_t * si,uint32_t off,uint32_t len,const char * key)287*8119dad8SRobert Mustacchi spd_parse_ddr3_mtb(spd_info_t *si, uint32_t off, uint32_t len,
288*8119dad8SRobert Mustacchi     const char *key)
289*8119dad8SRobert Mustacchi {
290*8119dad8SRobert Mustacchi 	const uint8_t dividend = si->si_data[off];
291*8119dad8SRobert Mustacchi 	const uint8_t divisor = si->si_data[off + 1];
292*8119dad8SRobert Mustacchi 
293*8119dad8SRobert Mustacchi 	if (dividend != SPD_DDR3_MTB_125PS_DIVIDEND ||
294*8119dad8SRobert Mustacchi 	    divisor != SPD_DDR3_MTB_125PS_DIVISOR) {
295*8119dad8SRobert Mustacchi 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE, "library encountered "
296*8119dad8SRobert Mustacchi 		    "undefined MTB value (not 125ps): found divisor and "
297*8119dad8SRobert Mustacchi 		    "dividend %u/%u", divisor, dividend);
298*8119dad8SRobert Mustacchi 		return;
299*8119dad8SRobert Mustacchi 	}
300*8119dad8SRobert Mustacchi 
301*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, key, SPD_DDR3_MTB_PS);
302*8119dad8SRobert Mustacchi }
303*8119dad8SRobert Mustacchi 
304*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_cas(spd_info_t * si,uint32_t off,uint32_t len,const char * key)305*8119dad8SRobert Mustacchi spd_parse_ddr3_cas(spd_info_t *si, uint32_t off, uint32_t len,
306*8119dad8SRobert Mustacchi     const char *key)
307*8119dad8SRobert Mustacchi {
308*8119dad8SRobert Mustacchi 	uint32_t cas[16] = { 0 };
309*8119dad8SRobert Mustacchi 	uint_t ncas = 0;
310*8119dad8SRobert Mustacchi 
311*8119dad8SRobert Mustacchi 	ASSERT3U(len, ==, 2);
312*8119dad8SRobert Mustacchi 	for (uint32_t byte = 0; byte < len; byte++) {
313*8119dad8SRobert Mustacchi 		const uint32_t data = si->si_data[off + byte];
314*8119dad8SRobert Mustacchi 		uint32_t nbits = NBBY;
315*8119dad8SRobert Mustacchi 
316*8119dad8SRobert Mustacchi 		/*
317*8119dad8SRobert Mustacchi 		 * The last byte reserves the last bit.
318*8119dad8SRobert Mustacchi 		 */
319*8119dad8SRobert Mustacchi 		if (byte == len - 1)
320*8119dad8SRobert Mustacchi 			nbits--;
321*8119dad8SRobert Mustacchi 
322*8119dad8SRobert Mustacchi 		for (uint32_t i = 0; i < nbits; i++) {
323*8119dad8SRobert Mustacchi 			if (bitx8(data, i, i) == 1) {
324*8119dad8SRobert Mustacchi 				cas[ncas] = SPD_DDR3_CAS_BASE + i + NBBY * byte;
325*8119dad8SRobert Mustacchi 				ncas++;
326*8119dad8SRobert Mustacchi 			}
327*8119dad8SRobert Mustacchi 		}
328*8119dad8SRobert Mustacchi 	}
329*8119dad8SRobert Mustacchi 
330*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32_array(si, key, cas, ncas);
331*8119dad8SRobert Mustacchi }
332*8119dad8SRobert Mustacchi 
333*8119dad8SRobert Mustacchi /*
334*8119dad8SRobert Mustacchi  * Parse a time value that is a single number of MTB units.
335*8119dad8SRobert Mustacchi  */
336*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_mtb_time(spd_info_t * si,uint32_t off,uint32_t len,const char * key)337*8119dad8SRobert Mustacchi spd_parse_ddr3_mtb_time(spd_info_t *si, uint32_t off, uint32_t len,
338*8119dad8SRobert Mustacchi     const char *key)
339*8119dad8SRobert Mustacchi {
340*8119dad8SRobert Mustacchi 	const uint64_t ps = (uint64_t)si->si_data[off] * SPD_DDR3_MTB_PS;
341*8119dad8SRobert Mustacchi 
342*8119dad8SRobert Mustacchi 	if (ps == 0) {
343*8119dad8SRobert Mustacchi 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
344*8119dad8SRobert Mustacchi 		    "encountered unexpected zero time value");
345*8119dad8SRobert Mustacchi 		return;
346*8119dad8SRobert Mustacchi 	}
347*8119dad8SRobert Mustacchi 	spd_nvl_insert_u64(si, key, ps);
348*8119dad8SRobert Mustacchi }
349*8119dad8SRobert Mustacchi 
350*8119dad8SRobert Mustacchi /*
351*8119dad8SRobert Mustacchi  *
352*8119dad8SRobert Mustacchi  * t~RAS~ consists of the upper nibble at off and the MTB at off + 1.
353*8119dad8SRobert Mustacchi  */
354*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_tras(spd_info_t * si,uint32_t off,uint32_t len,const char * key)355*8119dad8SRobert Mustacchi spd_parse_ddr3_tras(spd_info_t *si, uint32_t off, uint32_t len,
356*8119dad8SRobert Mustacchi     const char *key)
357*8119dad8SRobert Mustacchi {
358*8119dad8SRobert Mustacchi 	const uint8_t ras_nib = SPD_DDR3_RAS_RC_UPPER_RAS(si->si_data[off]);
359*8119dad8SRobert Mustacchi 	ASSERT3U(len, ==, 2);
360*8119dad8SRobert Mustacchi 
361*8119dad8SRobert Mustacchi 	return (spd_parse_ddr_time(si, key, ras_nib, si->si_data[off + 1], 0));
362*8119dad8SRobert Mustacchi }
363*8119dad8SRobert Mustacchi 
364*8119dad8SRobert Mustacchi /*
365*8119dad8SRobert Mustacchi  * t~RC~ consists of an upper 4-bit nibble at off. Its MTB is at off + 2. The
366*8119dad8SRobert Mustacchi  * FTB is at off + len - 1.
367*8119dad8SRobert Mustacchi  */
368*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_trc(spd_info_t * si,uint32_t off,uint32_t len,const char * key)369*8119dad8SRobert Mustacchi spd_parse_ddr3_trc(spd_info_t *si, uint32_t off, uint32_t len,
370*8119dad8SRobert Mustacchi     const char *key)
371*8119dad8SRobert Mustacchi {
372*8119dad8SRobert Mustacchi 	const uint8_t rc_nib = SPD_DDR3_RAS_RC_UPPER_RC(si->si_data[off]);
373*8119dad8SRobert Mustacchi 
374*8119dad8SRobert Mustacchi 	return (spd_parse_ddr_time(si, key, rc_nib, si->si_data[off + 2],
375*8119dad8SRobert Mustacchi 	    si->si_data[off + len - 1]));
376*8119dad8SRobert Mustacchi }
377*8119dad8SRobert Mustacchi 
378*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_tfaw(spd_info_t * si,uint32_t off,uint32_t len,const char * key)379*8119dad8SRobert Mustacchi spd_parse_ddr3_tfaw(spd_info_t *si, uint32_t off, uint32_t len,
380*8119dad8SRobert Mustacchi     const char *key)
381*8119dad8SRobert Mustacchi {
382*8119dad8SRobert Mustacchi 	const uint8_t nib = SPD_DDR3_TFAB_NIB_UPPER_TFAW(si->si_data[off]);
383*8119dad8SRobert Mustacchi 	ASSERT3U(len, ==, 2);
384*8119dad8SRobert Mustacchi 
385*8119dad8SRobert Mustacchi 	return (spd_parse_ddr_time(si, key, nib, si->si_data[off + 1], 0));
386*8119dad8SRobert Mustacchi }
387*8119dad8SRobert Mustacchi 
388*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_opt_feat(spd_info_t * si,uint32_t off,uint32_t len,const char * key)389*8119dad8SRobert Mustacchi spd_parse_ddr3_opt_feat(spd_info_t *si, uint32_t off, uint32_t len,
390*8119dad8SRobert Mustacchi     const char *key)
391*8119dad8SRobert Mustacchi {
392*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
393*8119dad8SRobert Mustacchi 	spd_ddr3_feat_t flags = 0;
394*8119dad8SRobert Mustacchi 
395*8119dad8SRobert Mustacchi 	if (SPD_DDR3_OPT_FEAT_RZQ6(data) != 0)
396*8119dad8SRobert Mustacchi 		flags |= SPD_DDR3_FEAT_RZQ_6;
397*8119dad8SRobert Mustacchi 	if (SPD_DDR3_OPT_FEAT_RZQ7(data) != 0)
398*8119dad8SRobert Mustacchi 		flags |= SPD_DDR3_FEAT_RZQ_7;
399*8119dad8SRobert Mustacchi 	if (SPD_DDR3_OPT_FEAT_DLLO(data) != 0)
400*8119dad8SRobert Mustacchi 		flags |= SPD_DDR3_FEAT_DLL_OFF;
401*8119dad8SRobert Mustacchi 
402*8119dad8SRobert Mustacchi 	if (flags != 0) {
403*8119dad8SRobert Mustacchi 		spd_upsert_flag(si, SPD_KEY_DDR3_FEAT, flags);
404*8119dad8SRobert Mustacchi 	}
405*8119dad8SRobert Mustacchi }
406*8119dad8SRobert Mustacchi 
407*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_temp[] = {
408*8119dad8SRobert Mustacchi 	{ SPD_DDR3_REFRESH_ETR_TEMP_85C, JEDEC_TEMP_CASE_NT, false },
409*8119dad8SRobert Mustacchi 	{ SPD_DDR3_REFRESH_ETR_TEMP_95C, JEDEC_TEMP_CASE_XT, false },
410*8119dad8SRobert Mustacchi };
411*8119dad8SRobert Mustacchi 
412*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_xtrr[] = {
413*8119dad8SRobert Mustacchi 	{ SPD_DDR3_REFRESH_ETR_REF_2X, 2, false },
414*8119dad8SRobert Mustacchi 	{ SPD_DDR3_REFRESH_ETR_REF_1X, 1, false },
415*8119dad8SRobert Mustacchi };
416*8119dad8SRobert Mustacchi 
417*8119dad8SRobert Mustacchi /*
418*8119dad8SRobert Mustacchi  * While this defines an ODTS bit it was pending a ballot and it's not clear to
419*8119dad8SRobert Mustacchi  * us that this ballot has ever passed. If it has, then we will denote
420*8119dad8SRobert Mustacchi  * something there.
421*8119dad8SRobert Mustacchi  */
422*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_refresh(spd_info_t * si,uint32_t off,uint32_t len,const char * key)423*8119dad8SRobert Mustacchi spd_parse_ddr3_refresh(spd_info_t *si, uint32_t off, uint32_t len,
424*8119dad8SRobert Mustacchi     const char *key)
425*8119dad8SRobert Mustacchi {
426*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
427*8119dad8SRobert Mustacchi 	const uint8_t etr = SPD_DDR3_REFRESH_ETR_TEMP(data);
428*8119dad8SRobert Mustacchi 	const uint8_t rr = SPD_DDR3_REFRESH_ETR_REF(data);
429*8119dad8SRobert Mustacchi 
430*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_OPER_TEMP, etr,
431*8119dad8SRobert Mustacchi 	    spd_ddr3_temp, ARRAY_SIZE(spd_ddr3_temp));
432*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_XTRR, rr,
433*8119dad8SRobert Mustacchi 	    spd_ddr3_xtrr, ARRAY_SIZE(spd_ddr3_xtrr));
434*8119dad8SRobert Mustacchi 	if (SPD_DDR3_REFRESH_ASR_SUP(data) != 0) {
435*8119dad8SRobert Mustacchi 		spd_upsert_flag(si, SPD_KEY_DDR3_FEAT, SPD_DDR3_FEAT_ASR);
436*8119dad8SRobert Mustacchi 	}
437*8119dad8SRobert Mustacchi 
438*8119dad8SRobert Mustacchi 	if (SPD_DDR3_REFRESH_PASR_SUP(data) != 0) {
439*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR_PASR);
440*8119dad8SRobert Mustacchi 	}
441*8119dad8SRobert Mustacchi }
442*8119dad8SRobert Mustacchi 
443*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_ts(spd_info_t * si,uint32_t off,uint32_t len,const char * key)444*8119dad8SRobert Mustacchi spd_parse_ddr3_ts(spd_info_t *si, uint32_t off, uint32_t len,
445*8119dad8SRobert Mustacchi     const char *key)
446*8119dad8SRobert Mustacchi {
447*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
448*8119dad8SRobert Mustacchi 
449*8119dad8SRobert Mustacchi 	if (SPD_DDR3_MOD_THERM_PRES(data)) {
450*8119dad8SRobert Mustacchi 		spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_TEMP_1);
451*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DEV_TEMP_TYPE,
452*8119dad8SRobert Mustacchi 		    SPD_TEMP_T_TSE2002);
453*8119dad8SRobert Mustacchi 	}
454*8119dad8SRobert Mustacchi }
455*8119dad8SRobert Mustacchi 
456*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_sl_map[] = {
457*8119dad8SRobert Mustacchi 	{ SPD_DDR3_PKG_SIG_LOAD_UNSPEC, SPD_SL_UNSPECIFIED, false },
458*8119dad8SRobert Mustacchi 	{ SPD_DDR3_PKG_SIG_LOAD_MULTI, SPD_SL_MUTLI_STACK, false },
459*8119dad8SRobert Mustacchi 	{ SPD_DDR3_PKG_SIG_LOAD_SINGLE, SPD_SL_3DS, false }
460*8119dad8SRobert Mustacchi };
461*8119dad8SRobert Mustacchi 
462*8119dad8SRobert Mustacchi static const spd_value_range_t spd_ddr3_ndie_range = {
463*8119dad8SRobert Mustacchi 	.svr_min = SPD_DDR3_PKG_DIE_CNT_MIN,
464*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR3_PKG_DIE_CNT_MAX,
465*8119dad8SRobert Mustacchi 	.svr_exp = true
466*8119dad8SRobert Mustacchi };
467*8119dad8SRobert Mustacchi 
468*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_type(spd_info_t * si,uint32_t off,uint32_t len,const char * key)469*8119dad8SRobert Mustacchi spd_parse_ddr3_type(spd_info_t *si, uint32_t off, uint32_t len,
470*8119dad8SRobert Mustacchi     const char *key)
471*8119dad8SRobert Mustacchi {
472*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
473*8119dad8SRobert Mustacchi 	const uint8_t ndie = SPD_DDR3_PKG_DIE_CNT(data);
474*8119dad8SRobert Mustacchi 	const uint8_t sl = SPD_DDR3_PKG_SIG_LOAD(data);
475*8119dad8SRobert Mustacchi 
476*8119dad8SRobert Mustacchi 	if (SPD_DDR3_PKG_TYPE(data) == SPD_DDR3_PKG_TYPE_NOT) {
477*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_PKG_NOT_MONO);
478*8119dad8SRobert Mustacchi 	}
479*8119dad8SRobert Mustacchi 
480*8119dad8SRobert Mustacchi 	/*
481*8119dad8SRobert Mustacchi 	 * A value of zero here is considered unspecified.
482*8119dad8SRobert Mustacchi 	 */
483*8119dad8SRobert Mustacchi 	if (SPD_DDR3_PKG_DIE_CNT(data) != 0) {
484*8119dad8SRobert Mustacchi 		spd_insert_range(si, SPD_KEY_PKG_NDIE, ndie,
485*8119dad8SRobert Mustacchi 		    &spd_ddr3_ndie_range);
486*8119dad8SRobert Mustacchi 	}
487*8119dad8SRobert Mustacchi 
488*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_PKG_SL, sl, spd_ddr3_sl_map,
489*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_sl_map));
490*8119dad8SRobert Mustacchi }
491*8119dad8SRobert Mustacchi 
492*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_maw_map[] = {
493*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAW_8192X, 8192, false },
494*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAW_4096X, 4096, false },
495*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAW_2048X, 2048, false }
496*8119dad8SRobert Mustacchi };
497*8119dad8SRobert Mustacchi 
498*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_mac_map[] = {
499*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_UNTESTED, 0, true},
500*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_700K, 700000, false },
501*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_600K, 600000, false },
502*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_500K, 500000, false },
503*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_400K, 400000, false },
504*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_300K, 300000, false },
505*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_200K, 200000, false },
506*8119dad8SRobert Mustacchi 	{ SPD_DDR3_MAC_MAC_UNLIMITED, SPD_KEY_MAC_UNLIMITED, false }
507*8119dad8SRobert Mustacchi };
508*8119dad8SRobert Mustacchi 
509*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_mac(spd_info_t * si,uint32_t off,uint32_t len,const char * key)510*8119dad8SRobert Mustacchi spd_parse_ddr3_mac(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
511*8119dad8SRobert Mustacchi {
512*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
513*8119dad8SRobert Mustacchi 	const uint8_t maw = SPD_DDR3_MAC_MAW(data);
514*8119dad8SRobert Mustacchi 	const uint8_t mac = SPD_DDR3_MAC_MAC(data);
515*8119dad8SRobert Mustacchi 
516*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MAW, maw, spd_ddr3_maw_map,
517*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_maw_map));
518*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MAC, mac, spd_ddr3_mac_map,
519*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_mac_map));
520*8119dad8SRobert Mustacchi }
521*8119dad8SRobert Mustacchi 
522*8119dad8SRobert Mustacchi /*
523*8119dad8SRobert Mustacchi  * The DDR3 CRC comes in two different lengths as the DDR3 CRC may optionally
524*8119dad8SRobert Mustacchi  * cover the manufacturing information or stop short at byte 116. Which length
525*8119dad8SRobert Mustacchi  * this is is defined in byte 0.
526*8119dad8SRobert Mustacchi  */
527*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_crc(spd_info_t * si,uint32_t off,uint32_t len,const char * key)528*8119dad8SRobert Mustacchi spd_parse_ddr3_crc(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
529*8119dad8SRobert Mustacchi {
530*8119dad8SRobert Mustacchi 	const uint16_t expect = si->si_data[off + len - 2] |
531*8119dad8SRobert Mustacchi 	    (si->si_data[off + len - 1] << 8);
532*8119dad8SRobert Mustacchi 	const uint8_t crc = SPD_DDR3_NBYTES_CRC(si->si_data[SPD_DDR3_NBYTES]);
533*8119dad8SRobert Mustacchi 	const uint32_t crc_len = crc == SPD_DDR3_NBYTES_CRC_125 ? 127 : 117;
534*8119dad8SRobert Mustacchi 
535*8119dad8SRobert Mustacchi 	spd_parse_crc_expect(si, off, crc_len, expect, key);
536*8119dad8SRobert Mustacchi }
537*8119dad8SRobert Mustacchi 
538*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr3_common[] = {
539*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_NBYTES, .sp_parse = spd_parse_ddr3_nbytes },
540*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_SPD_REV, .sp_parse = spd_parse_rev },
541*8119dad8SRobert Mustacchi 	/*
542*8119dad8SRobert Mustacchi 	 * We have previously validated that the DRAM type is something that we
543*8119dad8SRobert Mustacchi 	 * understand. We pass through the raw enum to users here.
544*8119dad8SRobert Mustacchi 	 */
545*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_DRAM_TYPE, .sp_key = SPD_KEY_DRAM_TYPE,
546*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_raw_u8 },
547*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MOD_TYPE, .sp_parse = spd_parse_ddr3_mod_type },
548*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_DENSITY, .sp_parse = spd_parse_ddr3_density },
549*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_ADDR, .sp_parse = spd_parse_ddr3_addr },
550*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_VOLT, .sp_key = SPD_KEY_NOM_VDD,
551*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_volt },
552*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MOD_ORG, .sp_parse = spd_parse_ddr3_mod_org },
553*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_BUS_WIDTH, .sp_parse = spd_parse_ddr3_bus_width },
554*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_FTB, .sp_key = SPD_KEY_FTB,
555*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_ftb },
556*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MTB_DIVIDEND, .sp_key = SPD_KEY_MTB, .sp_len = 2,
557*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_mtb },
558*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TCK_MIN, .sp_key = SPD_KEY_TCKAVG_MIN,
559*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_TCK_MIN_FINE - SPD_DDR3_TCK_MIN + 1,
560*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
561*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_CAS_SUP0, .sp_key = SPD_KEY_CAS, .sp_len = 2,
562*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_cas },
563*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TAA_MIN, .sp_key = SPD_KEY_TAA_MIN,
564*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_TAA_MIN_FINE - SPD_DDR3_TAA_MIN + 1,
565*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
566*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TWR_MIN, .sp_key = SPD_KEY_TWR_MIN,
567*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_mtb_time },
568*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TRCD_MIN, .sp_key = SPD_KEY_TRCD_MIN,
569*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_TRCD_MIN_FINE - SPD_DDR3_TRCD_MIN + 1,
570*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
571*8119dad8SRobert Mustacchi 	/*
572*8119dad8SRobert Mustacchi 	 * DDR3 defines only a single tRRD value. There are no bank groups in
573*8119dad8SRobert Mustacchi 	 * DDR3 therefore we translate that to tRRD_L, as we consider everything
574*8119dad8SRobert Mustacchi 	 * to be in a single bank group.
575*8119dad8SRobert Mustacchi 	 */
576*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TRRD_MIN, .sp_key = SPD_KEY_TRRD_L_MIN,
577*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_mtb_time },
578*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TRP_MIN, .sp_key = SPD_KEY_TRP_MIN,
579*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_TRP_MIN_FINE - SPD_DDR3_TRP_MIN + 1,
580*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_mtb_ftb_time_pair },
581*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RAS_RC_UPPER, .sp_len = 2,
582*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_TRAS_MIN, .sp_parse = spd_parse_ddr3_tras },
583*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RAS_RC_UPPER, .sp_key = SPD_KEY_TRC_MIN,
584*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_TRC_MIN_FINE - SPD_DDR3_RAS_RC_UPPER + 1,
585*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_trc },
586*8119dad8SRobert Mustacchi 	/*
587*8119dad8SRobert Mustacchi 	 * Our rough understanding is that the DDR3 tRFC is a 1x rate.
588*8119dad8SRobert Mustacchi 	 */
589*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TRFC_MIN_LSB, .sp_len = 2,
590*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_TRFC1_MIN, .sp_parse = spd_parse_mtb_pair },
591*8119dad8SRobert Mustacchi 	/*
592*8119dad8SRobert Mustacchi 	 * tWTR is like tRRD and it gets mapped to the same bank group case.
593*8119dad8SRobert Mustacchi 	 */
594*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TWTR_MIN, .sp_key = SPD_KEY_TWTRS_MIN,
595*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_mtb_time },
596*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TRTP_MIN, .sp_key = SPD_KEY_TRTP,
597*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_mtb_time },
598*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TFAW_NIB, .sp_len = 2,
599*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_TFAW, .sp_parse = spd_parse_ddr3_tfaw },
600*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_OPT_FEAT, .sp_parse = spd_parse_ddr3_opt_feat },
601*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_REFRESH, .sp_parse = spd_parse_ddr3_refresh },
602*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MOD_THERM, .sp_parse = spd_parse_ddr3_ts },
603*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_TYPE, .sp_parse = spd_parse_ddr3_type },
604*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MAC, .sp_parse = spd_parse_ddr3_mac},
605*8119dad8SRobert Mustacchi 	/*
606*8119dad8SRobert Mustacchi 	 * As the CRC is part of all module types we just stick in with the
607*8119dad8SRobert Mustacchi 	 * general processing.
608*8119dad8SRobert Mustacchi 	 */
609*8119dad8SRobert Mustacchi 	{ .sp_len = SPD_DDR3_CRC_MSB + 1, .sp_key = SPD_KEY_CRC_DDR3,
610*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_crc },
611*8119dad8SRobert Mustacchi };
612*8119dad8SRobert Mustacchi 
613*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr3_mfg[] = {
614*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MFG_MOD_ID0, .sp_len = 2,
615*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_MFG_ID,
616*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id },
617*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MFG_MOD_ID0, .sp_len = 2,
618*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_MFG_NAME,
619*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id_str },
620*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MFG_LOC, .sp_key = SPD_KEY_MFG_MOD_LOC_ID,
621*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_raw_u8 },
622*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MFG_YEAR, .sp_key = SPD_KEY_MFG_MOD_YEAR,
623*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_hex_string },
624*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MFG_WEEK, .sp_key = SPD_KEY_MFG_MOD_WEEK,
625*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_hex_string },
626*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MOD_SN, .sp_len = SPD_DDR3_MOD_SN_LEN,
627*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_SN, .sp_parse = spd_parse_hex_string },
628*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MOD_PN, .sp_len = SPD_DDR3_MOD_PN_LEN,
629*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_PN, .sp_parse = spd_parse_string },
630*8119dad8SRobert Mustacchi 	/*
631*8119dad8SRobert Mustacchi 	 * In DDR3 the module revision is a two byte value that is up to the
632*8119dad8SRobert Mustacchi 	 * vendor to define. While we've seen one instance where this was split
633*8119dad8SRobert Mustacchi 	 * into a DDR4 style module and DRAM revision, we just blindly turn it
634*8119dad8SRobert Mustacchi 	 * into a hex string just because that is not a guarantee.
635*8119dad8SRobert Mustacchi 	 */
636*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MOD_REV, .sp_len = SPD_DDR3_MOD_REV_LEN,
637*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_REV, .sp_parse = spd_parse_hex_string },
638*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MFG_DRAM_ID0, .sp_len = 2,
639*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_ID,
640*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id },
641*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_MFG_DRAM_ID0, .sp_len = 2,
642*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_NAME,
643*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id_str },
644*8119dad8SRobert Mustacchi };
645*8119dad8SRobert Mustacchi 
646*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_design(spd_info_t * si,uint32_t off,uint32_t len,const char * key)647*8119dad8SRobert Mustacchi spd_parse_ddr3_design(spd_info_t *si, uint32_t off, uint32_t len,
648*8119dad8SRobert Mustacchi     const char *key)
649*8119dad8SRobert Mustacchi {
650*8119dad8SRobert Mustacchi 	ASSERT3U(off, >=, SPD_DDR3_RDIMM_HEIGHT);
651*8119dad8SRobert Mustacchi 	return (spd_parse_design(si, off, SPD_DDR3_UDIMM_HEIGHT));
652*8119dad8SRobert Mustacchi }
653*8119dad8SRobert Mustacchi 
654*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_edge(spd_info_t * si,uint32_t off,uint32_t len,const char * key)655*8119dad8SRobert Mustacchi spd_parse_ddr3_edge(spd_info_t *si, uint32_t off, uint32_t len,
656*8119dad8SRobert Mustacchi     const char *key)
657*8119dad8SRobert Mustacchi {
658*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
659*8119dad8SRobert Mustacchi 
660*8119dad8SRobert Mustacchi 	if (SPD_DDR3_UDIMM_MAP_R1(data) == SPD_DDR3_UDIMM_MAP_R1_MIRROR)
661*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_MOD_EDGE_MIRROR);
662*8119dad8SRobert Mustacchi }
663*8119dad8SRobert Mustacchi 
664*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr3_udimm[] = {
665*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_UDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
666*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_height },
667*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_UDIMM_THICK, .sp_parse = spd_parse_thickness },
668*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_UDIMM_REF, .sp_parse = spd_parse_ddr3_design },
669*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_UDIMM_MAP, .sp_parse = spd_parse_ddr3_edge }
670*8119dad8SRobert Mustacchi };
671*8119dad8SRobert Mustacchi 
672*8119dad8SRobert Mustacchi /*
673*8119dad8SRobert Mustacchi  * This mapping is true for both the number of rows and registers.
674*8119dad8SRobert Mustacchi  */
675*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_rdimm_nrows_map[] = {
676*8119dad8SRobert Mustacchi 	{ 0, 0, true },
677*8119dad8SRobert Mustacchi 	{ 1, 1, false },
678*8119dad8SRobert Mustacchi 	{ 2, 2, false },
679*8119dad8SRobert Mustacchi 	{ 3, 4, false }
680*8119dad8SRobert Mustacchi };
681*8119dad8SRobert Mustacchi 
682*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_rdimm_attr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)683*8119dad8SRobert Mustacchi spd_parse_ddr3_rdimm_attr(spd_info_t *si, uint32_t off, uint32_t len,
684*8119dad8SRobert Mustacchi     const char *key)
685*8119dad8SRobert Mustacchi {
686*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
687*8119dad8SRobert Mustacchi 	const uint8_t nregs = SPD_DDR3_RDIMM_ATTR_NREGS(data);
688*8119dad8SRobert Mustacchi 	const uint8_t nrows = SPD_DDR3_RDIMM_ATTR_NROWS(data);
689*8119dad8SRobert Mustacchi 
690*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_NROWS, nrows, spd_ddr3_rdimm_nrows_map,
691*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_rdimm_nrows_map));
692*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_NREGS, nregs, spd_ddr3_rdimm_nrows_map,
693*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_rdimm_nrows_map));
694*8119dad8SRobert Mustacchi }
695*8119dad8SRobert Mustacchi 
696*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_rdimm_hs(spd_info_t * si,uint32_t off,uint32_t len,const char * key)697*8119dad8SRobert Mustacchi spd_parse_ddr3_rdimm_hs(spd_info_t *si, uint32_t off, uint32_t len,
698*8119dad8SRobert Mustacchi     const char *key)
699*8119dad8SRobert Mustacchi {
700*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
701*8119dad8SRobert Mustacchi 
702*8119dad8SRobert Mustacchi 	if (SPD_DDR3_RDIMM_THERM_IMPL(data) != 0)
703*8119dad8SRobert Mustacchi 		spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS);
704*8119dad8SRobert Mustacchi }
705*8119dad8SRobert Mustacchi 
706*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_rdimm_type(spd_info_t * si,uint32_t off,uint32_t len,const char * key)707*8119dad8SRobert Mustacchi spd_parse_ddr3_rdimm_type(spd_info_t *si, uint32_t off, uint32_t len,
708*8119dad8SRobert Mustacchi     const char *key)
709*8119dad8SRobert Mustacchi {
710*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
711*8119dad8SRobert Mustacchi 	const uint8_t type = SPD_DDR3_RDIMM_RTYPE_TYPE(data);
712*8119dad8SRobert Mustacchi 
713*8119dad8SRobert Mustacchi 	if (type != SPD_DDR3_RDIMM_RTYPE_TYPE_SSTE32882) {
714*8119dad8SRobert Mustacchi 		spd_nvl_err(si, SPD_KEY_DEV_RCD_TYPE, SPD_ERROR_NO_XLATE,
715*8119dad8SRobert Mustacchi 		    "encountered unknown register type value: 0x%x", type);
716*8119dad8SRobert Mustacchi 		return;
717*8119dad8SRobert Mustacchi 	}
718*8119dad8SRobert Mustacchi 
719*8119dad8SRobert Mustacchi 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_RCD);
720*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_DEV_RCD_TYPE, SPD_RCD_T_SSTE32882);
721*8119dad8SRobert Mustacchi }
722*8119dad8SRobert Mustacchi 
723*8119dad8SRobert Mustacchi /*
724*8119dad8SRobert Mustacchi  * There are different variants of these maps that RDIMMs and LRDIMMs share
725*8119dad8SRobert Mustacchi  * which are used depending on the specific register value and what it actually
726*8119dad8SRobert Mustacchi  * supports.
727*8119dad8SRobert Mustacchi  */
728*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_rdimm_lmsv_ds_map[] = {
729*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_LIGHT, SPD_DRIVE_LIGHT, false },
730*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_MODERATE, SPD_DRIVE_MODERATE, false },
731*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_STRONG, SPD_DRIVE_STRONG, false },
732*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_VERY_STRONG, SPD_DRIVE_VERY_STRONG, false },
733*8119dad8SRobert Mustacchi };
734*8119dad8SRobert Mustacchi 
735*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_rdimm_lms_ds_map[] = {
736*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_LIGHT, SPD_DRIVE_LIGHT, false },
737*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_MODERATE, SPD_DRIVE_MODERATE, false },
738*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_STRONG, SPD_DRIVE_STRONG, false },
739*8119dad8SRobert Mustacchi };
740*8119dad8SRobert Mustacchi 
741*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_rdimm_lm_ds_map[] = {
742*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_LIGHT, SPD_DRIVE_LIGHT, false },
743*8119dad8SRobert Mustacchi 	{ SPD_DDR3_RDIMM_DS_MODERATE, SPD_DRIVE_MODERATE, false },
744*8119dad8SRobert Mustacchi };
745*8119dad8SRobert Mustacchi 
746*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_rdimm_cads(spd_info_t * si,uint32_t off,uint32_t len,const char * key)747*8119dad8SRobert Mustacchi spd_parse_ddr3_rdimm_cads(spd_info_t *si, uint32_t off, uint32_t len,
748*8119dad8SRobert Mustacchi     const char *key)
749*8119dad8SRobert Mustacchi {
750*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
751*8119dad8SRobert Mustacchi 	const uint8_t caa = SPD_DDR3_RDIMM_CADS_CAA(data);
752*8119dad8SRobert Mustacchi 	const uint8_t cab = SPD_DDR3_RDIMM_CADS_CAB(data);
753*8119dad8SRobert Mustacchi 
754*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_RCD_DS_CAA, caa,
755*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
756*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_RCD_DS_CAB, cab,
757*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
758*8119dad8SRobert Mustacchi }
759*8119dad8SRobert Mustacchi 
760*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_rdimm_ccds(spd_info_t * si,uint32_t off,uint32_t len,const char * key)761*8119dad8SRobert Mustacchi spd_parse_ddr3_rdimm_ccds(spd_info_t *si, uint32_t off, uint32_t len,
762*8119dad8SRobert Mustacchi     const char *key)
763*8119dad8SRobert Mustacchi {
764*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
765*8119dad8SRobert Mustacchi 	const uint8_t ctla = SPD_DDR3_RDIMM_CCDS_CTLA(data);
766*8119dad8SRobert Mustacchi 	const uint8_t ctlb = SPD_DDR3_RDIMM_CCDS_CTLB(data);
767*8119dad8SRobert Mustacchi 	const uint8_t y1 = SPD_DDR3_RDIMM_CCDS_CLK1(data);
768*8119dad8SRobert Mustacchi 	const uint8_t y0 = SPD_DDR3_RDIMM_CCDS_CLK0(data);
769*8119dad8SRobert Mustacchi 
770*8119dad8SRobert Mustacchi 
771*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_RCD_DS_CTLA, ctla,
772*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lm_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lm_ds_map));
773*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_RCD_DS_CTLB, ctlb,
774*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lm_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lm_ds_map));
775*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_RCD_DS_Y0, y0,
776*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
777*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_RCD_DS_Y1, y1,
778*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
779*8119dad8SRobert Mustacchi }
780*8119dad8SRobert Mustacchi 
781*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr3_rdimm[] = {
782*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
783*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_height },
784*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_THICK, .sp_parse = spd_parse_thickness },
785*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_REF, .sp_parse = spd_parse_ddr3_design },
786*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_ATTR,
787*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_rdimm_attr },
788*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_THERM, .sp_parse = spd_parse_ddr3_rdimm_hs },
789*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_REG_MFG_ID0, .sp_len = 2,
790*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_DEV_RCD_MFG,
791*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id },
792*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_REG_MFG_ID0, .sp_len = 2,
793*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_DEV_RCD_MFG_NAME,
794*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id_str },
795*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_REV, .sp_key = SPD_KEY_DEV_RCD_REV,
796*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_dram_step },
797*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_RTYPE,
798*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_rdimm_type },
799*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_CADS,
800*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_rdimm_cads },
801*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_RDIMM_CCDS,
802*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_rdimm_ccds },
803*8119dad8SRobert Mustacchi };
804*8119dad8SRobert Mustacchi 
805*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr3_cdimm[] = {
806*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_CDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
807*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_height },
808*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_CDIMM_THICK, .sp_parse = spd_parse_thickness },
809*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_CDIMM_REF, .sp_parse = spd_parse_ddr3_design },
810*8119dad8SRobert Mustacchi };
811*8119dad8SRobert Mustacchi 
812*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_lrdimm_nrows_map[] = {
813*8119dad8SRobert Mustacchi 	{ 0, 0, true },
814*8119dad8SRobert Mustacchi 	{ 1, 1, false },
815*8119dad8SRobert Mustacchi 	{ 2, 2, false },
816*8119dad8SRobert Mustacchi };
817*8119dad8SRobert Mustacchi 
818*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_lrdimm_orient_map[] = {
819*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_ATTR_ORIENT_VERT, SPD_ORNT_VERTICAL, false },
820*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_ATTR_ORIENT_HORIZ, SPD_ORNT_HORIZONTAL, false }
821*8119dad8SRobert Mustacchi };
822*8119dad8SRobert Mustacchi 
823*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_attr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)824*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_attr(spd_info_t *si, uint32_t off, uint32_t len,
825*8119dad8SRobert Mustacchi     const char *key)
826*8119dad8SRobert Mustacchi {
827*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
828*8119dad8SRobert Mustacchi 	const uint8_t mirror = SPD_DDR3_LRDIMM_ATTR_MIR(data);
829*8119dad8SRobert Mustacchi 	const uint8_t nrows = SPD_DDR3_LRDIMM_ATTR_NROWS(data);
830*8119dad8SRobert Mustacchi 	const uint8_t orient = SPD_DDR3_LRDIMM_ATTR_ORIENT(data);
831*8119dad8SRobert Mustacchi 
832*8119dad8SRobert Mustacchi 	if (mirror == SPD_DDR3_LRDIMM_ATTR_MIR_ODD_ARE)
833*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_MOD_EDGE_MIRROR);
834*8119dad8SRobert Mustacchi 
835*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_NROWS, nrows, spd_ddr3_lrdimm_nrows_map,
836*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr3_lrdimm_nrows_map));
837*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_MB_ORIENT, orient,
838*8119dad8SRobert Mustacchi 	    spd_ddr3_lrdimm_orient_map, ARRAY_SIZE(spd_ddr3_lrdimm_orient_map));
839*8119dad8SRobert Mustacchi 
840*8119dad8SRobert Mustacchi 	if (SPD_DDR3_LRDIMM_ATTR_HS(data) != 0)
841*8119dad8SRobert Mustacchi 		spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS);
842*8119dad8SRobert Mustacchi }
843*8119dad8SRobert Mustacchi 
844*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_mb(spd_info_t * si,uint32_t off,uint32_t len,const char * key)845*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_mb(spd_info_t *si, uint32_t off, uint32_t len,
846*8119dad8SRobert Mustacchi     const char *key)
847*8119dad8SRobert Mustacchi {
848*8119dad8SRobert Mustacchi 	ASSERT3U(len, ==, 2);
849*8119dad8SRobert Mustacchi 
850*8119dad8SRobert Mustacchi 	/*
851*8119dad8SRobert Mustacchi 	 * Use this chance to set the DDR3 MB device as present and its type.
852*8119dad8SRobert Mustacchi 	 */
853*8119dad8SRobert Mustacchi 	spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_DB);
854*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_DEV_DB_TYPE, SPD_DB_T_DDR3MB);
855*8119dad8SRobert Mustacchi 	spd_parse_jedec_id(si, off, 2, SPD_KEY_DEV_DB_MFG);
856*8119dad8SRobert Mustacchi 	spd_parse_jedec_id_str(si, off, 2, SPD_KEY_DEV_DB_MFG_NAME);
857*8119dad8SRobert Mustacchi }
858*8119dad8SRobert Mustacchi 
859*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_tcds(spd_info_t * si,uint32_t off,uint32_t len,const char * key)860*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_tcds(spd_info_t *si, uint32_t off, uint32_t len,
861*8119dad8SRobert Mustacchi     const char *key)
862*8119dad8SRobert Mustacchi {
863*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
864*8119dad8SRobert Mustacchi 	const uint8_t ca = SPD_DDR3_LRDIMM_TCDS_AC(data);
865*8119dad8SRobert Mustacchi 	const uint8_t cs = SPD_DDR3_LRDIMM_TCDS_QxCS(data);
866*8119dad8SRobert Mustacchi 
867*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_MB_DS_CA, ca,
868*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lmsv_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lmsv_ds_map));
869*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_MB_DS_CS, cs,
870*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
871*8119dad8SRobert Mustacchi }
872*8119dad8SRobert Mustacchi 
873*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_ckds(spd_info_t * si,uint32_t off,uint32_t len,const char * key)874*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_ckds(spd_info_t *si, uint32_t off, uint32_t len,
875*8119dad8SRobert Mustacchi     const char *key)
876*8119dad8SRobert Mustacchi {
877*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
878*8119dad8SRobert Mustacchi 	const uint8_t odt = SPD_DDR3_LRDIMM_CKDS_ODT(data);
879*8119dad8SRobert Mustacchi 	const uint8_t cke = SPD_DDR3_LRDIMM_CKDS_CKE(data);
880*8119dad8SRobert Mustacchi 	const uint8_t y1 = SPD_DDR3_LRDIMM_CKDS_Y1Y3(data);
881*8119dad8SRobert Mustacchi 	const uint8_t y0 = SPD_DDR3_LRDIMM_CKDS_Y0Y2(data);
882*8119dad8SRobert Mustacchi 
883*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_MB_DS_ODT, odt,
884*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
885*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_MB_DS_CKE, cke,
886*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
887*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_MB_DS_Y1, y1,
888*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
889*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR3_MB_DS_Y0, y0,
890*8119dad8SRobert Mustacchi 	    spd_ddr3_rdimm_lms_ds_map, ARRAY_SIZE(spd_ddr3_rdimm_lms_ds_map));
891*8119dad8SRobert Mustacchi }
892*8119dad8SRobert Mustacchi 
893*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_ext_delay(spd_info_t * si,uint32_t off,uint32_t len,const char * key)894*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_ext_delay(spd_info_t *si, uint32_t off, uint32_t len,
895*8119dad8SRobert Mustacchi     const char *key)
896*8119dad8SRobert Mustacchi {
897*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
898*8119dad8SRobert Mustacchi 	const uint8_t y = SPD_DDR3_LRDIMM_EXTD_Y(data);
899*8119dad8SRobert Mustacchi 	const uint8_t cs = SPD_DDR3_LRDIMM_EXTD_CS(data);
900*8119dad8SRobert Mustacchi 	const uint8_t odt = SPD_DDR3_LRDIMM_EXTD_ODT(data);
901*8119dad8SRobert Mustacchi 	const uint8_t cke = SPD_DDR3_LRDIMM_EXTD_CKE(data);
902*8119dad8SRobert Mustacchi 
903*8119dad8SRobert Mustacchi 	/*
904*8119dad8SRobert Mustacchi 	 * A value of 0 is equal to no delay, otherwise these are a measure of
905*8119dad8SRobert Mustacchi 	 * x/128 * tCK values and we store x in the nvlist.
906*8119dad8SRobert Mustacchi 	 */
907*8119dad8SRobert Mustacchi 	if (y != 0)
908*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_EXTD_Y, y);
909*8119dad8SRobert Mustacchi 	if (cs != 0)
910*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_EXTD_CS, cs);
911*8119dad8SRobert Mustacchi 	if (odt != 0)
912*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_EXTD_ODT, odt);
913*8119dad8SRobert Mustacchi 	if (cke != 0)
914*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_EXTD_CKE, cke);
915*8119dad8SRobert Mustacchi }
916*8119dad8SRobert Mustacchi 
917*8119dad8SRobert Mustacchi /*
918*8119dad8SRobert Mustacchi  * Each additive delay nibble contains an enable bit. However, the enable bit
919*8119dad8SRobert Mustacchi  * for Y clocks is actually bit 0 in SPD_DDR3_LRDIMM_TCDS.
920*8119dad8SRobert Mustacchi  */
921*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_add_delay_csy(spd_info_t * si,uint32_t off,uint32_t len,const char * key)922*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_add_delay_csy(spd_info_t *si, uint32_t off, uint32_t len,
923*8119dad8SRobert Mustacchi     const char *key)
924*8119dad8SRobert Mustacchi {
925*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
926*8119dad8SRobert Mustacchi 	const uint8_t y = SPD_DDR3_LRDIMM_ADDD_CSY_Y(data);
927*8119dad8SRobert Mustacchi 	const uint8_t cs = SPD_DDR3_LRDIMM_ADDD_CSY_CS(data);
928*8119dad8SRobert Mustacchi 	ASSERT3U(off, >, SPD_DDR3_LRDIMM_TCDS);
929*8119dad8SRobert Mustacchi 	const uint8_t yen = si->si_data[SPD_DDR3_LRDIMM_TCDS];
930*8119dad8SRobert Mustacchi 
931*8119dad8SRobert Mustacchi 	if (SPD_DDR3_LRDIMM_TCDS_ACPL(yen) != SPD_DDR3_LRDIMM_TCDS_ACPL_STD) {
932*8119dad8SRobert Mustacchi 		const uint8_t val = SPD_DDR3_LRDIMM_ADD_BASE - y;
933*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_ADDD_Y, val);
934*8119dad8SRobert Mustacchi 	}
935*8119dad8SRobert Mustacchi 
936*8119dad8SRobert Mustacchi 	if (SPD_DDR3_LRDIMM_ADDD_CSY_CS_EN(data) != 0) {
937*8119dad8SRobert Mustacchi 		const uint8_t val = SPD_DDR3_LRDIMM_ADD_BASE - cs;
938*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_ADDD_CS, val);
939*8119dad8SRobert Mustacchi 	}
940*8119dad8SRobert Mustacchi }
941*8119dad8SRobert Mustacchi 
942*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_add_delay_odt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)943*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_add_delay_odt(spd_info_t *si, uint32_t off, uint32_t len,
944*8119dad8SRobert Mustacchi     const char *key)
945*8119dad8SRobert Mustacchi {
946*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
947*8119dad8SRobert Mustacchi 	const uint8_t cke = SPD_DDR3_LRDIMM_ADDD_ODT_CKE(data);
948*8119dad8SRobert Mustacchi 	const uint8_t odt = SPD_DDR3_LRDIMM_ADDD_ODT_ODT(data);
949*8119dad8SRobert Mustacchi 
950*8119dad8SRobert Mustacchi 	if (SPD_DDR3_LRDIMM_ADDD_ODT_CKE_EN(data) != 0) {
951*8119dad8SRobert Mustacchi 		const uint8_t val = SPD_DDR3_LRDIMM_ADD_BASE - cke;
952*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_ADDD_CKE, val);
953*8119dad8SRobert Mustacchi 	}
954*8119dad8SRobert Mustacchi 
955*8119dad8SRobert Mustacchi 	if (SPD_DDR3_LRDIMM_ADDD_ODT_ODT_EN(data) != 0) {
956*8119dad8SRobert Mustacchi 		const uint8_t val = SPD_DDR3_LRDIMM_ADD_BASE - odt;
957*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR3_MB_ADDD_ODT, val);
958*8119dad8SRobert Mustacchi 	}
959*8119dad8SRobert Mustacchi }
960*8119dad8SRobert Mustacchi 
961*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_mdq_ds_map[] = {
962*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_DS_40R, 40, false },
963*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_DS_34R, 34, false },
964*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_DS_48R, 48, false },
965*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_DS_27R, 27, false },
966*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_DS_20R, 20, false }
967*8119dad8SRobert Mustacchi };
968*8119dad8SRobert Mustacchi 
969*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_odt_map[] = {
970*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_ODT_DIS, SPD_TERM_DISABLED, false },
971*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_ODT_60R, 60, false },
972*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_ODT_120R, 120, false },
973*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_ODT_40R, 40, false },
974*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_ODT_30R, 30, false },
975*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_ODT_240R, 240, false },
976*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_MDQ_ODT_80R, 80, false },
977*8119dad8SRobert Mustacchi };
978*8119dad8SRobert Mustacchi 
979*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_mdq(spd_info_t * si,uint32_t off,uint32_t len,const char * key)980*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_mdq(spd_info_t *si, uint32_t off, uint32_t len,
981*8119dad8SRobert Mustacchi     const char *key)
982*8119dad8SRobert Mustacchi {
983*8119dad8SRobert Mustacchi 	const uint8_t d800 = si->si_data[off];
984*8119dad8SRobert Mustacchi 	const uint8_t d1333 = si->si_data[off + SPD_DDR3_LRDIMM_STRIDE];
985*8119dad8SRobert Mustacchi 	const uint8_t d1866 = si->si_data[off + SPD_DDR3_LRDIMM_STRIDE * 2];
986*8119dad8SRobert Mustacchi 	const uint8_t odt[3] = { SPD_DDR3_LRDIMM_MDQ_ODT(d800),
987*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_MDQ_ODT(d1333), SPD_DDR3_LRDIMM_MDQ_ODT(d1866) };
988*8119dad8SRobert Mustacchi 	const uint8_t ds[3] = { SPD_DDR3_LRDIMM_MDQ_DS(d800),
989*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_MDQ_DS(d1333), SPD_DDR3_LRDIMM_MDQ_DS(d1866) };
990*8119dad8SRobert Mustacchi 
991*8119dad8SRobert Mustacchi 	spd_insert_map_array(si, SPD_KEY_DDR3_MDQ_ODT, odt, ARRAY_SIZE(odt),
992*8119dad8SRobert Mustacchi 	    spd_ddr3_odt_map, ARRAY_SIZE(spd_ddr3_odt_map));
993*8119dad8SRobert Mustacchi 	spd_insert_map_array(si, SPD_KEY_DDR3_MDQ_DS, ds, ARRAY_SIZE(ds),
994*8119dad8SRobert Mustacchi 	    spd_ddr3_mdq_ds_map, ARRAY_SIZE(spd_ddr3_mdq_ds_map));
995*8119dad8SRobert Mustacchi }
996*8119dad8SRobert Mustacchi 
997*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_odt_common(spd_info_t * si,uint32_t off,const char * r0_odt0_rd_key,const char * r0_odt1_rd_key,const char * r1_odt0_rd_key,const char * r1_odt1_rd_key,const char * r0_odt0_wr_key,const char * r0_odt1_wr_key,const char * r1_odt0_wr_key,const char * r1_odt1_wr_key)998*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_odt_common(spd_info_t *si, uint32_t off,
999*8119dad8SRobert Mustacchi     const char *r0_odt0_rd_key, const char *r0_odt1_rd_key,
1000*8119dad8SRobert Mustacchi     const char *r1_odt0_rd_key, const char *r1_odt1_rd_key,
1001*8119dad8SRobert Mustacchi     const char *r0_odt0_wr_key, const char *r0_odt1_wr_key,
1002*8119dad8SRobert Mustacchi     const char *r1_odt0_wr_key, const char *r1_odt1_wr_key)
1003*8119dad8SRobert Mustacchi {
1004*8119dad8SRobert Mustacchi 	const uint8_t d800 = si->si_data[off];
1005*8119dad8SRobert Mustacchi 	const uint8_t d1333 = si->si_data[off + SPD_DDR3_LRDIMM_STRIDE];
1006*8119dad8SRobert Mustacchi 	const uint8_t d1866 = si->si_data[off + SPD_DDR3_LRDIMM_STRIDE * 2];
1007*8119dad8SRobert Mustacchi 	boolean_t r0_odt0_rd[3] = { SPD_DDR3_LRDIMM_ODT_R0_ODT0_RD(d800),
1008*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT0_RD(d1333),
1009*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT0_RD(d1866) };
1010*8119dad8SRobert Mustacchi 	boolean_t r0_odt1_rd[3] = { SPD_DDR3_LRDIMM_ODT_R0_ODT1_RD(d800),
1011*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT1_RD(d1333),
1012*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT1_RD(d1866) };
1013*8119dad8SRobert Mustacchi 	boolean_t r1_odt0_rd[3] = { SPD_DDR3_LRDIMM_ODT_R1_ODT0_RD(d800),
1014*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT0_RD(d1333),
1015*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT0_RD(d1866) };
1016*8119dad8SRobert Mustacchi 	boolean_t r1_odt1_rd[3] = { SPD_DDR3_LRDIMM_ODT_R1_ODT1_RD(d800),
1017*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT1_RD(d1333),
1018*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT1_RD(d1866) };
1019*8119dad8SRobert Mustacchi 	boolean_t r0_odt0_wr[3] = { SPD_DDR3_LRDIMM_ODT_R0_ODT0_WR(d800),
1020*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT0_WR(d1333),
1021*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT0_WR(d1866) };
1022*8119dad8SRobert Mustacchi 	boolean_t r0_odt1_wr[3] = { SPD_DDR3_LRDIMM_ODT_R0_ODT1_WR(d800),
1023*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT1_WR(d1333),
1024*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_ODT1_WR(d1866) };
1025*8119dad8SRobert Mustacchi 	boolean_t r1_odt0_wr[3] = { SPD_DDR3_LRDIMM_ODT_R1_ODT0_WR(d800),
1026*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT0_WR(d1333),
1027*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT0_WR(d1866) };
1028*8119dad8SRobert Mustacchi 	boolean_t r1_odt1_wr[3] = { SPD_DDR3_LRDIMM_ODT_R1_ODT1_WR(d800),
1029*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT1_WR(d1333),
1030*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R1_ODT1_WR(d1866) };
1031*8119dad8SRobert Mustacchi 
1032*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r0_odt0_rd_key, r0_odt0_rd,
1033*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r0_odt0_rd));
1034*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r0_odt1_rd_key, r0_odt1_rd,
1035*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r0_odt1_rd));
1036*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r1_odt0_rd_key, r1_odt0_rd,
1037*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r1_odt0_rd));
1038*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r1_odt1_rd_key, r1_odt1_rd,
1039*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r1_odt1_rd));
1040*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r0_odt0_wr_key, r0_odt0_wr,
1041*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r0_odt0_wr));
1042*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r0_odt1_wr_key, r0_odt1_wr,
1043*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r0_odt1_wr));
1044*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r1_odt0_wr_key, r1_odt0_wr,
1045*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r1_odt0_wr));
1046*8119dad8SRobert Mustacchi 	spd_nvl_insert_boolean_array(si, r1_odt1_wr_key, r1_odt1_wr,
1047*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(r1_odt1_wr));
1048*8119dad8SRobert Mustacchi }
1049*8119dad8SRobert Mustacchi 
1050*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_odt_r0(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1051*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_odt_r0(spd_info_t *si, uint32_t off, uint32_t len,
1052*8119dad8SRobert Mustacchi     const char *key)
1053*8119dad8SRobert Mustacchi {
1054*8119dad8SRobert Mustacchi 	spd_parse_ddr3_lrdimm_odt_common(si, off,
1055*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R0_ODT0_RD, SPD_KEY_DDR3_MB_R0_ODT1_RD,
1056*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R1_ODT0_RD, SPD_KEY_DDR3_MB_R1_ODT1_RD,
1057*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R0_ODT0_WR, SPD_KEY_DDR3_MB_R0_ODT1_WR,
1058*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R1_ODT0_WR, SPD_KEY_DDR3_MB_R1_ODT1_WR);
1059*8119dad8SRobert Mustacchi }
1060*8119dad8SRobert Mustacchi 
1061*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_odt_r2(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1062*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_odt_r2(spd_info_t *si, uint32_t off, uint32_t len,
1063*8119dad8SRobert Mustacchi     const char *key)
1064*8119dad8SRobert Mustacchi {
1065*8119dad8SRobert Mustacchi 	spd_parse_ddr3_lrdimm_odt_common(si, off,
1066*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R2_ODT0_RD, SPD_KEY_DDR3_MB_R2_ODT1_RD,
1067*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R3_ODT0_RD, SPD_KEY_DDR3_MB_R3_ODT1_RD,
1068*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R2_ODT0_WR, SPD_KEY_DDR3_MB_R2_ODT1_WR,
1069*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R3_ODT0_WR, SPD_KEY_DDR3_MB_R3_ODT1_WR);
1070*8119dad8SRobert Mustacchi 
1071*8119dad8SRobert Mustacchi }
1072*8119dad8SRobert Mustacchi 
1073*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_odt_r4(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1074*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_odt_r4(spd_info_t *si, uint32_t off, uint32_t len,
1075*8119dad8SRobert Mustacchi     const char *key)
1076*8119dad8SRobert Mustacchi {
1077*8119dad8SRobert Mustacchi 	spd_parse_ddr3_lrdimm_odt_common(si, off,
1078*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R4_ODT0_RD, SPD_KEY_DDR3_MB_R4_ODT1_RD,
1079*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R5_ODT0_RD, SPD_KEY_DDR3_MB_R5_ODT1_RD,
1080*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R4_ODT0_WR, SPD_KEY_DDR3_MB_R4_ODT1_WR,
1081*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R5_ODT0_WR, SPD_KEY_DDR3_MB_R5_ODT1_WR);
1082*8119dad8SRobert Mustacchi 
1083*8119dad8SRobert Mustacchi }
1084*8119dad8SRobert Mustacchi 
1085*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_odt_r6(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1086*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_odt_r6(spd_info_t *si, uint32_t off, uint32_t len,
1087*8119dad8SRobert Mustacchi     const char *key)
1088*8119dad8SRobert Mustacchi {
1089*8119dad8SRobert Mustacchi 	spd_parse_ddr3_lrdimm_odt_common(si, off,
1090*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R6_ODT0_RD, SPD_KEY_DDR3_MB_R6_ODT1_RD,
1091*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R7_ODT0_RD, SPD_KEY_DDR3_MB_R7_ODT1_RD,
1092*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R6_ODT0_WR, SPD_KEY_DDR3_MB_R6_ODT1_WR,
1093*8119dad8SRobert Mustacchi 	    SPD_KEY_DDR3_MB_R7_ODT0_WR, SPD_KEY_DDR3_MB_R7_ODT1_WR);
1094*8119dad8SRobert Mustacchi }
1095*8119dad8SRobert Mustacchi 
1096*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_rtt_wr_map[] = {
1097*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_WR_DIS, SPD_TERM_DISABLED, false },
1098*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_WR_60R, 60, false },
1099*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_WR_120R, 120, false },
1100*8119dad8SRobert Mustacchi };
1101*8119dad8SRobert Mustacchi 
1102*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_rtt_nom_map[] = {
1103*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_NOM_DIS, SPD_TERM_DISABLED, false },
1104*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_NOM_60R, 60, false },
1105*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_NOM_120R, 120, false },
1106*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_NOM_40R, 40, false },
1107*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_NOM_20R, 20, false },
1108*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_NOM_30R, 30, false },
1109*8119dad8SRobert Mustacchi };
1110*8119dad8SRobert Mustacchi 
1111*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr3_dram_imp_map[] = {
1112*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_IMP_40R, 40, false },
1113*8119dad8SRobert Mustacchi 	{ SPD_DDR3_LRDIMM_RTT_IMP_34R, 34, false }
1114*8119dad8SRobert Mustacchi };
1115*8119dad8SRobert Mustacchi 
1116*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_rtt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1117*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_rtt(spd_info_t *si, uint32_t off, uint32_t len,
1118*8119dad8SRobert Mustacchi     const char *key)
1119*8119dad8SRobert Mustacchi {
1120*8119dad8SRobert Mustacchi 	const uint8_t d800 = si->si_data[off];
1121*8119dad8SRobert Mustacchi 	const uint8_t d1333 = si->si_data[off + SPD_DDR3_LRDIMM_STRIDE];
1122*8119dad8SRobert Mustacchi 	const uint8_t d1866 = si->si_data[off + SPD_DDR3_LRDIMM_STRIDE * 2];
1123*8119dad8SRobert Mustacchi 	const uint8_t imp[3] = { SPD_DDR3_LRDIMM_RTT_IMP(d800),
1124*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_RTT_IMP(d1333), SPD_DDR3_LRDIMM_RTT_IMP(d1866) };
1125*8119dad8SRobert Mustacchi 	const uint8_t nom[3] = { SPD_DDR3_LRDIMM_RTT_NOM(d800),
1126*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_RTT_NOM(d1333), SPD_DDR3_LRDIMM_RTT_NOM(d1866) };
1127*8119dad8SRobert Mustacchi 	const uint8_t wr[3] = { SPD_DDR3_LRDIMM_RTT_WR(d800),
1128*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_RTT_WR(d1333), SPD_DDR3_LRDIMM_RTT_WR(d1866) };
1129*8119dad8SRobert Mustacchi 
1130*8119dad8SRobert Mustacchi 	spd_insert_map_array(si, SPD_KEY_DDR3_DRAM_DS, imp, ARRAY_SIZE(imp),
1131*8119dad8SRobert Mustacchi 	    spd_ddr3_dram_imp_map, ARRAY_SIZE(spd_ddr3_dram_imp_map));
1132*8119dad8SRobert Mustacchi 	spd_insert_map_array(si, SPD_KEY_DDR3_RTT_NOM, nom, ARRAY_SIZE(nom),
1133*8119dad8SRobert Mustacchi 	    spd_ddr3_rtt_nom_map, ARRAY_SIZE(spd_ddr3_rtt_nom_map));
1134*8119dad8SRobert Mustacchi 	spd_insert_map_array(si, SPD_KEY_DDR3_RTT_WRT, wr, ARRAY_SIZE(wr),
1135*8119dad8SRobert Mustacchi 	    spd_ddr3_rtt_wr_map, ARRAY_SIZE(spd_ddr3_rtt_wr_map));
1136*8119dad8SRobert Mustacchi }
1137*8119dad8SRobert Mustacchi 
1138*8119dad8SRobert Mustacchi /*
1139*8119dad8SRobert Mustacchi  * Parse the delay that is spread out amongst three registers, each of which are
1140*8119dad8SRobert Mustacchi  * two apart. These are for 1.5V, 1.35, and 1.25V each.
1141*8119dad8SRobert Mustacchi  */
1142*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_lrdimm_mod_delay(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1143*8119dad8SRobert Mustacchi spd_parse_ddr3_lrdimm_mod_delay(spd_info_t *si, uint32_t off, uint32_t len,
1144*8119dad8SRobert Mustacchi     const char *key)
1145*8119dad8SRobert Mustacchi {
1146*8119dad8SRobert Mustacchi 	const uint8_t d1v5 = si->si_data[off];
1147*8119dad8SRobert Mustacchi 	const uint8_t d1v35 = si->si_data[off + 2];
1148*8119dad8SRobert Mustacchi 	const uint8_t d1v25 = si->si_data[off + 4];
1149*8119dad8SRobert Mustacchi 	uint64_t delay[3] = { d1v25 * SPD_DDR3_MTB_PS, d1v35 * SPD_DDR3_MTB_PS,
1150*8119dad8SRobert Mustacchi 	    d1v5 * SPD_DDR3_MTB_PS };
1151*8119dad8SRobert Mustacchi 
1152*8119dad8SRobert Mustacchi 	spd_nvl_insert_u64_array(si, key, delay, ARRAY_SIZE(delay));
1153*8119dad8SRobert Mustacchi }
1154*8119dad8SRobert Mustacchi 
1155*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr3_lrdimm[] = {
1156*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
1157*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_height },
1158*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_THICK, .sp_parse = spd_parse_thickness },
1159*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_REF, .sp_parse = spd_parse_ddr3_design },
1160*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_ATTR,
1161*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_attr },
1162*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_MB_REV, .sp_key = SPD_KEY_DEV_DB_REV,
1163*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_dram_step },
1164*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_MB_MFG_ID0, .sp_len = 2,
1165*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_mb },
1166*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_TCDS,
1167*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_tcds },
1168*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_CKDS,
1169*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_ckds },
1170*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_EXTD,
1171*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_ext_delay },
1172*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_ADDD_CSY,
1173*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_add_delay_csy },
1174*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_ADDD_ODT,
1175*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_add_delay_odt },
1176*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_MDQ_800,
1177*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_MDQ_1866 - SPD_DDR3_LRDIMM_MDQ_800 + 1,
1178*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_mdq },
1179*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_ODT_R0_800,
1180*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_ODT_R0_1866 -
1181*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R0_800 + 1,
1182*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_odt_r0 },
1183*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_ODT_R2_800,
1184*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_ODT_R2_1866 -
1185*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R2_800 + 1,
1186*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_odt_r2 },
1187*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_ODT_R4_800,
1188*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_ODT_R4_1866 -
1189*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R4_800 + 1,
1190*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_odt_r4 },
1191*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_ODT_R6_800,
1192*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_ODT_R6_1866 -
1193*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_ODT_R6_800 + 1,
1194*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_odt_r6 },
1195*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_RTT_800,
1196*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_RTT_1866 - SPD_DDR3_LRDIMM_RTT_800 + 1,
1197*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_rtt },
1198*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_MIN_DELAY_1V5,
1199*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_DDR3_MOD_MIN_DELAY,
1200*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_MIN_DELAY_1V25 -
1201*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_MIN_DELAY_1V5 + 1,
1202*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_mod_delay },
1203*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_MAX_DELAY_1V5,
1204*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_DDR3_MOD_MAX_DELAY,
1205*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_MAX_DELAY_1V25 -
1206*8119dad8SRobert Mustacchi 	    SPD_DDR3_LRDIMM_MAX_DELAY_1V5 + 1,
1207*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr3_lrdimm_mod_delay },
1208*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR3_LRDIMM_PERS, .sp_key = SPD_KEY_DDR3_MB_PERS,
1209*8119dad8SRobert Mustacchi 	    .sp_len = SPD_DDR3_LRDIMM_PERS_NBYTES,
1210*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_u8_array }
1211*8119dad8SRobert Mustacchi };
1212*8119dad8SRobert Mustacchi 
1213*8119dad8SRobert Mustacchi static void
spd_parse_ddr3_mod_specific(spd_info_t * si)1214*8119dad8SRobert Mustacchi spd_parse_ddr3_mod_specific(spd_info_t *si)
1215*8119dad8SRobert Mustacchi {
1216*8119dad8SRobert Mustacchi 	uint32_t type;
1217*8119dad8SRobert Mustacchi 
1218*8119dad8SRobert Mustacchi 	if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_MOD_TYPE, &type) != 0)
1219*8119dad8SRobert Mustacchi 		return;
1220*8119dad8SRobert Mustacchi 
1221*8119dad8SRobert Mustacchi 	switch (type) {
1222*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_UDIMM:
1223*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_SODIMM:
1224*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_MICRO_DIMM:
1225*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_MINI_UDIMM:
1226*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_16b_SO_DIMM:
1227*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_32b_SO_DIMM:
1228*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_72b_SO_UDIMM:
1229*8119dad8SRobert Mustacchi 		spd_parse(si, spd_ddr3_udimm, ARRAY_SIZE(spd_ddr3_udimm));
1230*8119dad8SRobert Mustacchi 		break;
1231*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_RDIMM:
1232*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_MINI_RDIMM:
1233*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_72b_SO_RDIMM:
1234*8119dad8SRobert Mustacchi 		spd_parse(si, spd_ddr3_rdimm, ARRAY_SIZE(spd_ddr3_rdimm));
1235*8119dad8SRobert Mustacchi 		break;
1236*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_72b_SO_CDIMM:
1237*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_MINI_CDIMM:
1238*8119dad8SRobert Mustacchi 		spd_parse(si, spd_ddr3_cdimm, ARRAY_SIZE(spd_ddr3_cdimm));
1239*8119dad8SRobert Mustacchi 		break;
1240*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_LRDIMM:
1241*8119dad8SRobert Mustacchi 		spd_parse(si, spd_ddr3_lrdimm, ARRAY_SIZE(spd_ddr3_lrdimm));
1242*8119dad8SRobert Mustacchi 		break;
1243*8119dad8SRobert Mustacchi 	default:
1244*8119dad8SRobert Mustacchi 		break;
1245*8119dad8SRobert Mustacchi 	}
1246*8119dad8SRobert Mustacchi }
1247*8119dad8SRobert Mustacchi 
1248*8119dad8SRobert Mustacchi void
spd_parse_ddr3(spd_info_t * si)1249*8119dad8SRobert Mustacchi spd_parse_ddr3(spd_info_t *si)
1250*8119dad8SRobert Mustacchi {
1251*8119dad8SRobert Mustacchi 	if (SPD_DDR3_SPD_REV_ENC(si->si_data[SPD_DDR3_SPD_REV]) !=
1252*8119dad8SRobert Mustacchi 	    SPD_DDR3_SPD_REV_V1) {
1253*8119dad8SRobert Mustacchi 		si->si_error = LIBJEDEC_SPD_UNSUP_REV;
1254*8119dad8SRobert Mustacchi 		return;
1255*8119dad8SRobert Mustacchi 	}
1256*8119dad8SRobert Mustacchi 
1257*8119dad8SRobert Mustacchi 	spd_parse(si, spd_ddr3_common, ARRAY_SIZE(spd_ddr3_common));
1258*8119dad8SRobert Mustacchi 	spd_parse_ddr3_mod_specific(si);
1259*8119dad8SRobert Mustacchi 	spd_parse(si, spd_ddr3_mfg, ARRAY_SIZE(spd_ddr3_mfg));
1260*8119dad8SRobert Mustacchi }
1261