xref: /illumos-gate/usr/src/lib/libjedec/common/libjedec_spd_ddr5.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
1fe82ebb0SRobert Mustacchi /*
2fe82ebb0SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3fe82ebb0SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4fe82ebb0SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5fe82ebb0SRobert Mustacchi  * 1.0 of the CDDL.
6fe82ebb0SRobert Mustacchi  *
7fe82ebb0SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8fe82ebb0SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9fe82ebb0SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10fe82ebb0SRobert Mustacchi  */
11fe82ebb0SRobert Mustacchi 
12fe82ebb0SRobert Mustacchi /*
13*8119dad8SRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14fe82ebb0SRobert Mustacchi  */
15fe82ebb0SRobert Mustacchi 
16fe82ebb0SRobert Mustacchi /*
17fe82ebb0SRobert Mustacchi  * DDR5-specific SPD processing logic. For an overview of the processing design
18fe82ebb0SRobert Mustacchi  * please see libjedec_spd.c. Note, this currently does not handle NVDIMMs.
19fe82ebb0SRobert Mustacchi  */
20fe82ebb0SRobert Mustacchi 
21fe82ebb0SRobert Mustacchi #include <sys/sysmacros.h>
22fe82ebb0SRobert Mustacchi #include <sys/debug.h>
23fe82ebb0SRobert Mustacchi #include "libjedec_spd.h"
24fe82ebb0SRobert Mustacchi 
25fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_nbytes_total_map[] = {
26fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_NBYTES_TOTAL_UNDEF, 0, true },
27fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_NBYTES_TOTAL_256, 256, false },
28fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_NBYTES_TOTAL_512, 512, false },
29fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_NBYTES_TOTAL_1024, 1024, false },
30fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_NBYTES_TOTAL_2048, 2048, false }
31fe82ebb0SRobert Mustacchi };
32fe82ebb0SRobert Mustacchi 
33fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_nbytes(spd_info_t * si,uint32_t off,uint32_t len,const char * key)34fe82ebb0SRobert Mustacchi spd_parse_ddr5_nbytes(spd_info_t *si, uint32_t off, uint32_t len,
35fe82ebb0SRobert Mustacchi     const char *key)
36fe82ebb0SRobert Mustacchi {
37fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
38fe82ebb0SRobert Mustacchi 	const uint8_t total = SPD_DDR5_NBYTES_TOTAL(data);
39fe82ebb0SRobert Mustacchi 	uint8_t beta = SPD_DDR5_NBYTES_BETA(data);
40fe82ebb0SRobert Mustacchi 	beta = bitset8(beta, 4, 4, SPD_DDR5_NBYTES_BETAHI(data));
41fe82ebb0SRobert Mustacchi 
42fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_BETA, beta);
43fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_NBYTES_TOTAL, total,
44fe82ebb0SRobert Mustacchi 	    spd_ddr5_nbytes_total_map, ARRAY_SIZE(spd_ddr5_nbytes_total_map));
45fe82ebb0SRobert Mustacchi }
46fe82ebb0SRobert Mustacchi 
47fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_mod_type_map[] = {
48fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_RDIMM, SPD_MOD_TYPE_RDIMM, false },
49fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_UDIMM, SPD_MOD_TYPE_UDIMM, false },
50fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_SODIMM, SPD_MOD_TYPE_SODIMM, false },
51fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_LRDIMM, SPD_MOD_TYPE_LRDIMM, false },
52*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_CUDIMM, SPD_MOD_TYPE_CUDIMM, false },
53*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_CSODIMM, SPD_MOD_TYPE_CSODIMM, false },
54fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_MRDIMM, SPD_MOD_TYPE_MRDIMM, false },
55*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_CAMM2, SPD_MOD_TYPE_CAMM2, false },
56fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_DDIMM, SPD_MOD_TYPE_DDIMM, false },
57fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_TYPE_SOLDER, SPD_MOD_TYPE_SOLDER, false }
58fe82ebb0SRobert Mustacchi };
59fe82ebb0SRobert Mustacchi 
60fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_mod_is_hybrid_map[] = {
61fe82ebb0SRobert Mustacchi 	{ 0, SPD_MOD_NOT_HYBRID, false },
62fe82ebb0SRobert Mustacchi 	{ 1, SPD_MOD_HYBRID_NVDIMMM, false }
63fe82ebb0SRobert Mustacchi };
64fe82ebb0SRobert Mustacchi 
65fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_mod_hybrid_map[] = {
66fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_N, SPD_MOD_TYPE_NVDIMM_N, false },
67fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_MOD_TYPE_HYBRID_NVDIMM_P, SPD_MOD_TYPE_NVDIMM_P, false }
68fe82ebb0SRobert Mustacchi };
69fe82ebb0SRobert Mustacchi 
70*8119dad8SRobert Mustacchi /*
71*8119dad8SRobert Mustacchi  * This is shared between DDR5 and LPDDR5 as they end up using the same
72*8119dad8SRobert Mustacchi  * definitions for module types.
73*8119dad8SRobert Mustacchi  */
74*8119dad8SRobert Mustacchi void
spd_parse_ddr5_mod_type(spd_info_t * si,uint32_t off,uint32_t len,const char * key)75fe82ebb0SRobert Mustacchi spd_parse_ddr5_mod_type(spd_info_t *si, uint32_t off, uint32_t len,
76fe82ebb0SRobert Mustacchi     const char *key)
77fe82ebb0SRobert Mustacchi {
78fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
79fe82ebb0SRobert Mustacchi 	const uint8_t type = SPD_DDR5_MOD_TYPE_TYPE(data);
80fe82ebb0SRobert Mustacchi 	const uint8_t is_hyb = SPD_DDR5_MOD_TYPE_ISHYBRID(data);
81fe82ebb0SRobert Mustacchi 	const uint8_t hybrid = SPD_DDR5_MOD_TYPE_HYBRID(data);
82fe82ebb0SRobert Mustacchi 
83fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_HYBRID_TYPE, is_hyb,
84fe82ebb0SRobert Mustacchi 	    spd_ddr5_mod_is_hybrid_map, ARRAY_SIZE(spd_ddr5_mod_is_hybrid_map));
85fe82ebb0SRobert Mustacchi 
86fe82ebb0SRobert Mustacchi 	if (is_hyb != 0) {
87fe82ebb0SRobert Mustacchi 		spd_insert_map(si, SPD_KEY_MOD_NVDIMM_TYPE, hybrid,
88fe82ebb0SRobert Mustacchi 		    spd_ddr5_mod_hybrid_map,
89fe82ebb0SRobert Mustacchi 		    ARRAY_SIZE(spd_ddr5_mod_hybrid_map));
90fe82ebb0SRobert Mustacchi 	}
91fe82ebb0SRobert Mustacchi 
92fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_TYPE, type, spd_ddr5_mod_type_map,
93fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mod_type_map));
94fe82ebb0SRobert Mustacchi }
95fe82ebb0SRobert Mustacchi 
96fe82ebb0SRobert Mustacchi static bool
spd_parse_ddr5_isassym(spd_info_t * si)97fe82ebb0SRobert Mustacchi spd_parse_ddr5_isassym(spd_info_t *si)
98fe82ebb0SRobert Mustacchi {
99fe82ebb0SRobert Mustacchi 	ASSERT3U(si->si_size, >, SPD_DDR5_COM_ORG);
100fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[SPD_DDR5_COM_ORG];
101fe82ebb0SRobert Mustacchi 	const uint8_t is_asym = SPD_DDR5_COM_ORG_MIX(data);
102fe82ebb0SRobert Mustacchi 
103fe82ebb0SRobert Mustacchi 	return (is_asym == SPD_DDR5_COM_ORG_MIX_ASYM);
104fe82ebb0SRobert Mustacchi }
105fe82ebb0SRobert Mustacchi 
106fe82ebb0SRobert Mustacchi static const spd_value_map64_t spd_ddr5_density_map[] = {
107fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_4Gb, 4ULL * 1024ULL * 1024ULL * 1024ULL, false },
108fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_8Gb, 8ULL * 1024ULL * 1024ULL * 1024ULL, false },
109fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_12Gb, 12ULL * 1024ULL * 1024ULL * 1024ULL,
110fe82ebb0SRobert Mustacchi 	    false },
111fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_16Gb, 16ULL * 1024ULL * 1024ULL * 1024ULL,
112fe82ebb0SRobert Mustacchi 	    false },
113fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_24Gb, 24ULL * 1024ULL * 1024ULL * 1024ULL,
114fe82ebb0SRobert Mustacchi 	    false },
115fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_32Gb, 32ULL * 1024ULL * 1024ULL * 1024ULL,
116fe82ebb0SRobert Mustacchi 	    false },
117fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_48Gb, 48ULL * 1024ULL * 1024ULL * 1024ULL,
118fe82ebb0SRobert Mustacchi 	    false },
119fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPD_64Gb, 64ULL * 1024ULL * 1024ULL * 1024ULL,
120fe82ebb0SRobert Mustacchi 	    false },
121fe82ebb0SRobert Mustacchi };
122fe82ebb0SRobert Mustacchi 
123fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_ndies_map[] = {
124fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_MONO, 1, false },
125fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_DDP, 2, false },
126fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_2H3DS, 2, false },
127fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_4H3DS, 4, false },
128fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_8H3DS, 8, false },
129fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_16H3DS, 16, false },
130fe82ebb0SRobert Mustacchi };
131fe82ebb0SRobert Mustacchi 
132fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_sl_map[] = {
133fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_MONO, SPD_SL_UNSPECIFIED, false },
134fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_DDP, SPD_SL_UNSPECIFIED, false },
135fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_2H3DS, SPD_SL_3DS, false },
136fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_4H3DS, SPD_SL_3DS, false },
137fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_8H3DS, SPD_SL_3DS, false },
138fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DENPKG_DPP_16H3DS, SPD_SL_3DS, false },
139fe82ebb0SRobert Mustacchi };
140fe82ebb0SRobert Mustacchi 
141fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_denpkg(spd_info_t * si,uint8_t data,const char * ndie_key,const char * den_key,const char * sl_key)142fe82ebb0SRobert Mustacchi spd_parse_ddr5_denpkg(spd_info_t *si, uint8_t data, const char *ndie_key,
143fe82ebb0SRobert Mustacchi     const char *den_key, const char *sl_key)
144fe82ebb0SRobert Mustacchi {
145fe82ebb0SRobert Mustacchi 	const uint8_t ndie = SPD_DDR5_DENPKG_DPP(data);
146fe82ebb0SRobert Mustacchi 	const uint8_t dens = SPD_DDR5_DENPKG_DPD(data);
147fe82ebb0SRobert Mustacchi 
148fe82ebb0SRobert Mustacchi 	spd_insert_map(si, ndie_key, ndie, spd_ddr5_ndies_map,
149fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ndies_map));
150fe82ebb0SRobert Mustacchi 	spd_insert_map(si, sl_key, ndie, spd_ddr5_sl_map,
151fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_sl_map));
152fe82ebb0SRobert Mustacchi 	spd_insert_map64(si, den_key, dens, spd_ddr5_density_map,
153fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_density_map));
154fe82ebb0SRobert Mustacchi }
155fe82ebb0SRobert Mustacchi 
156fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_denpkg_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)157fe82ebb0SRobert Mustacchi spd_parse_ddr5_denpkg_pri(spd_info_t *si, uint32_t off, uint32_t len,
158fe82ebb0SRobert Mustacchi     const char *key)
159fe82ebb0SRobert Mustacchi {
160fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_PKG_NDIE,
161fe82ebb0SRobert Mustacchi 	    SPD_KEY_DIE_SIZE, SPD_KEY_PKG_SL);
162fe82ebb0SRobert Mustacchi }
163fe82ebb0SRobert Mustacchi 
164fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_denpkg_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)165fe82ebb0SRobert Mustacchi spd_parse_ddr5_denpkg_sec(spd_info_t *si, uint32_t off, uint32_t len,
166fe82ebb0SRobert Mustacchi     const char *key)
167fe82ebb0SRobert Mustacchi {
168fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
169fe82ebb0SRobert Mustacchi 		return;
170fe82ebb0SRobert Mustacchi 
171fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_denpkg(si, si->si_data[off], SPD_KEY_SEC_PKG_NDIE,
172fe82ebb0SRobert Mustacchi 	    SPD_KEY_SEC_DIE_SIZE, SPD_KEY_SEC_PKG_SL);
173fe82ebb0SRobert Mustacchi }
174fe82ebb0SRobert Mustacchi 
175fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_nrow_range = {
176fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_ADDR_NROWS_MAX,
177fe82ebb0SRobert Mustacchi 	.svr_base = SPD_DDR5_ADDR_NROWS_BASE
178fe82ebb0SRobert Mustacchi };
179fe82ebb0SRobert Mustacchi 
180fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_ncol_range = {
181fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_ADDR_NCOLS_MAX,
182fe82ebb0SRobert Mustacchi 	.svr_base = SPD_DDR5_ADDR_NCOLS_BASE
183fe82ebb0SRobert Mustacchi };
184fe82ebb0SRobert Mustacchi 
185fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_addr(spd_info_t * si,uint8_t data,const char * row_key,const char * col_key)186fe82ebb0SRobert Mustacchi spd_parse_ddr5_addr(spd_info_t *si, uint8_t data, const char *row_key,
187fe82ebb0SRobert Mustacchi     const char *col_key)
188fe82ebb0SRobert Mustacchi {
189fe82ebb0SRobert Mustacchi 	const uint8_t ncols = SPD_DDR5_ADDR_NCOLS(data);
190fe82ebb0SRobert Mustacchi 	const uint8_t nrows = SPD_DDR5_ADDR_NROWS(data);
191fe82ebb0SRobert Mustacchi 
192fe82ebb0SRobert Mustacchi 	spd_insert_range(si, col_key, ncols, &spd_ddr5_ncol_range);
193fe82ebb0SRobert Mustacchi 	spd_insert_range(si, row_key, nrows, &spd_ddr5_nrow_range);
194fe82ebb0SRobert Mustacchi }
195fe82ebb0SRobert Mustacchi 
196fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_addr_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)197fe82ebb0SRobert Mustacchi spd_parse_ddr5_addr_pri(spd_info_t *si, uint32_t off, uint32_t len,
198fe82ebb0SRobert Mustacchi     const char *key)
199fe82ebb0SRobert Mustacchi {
200fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_NROW_BITS,
201fe82ebb0SRobert Mustacchi 	    SPD_KEY_NCOL_BITS);
202fe82ebb0SRobert Mustacchi }
203fe82ebb0SRobert Mustacchi 
204fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_addr_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)205fe82ebb0SRobert Mustacchi spd_parse_ddr5_addr_sec(spd_info_t *si, uint32_t off, uint32_t len,
206fe82ebb0SRobert Mustacchi     const char *key)
207fe82ebb0SRobert Mustacchi {
208fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
209fe82ebb0SRobert Mustacchi 		return;
210fe82ebb0SRobert Mustacchi 
211fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_addr(si, si->si_data[off], SPD_KEY_SEC_NROW_BITS,
212fe82ebb0SRobert Mustacchi 	    SPD_KEY_SEC_NCOL_BITS);
213fe82ebb0SRobert Mustacchi }
214fe82ebb0SRobert Mustacchi 
215fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_width_map[] = {
216fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_WIDTH_X4, 4, false },
217fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_WIDTH_X8, 8, false },
218fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_WIDTH_X16, 16, false },
219fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_WIDTH_X32, 32, false }
220fe82ebb0SRobert Mustacchi };
221fe82ebb0SRobert Mustacchi 
222fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_width(spd_info_t * si,uint8_t data,const char * key)223fe82ebb0SRobert Mustacchi spd_parse_ddr5_width(spd_info_t *si, uint8_t data, const char *key)
224fe82ebb0SRobert Mustacchi {
225fe82ebb0SRobert Mustacchi 	const uint8_t width = SPD_DDR5_WIDTH_WIDTH(data);
226fe82ebb0SRobert Mustacchi 
227fe82ebb0SRobert Mustacchi 	spd_insert_map(si, key, width, spd_ddr5_width_map,
228fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_width_map));
229fe82ebb0SRobert Mustacchi }
230fe82ebb0SRobert Mustacchi 
231fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_width_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)232fe82ebb0SRobert Mustacchi spd_parse_ddr5_width_pri(spd_info_t *si, uint32_t off, uint32_t len,
233fe82ebb0SRobert Mustacchi     const char *key)
234fe82ebb0SRobert Mustacchi {
235fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_DRAM_WIDTH);
236fe82ebb0SRobert Mustacchi }
237fe82ebb0SRobert Mustacchi 
238fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_width_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)239fe82ebb0SRobert Mustacchi spd_parse_ddr5_width_sec(spd_info_t *si, uint32_t off, uint32_t len,
240fe82ebb0SRobert Mustacchi     const char *key)
241fe82ebb0SRobert Mustacchi {
242fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
243fe82ebb0SRobert Mustacchi 		return;
244fe82ebb0SRobert Mustacchi 
245fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_width(si, si->si_data[off], SPD_KEY_SEC_DRAM_WIDTH);
246fe82ebb0SRobert Mustacchi }
247fe82ebb0SRobert Mustacchi 
248fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_nbg_range = {
249*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR5_BANKS_NBG_BITS_MAX
250fe82ebb0SRobert Mustacchi };
251fe82ebb0SRobert Mustacchi 
252fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_nba_range = {
253*8119dad8SRobert Mustacchi 	.svr_max = SPD_DDR5_BANKS_NBA_BITS_MAX
254fe82ebb0SRobert Mustacchi };
255fe82ebb0SRobert Mustacchi 
256fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_banks(spd_info_t * si,uint8_t data,const char * bg_key,const char * ba_key)257fe82ebb0SRobert Mustacchi spd_parse_ddr5_banks(spd_info_t *si, uint8_t data, const char *bg_key,
258fe82ebb0SRobert Mustacchi     const char *ba_key)
259fe82ebb0SRobert Mustacchi {
260*8119dad8SRobert Mustacchi 	const uint8_t nbg = SPD_DDR5_BANKS_NBG_BITS(data);
261*8119dad8SRobert Mustacchi 	const uint8_t nba = SPD_DDR5_BANKS_NBA_BITS(data);
262fe82ebb0SRobert Mustacchi 
263fe82ebb0SRobert Mustacchi 	spd_insert_range(si, bg_key, nbg, &spd_ddr5_nbg_range);
264fe82ebb0SRobert Mustacchi 	spd_insert_range(si, ba_key, nba, &spd_ddr5_nba_range);
265fe82ebb0SRobert Mustacchi }
266fe82ebb0SRobert Mustacchi 
267fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_banks_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)268fe82ebb0SRobert Mustacchi spd_parse_ddr5_banks_pri(spd_info_t *si, uint32_t off, uint32_t len,
269fe82ebb0SRobert Mustacchi     const char *key)
270fe82ebb0SRobert Mustacchi {
271fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_NBGRP_BITS,
272fe82ebb0SRobert Mustacchi 	    SPD_KEY_NBANK_BITS);
273fe82ebb0SRobert Mustacchi }
274fe82ebb0SRobert Mustacchi 
275fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_banks_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)276fe82ebb0SRobert Mustacchi spd_parse_ddr5_banks_sec(spd_info_t *si, uint32_t off, uint32_t len,
277fe82ebb0SRobert Mustacchi     const char *key)
278fe82ebb0SRobert Mustacchi {
279fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
280fe82ebb0SRobert Mustacchi 		return;
281fe82ebb0SRobert Mustacchi 
282fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_banks(si, si->si_data[off], SPD_KEY_SEC_NBGRP_BITS,
283fe82ebb0SRobert Mustacchi 	    SPD_KEY_SEC_NBANK_BITS);
284fe82ebb0SRobert Mustacchi }
285fe82ebb0SRobert Mustacchi 
286fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_ppr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)287fe82ebb0SRobert Mustacchi spd_parse_ddr5_ppr(spd_info_t *si, uint32_t off, uint32_t len,
288fe82ebb0SRobert Mustacchi     const char *key)
289fe82ebb0SRobert Mustacchi {
290fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
291fe82ebb0SRobert Mustacchi 	spd_ppr_flags_t flags = SPD_PPR_F_HARD_PPR | SPD_PPR_F_SOFT_PPR;
292fe82ebb0SRobert Mustacchi 
293fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_PPR_GRAN(data) == SPD_DDR5_PPR_GRAN_BGRP) {
294fe82ebb0SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN,
295fe82ebb0SRobert Mustacchi 		    SPD_PPR_GRAN_BANK_GROUP);
296fe82ebb0SRobert Mustacchi 	} else {
297fe82ebb0SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_PPR_GRAN,
298fe82ebb0SRobert Mustacchi 		    SPD_PPR_GRAN_BANK);
299fe82ebb0SRobert Mustacchi 	}
300fe82ebb0SRobert Mustacchi 
301fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_PPR_LOCK_SUP(data) != 0)
302fe82ebb0SRobert Mustacchi 		flags |= SPD_PPR_F_PPR_UNDO;
303fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_PPR_MPPR_SUP(data) != 0)
304fe82ebb0SRobert Mustacchi 		flags |= SPD_PPR_F_MBIST_PPR;
305fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_PPR, flags);
306fe82ebb0SRobert Mustacchi 
307fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_PPR_BL32_SUP(data) != 0)
308fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_BL32);
309fe82ebb0SRobert Mustacchi }
310fe82ebb0SRobert Mustacchi 
311fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_dca_map[] = {
312fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_SPD_DCA_TYPE_UNSUP, SPD_DCA_UNSPPORTED, false },
313fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_SPD_DCA_TYPE_1_2P, SPD_DCA_1_OR_2_PHASE, false },
314fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_SPD_DCA_TYPE_4P, SPD_DCA_4_PHASE, false }
315fe82ebb0SRobert Mustacchi };
316fe82ebb0SRobert Mustacchi 
317fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_dca(spd_info_t * si,uint32_t off,uint32_t len,const char * key)318fe82ebb0SRobert Mustacchi spd_parse_ddr5_dca(spd_info_t *si, uint32_t off, uint32_t len,
319fe82ebb0SRobert Mustacchi     const char *key)
320fe82ebb0SRobert Mustacchi {
321fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
322fe82ebb0SRobert Mustacchi 	const uint8_t dca = SPD_DDR5_SPD_DCA_TYPE(data);
323fe82ebb0SRobert Mustacchi 
324fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_SPD_DCA_PASR(data) != 0)
325*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR_PASR);
326fe82ebb0SRobert Mustacchi 
327fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_DCA, dca, spd_ddr5_dca_map,
328fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_dca_map));
329fe82ebb0SRobert Mustacchi }
330fe82ebb0SRobert Mustacchi 
331fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_flt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)332fe82ebb0SRobert Mustacchi spd_parse_ddr5_flt(spd_info_t *si, uint32_t off, uint32_t len,
333fe82ebb0SRobert Mustacchi     const char *key)
334fe82ebb0SRobert Mustacchi {
335fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
336fe82ebb0SRobert Mustacchi 	spd_fault_t flt = 0;
337fe82ebb0SRobert Mustacchi 
338fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_FLT_WIDE_TS(data) != 0)
339fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_WIDE_TS);
340fe82ebb0SRobert Mustacchi 
341fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_FLT_WBSUPR_SUP(data) != 0) {
342fe82ebb0SRobert Mustacchi 		if (SPD_DDR5_FLT_WBSUPR_SEL(data) ==
343fe82ebb0SRobert Mustacchi 		    SPD_DDR5_FLT_WBSUPR_SEL_MR15) {
344fe82ebb0SRobert Mustacchi 			flt |= SPD_FLT_WRSUP_MR15;
345fe82ebb0SRobert Mustacchi 		} else {
346fe82ebb0SRobert Mustacchi 			flt |= SPD_FLT_WRSUP_MR9;
347fe82ebb0SRobert Mustacchi 		}
348fe82ebb0SRobert Mustacchi 	}
349fe82ebb0SRobert Mustacchi 
350fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_FLT_BFLT(data))
351fe82ebb0SRobert Mustacchi 		flt |= SPD_FLT_BOUNDED;
352*8119dad8SRobert Mustacchi 	if (flt != 0)
353*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, SPD_KEY_DDR5_FLT, flt);
354fe82ebb0SRobert Mustacchi }
355fe82ebb0SRobert Mustacchi 
356fe82ebb0SRobert Mustacchi /*
357fe82ebb0SRobert Mustacchi  * Voltages support describing the nominal, operational, and endurant ranges.
358fe82ebb0SRobert Mustacchi  * Currently we only encode the nominal values.
359fe82ebb0SRobert Mustacchi  */
360fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_voltage(spd_info_t * si,uint8_t data,const char * key,uint32_t * mv,uint32_t nmv)361fe82ebb0SRobert Mustacchi spd_parse_ddr5_voltage(spd_info_t *si, uint8_t data, const char *key,
362fe82ebb0SRobert Mustacchi     uint32_t *mv, uint32_t nmv)
363fe82ebb0SRobert Mustacchi {
364fe82ebb0SRobert Mustacchi 	const uint8_t nom_idx = SPD_DDR5_DRAM_VOLT_NOM(data);
365fe82ebb0SRobert Mustacchi 
366fe82ebb0SRobert Mustacchi 	if (nom_idx >= nmv) {
367fe82ebb0SRobert Mustacchi 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
368fe82ebb0SRobert Mustacchi 		    "encountered unknown value: 0x%x", nom_idx);
369fe82ebb0SRobert Mustacchi 	} else {
370fe82ebb0SRobert Mustacchi 		spd_nvl_insert_u32_array(si, key, &mv[nom_idx], 1);
371fe82ebb0SRobert Mustacchi 	}
372fe82ebb0SRobert Mustacchi }
373fe82ebb0SRobert Mustacchi 
374fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_vdd(spd_info_t * si,uint32_t off,uint32_t len,const char * key)375fe82ebb0SRobert Mustacchi spd_parse_ddr5_vdd(spd_info_t *si, uint32_t off, uint32_t len,
376fe82ebb0SRobert Mustacchi     const char *key)
377fe82ebb0SRobert Mustacchi {
378fe82ebb0SRobert Mustacchi 	uint32_t volts[] = { 1100 };
379fe82ebb0SRobert Mustacchi 	return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts,
380fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(volts)));
381fe82ebb0SRobert Mustacchi }
382fe82ebb0SRobert Mustacchi 
383fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_vddq(spd_info_t * si,uint32_t off,uint32_t len,const char * key)384fe82ebb0SRobert Mustacchi spd_parse_ddr5_vddq(spd_info_t *si, uint32_t off, uint32_t len,
385fe82ebb0SRobert Mustacchi     const char *key)
386fe82ebb0SRobert Mustacchi {
387fe82ebb0SRobert Mustacchi 	uint32_t volts[] = { 1100 };
388fe82ebb0SRobert Mustacchi 	return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts,
389fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(volts)));
390fe82ebb0SRobert Mustacchi }
391fe82ebb0SRobert Mustacchi 
392fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_vpp(spd_info_t * si,uint32_t off,uint32_t len,const char * key)393fe82ebb0SRobert Mustacchi spd_parse_ddr5_vpp(spd_info_t *si, uint32_t off, uint32_t len,
394fe82ebb0SRobert Mustacchi     const char *key)
395fe82ebb0SRobert Mustacchi {
396fe82ebb0SRobert Mustacchi 	uint32_t volts[] = { 1800 };
397fe82ebb0SRobert Mustacchi 	return (spd_parse_ddr5_voltage(si, si->si_data[off], key, volts,
398fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(volts)));
399fe82ebb0SRobert Mustacchi }
400fe82ebb0SRobert Mustacchi 
401fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_time(spd_info_t * si,uint32_t off,uint32_t len,const char * key)402fe82ebb0SRobert Mustacchi spd_parse_ddr5_time(spd_info_t *si, uint32_t off, uint32_t len,
403fe82ebb0SRobert Mustacchi     const char *key)
404fe82ebb0SRobert Mustacchi {
405fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
406fe82ebb0SRobert Mustacchi 
407fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_TIME_STD(data) == SPD_DDR5_TIME_STD_NON)
408fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_NONSTD_TIME);
409fe82ebb0SRobert Mustacchi }
410fe82ebb0SRobert Mustacchi 
411fe82ebb0SRobert Mustacchi /*
412fe82ebb0SRobert Mustacchi  * Time in picoseconds. The LSB is at off. The MSB is at off + 1.
413fe82ebb0SRobert Mustacchi  */
414fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_ps(spd_info_t * si,uint32_t off,uint32_t len,const char * key)415fe82ebb0SRobert Mustacchi spd_parse_ddr5_ps(spd_info_t *si, uint32_t off, uint32_t len,
416fe82ebb0SRobert Mustacchi     const char *key)
417fe82ebb0SRobert Mustacchi {
418fe82ebb0SRobert Mustacchi 	uint64_t ps;
419fe82ebb0SRobert Mustacchi 
420fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 2);
421*8119dad8SRobert Mustacchi 	ps = (uint64_t)si->si_data[off];
422*8119dad8SRobert Mustacchi 	ps |= (uint64_t)si->si_data[off + 1] << 8;
423fe82ebb0SRobert Mustacchi 
424fe82ebb0SRobert Mustacchi 	if (ps == 0) {
425fe82ebb0SRobert Mustacchi 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
426fe82ebb0SRobert Mustacchi 		    "encountered unexpected zero time value");
427fe82ebb0SRobert Mustacchi 		return;
428fe82ebb0SRobert Mustacchi 	}
429fe82ebb0SRobert Mustacchi 
430fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u64(si, key, ps);
431fe82ebb0SRobert Mustacchi }
432fe82ebb0SRobert Mustacchi 
433fe82ebb0SRobert Mustacchi /*
434fe82ebb0SRobert Mustacchi  * Time in nanoseconds. The LSB is at off. The MSB is at off + 1. We normalize
435fe82ebb0SRobert Mustacchi  * all times to ps.
436fe82ebb0SRobert Mustacchi  */
437fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_ns(spd_info_t * si,uint32_t off,uint32_t len,const char * key)438fe82ebb0SRobert Mustacchi spd_parse_ddr5_ns(spd_info_t *si, uint32_t off, uint32_t len,
439fe82ebb0SRobert Mustacchi     const char *key)
440fe82ebb0SRobert Mustacchi {
441fe82ebb0SRobert Mustacchi 	uint64_t ns, ps;
442fe82ebb0SRobert Mustacchi 
443fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 2);
444*8119dad8SRobert Mustacchi 	ns = (uint64_t)si->si_data[off];
445*8119dad8SRobert Mustacchi 	ns |= (uint64_t)si->si_data[off + 1] << 8;
446fe82ebb0SRobert Mustacchi 
447fe82ebb0SRobert Mustacchi 	if (ns == 0) {
448fe82ebb0SRobert Mustacchi 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
449fe82ebb0SRobert Mustacchi 		    "encountered unexpected zero time value");
450fe82ebb0SRobert Mustacchi 		return;
451fe82ebb0SRobert Mustacchi 	}
452fe82ebb0SRobert Mustacchi 
453fe82ebb0SRobert Mustacchi 	ps = ns * 1000;
454fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u64(si, key, ps);
455fe82ebb0SRobert Mustacchi }
456fe82ebb0SRobert Mustacchi 
457fe82ebb0SRobert Mustacchi /*
458fe82ebb0SRobert Mustacchi  * Several DDR5 timing properties are only valid for 3DS type DIMMs. So we
459fe82ebb0SRobert Mustacchi  * double check the actual DIMM type before we proceed to parse this.
460fe82ebb0SRobert Mustacchi  */
461fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_3ds_ns(spd_info_t * si,uint32_t off,uint32_t len,const char * key)462fe82ebb0SRobert Mustacchi spd_parse_ddr5_3ds_ns(spd_info_t *si, uint32_t off, uint32_t len,
463fe82ebb0SRobert Mustacchi     const char *key)
464fe82ebb0SRobert Mustacchi {
465fe82ebb0SRobert Mustacchi 	ASSERT3U(off, >=, SPD_DDR5_DENPKG1);
466fe82ebb0SRobert Mustacchi 	uint32_t val;
467fe82ebb0SRobert Mustacchi 
468fe82ebb0SRobert Mustacchi 	if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_PKG_SL, &val) != 0 ||
469fe82ebb0SRobert Mustacchi 	    val != SPD_SL_3DS) {
470fe82ebb0SRobert Mustacchi 		return;
471fe82ebb0SRobert Mustacchi 	}
472fe82ebb0SRobert Mustacchi 
473fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_ns(si, off, len, key);
474fe82ebb0SRobert Mustacchi }
475fe82ebb0SRobert Mustacchi 
476fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_nck(spd_info_t * si,uint32_t off,uint32_t len,const char * key)477fe82ebb0SRobert Mustacchi spd_parse_ddr5_nck(spd_info_t *si, uint32_t off, uint32_t len,
478fe82ebb0SRobert Mustacchi     const char *key)
479fe82ebb0SRobert Mustacchi {
480fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
481fe82ebb0SRobert Mustacchi 
482fe82ebb0SRobert Mustacchi 	if (data == 0) {
483fe82ebb0SRobert Mustacchi 		spd_nvl_err(si, key, SPD_ERROR_NO_XLATE,
484fe82ebb0SRobert Mustacchi 		    "encountered unexpected zero clock value");
485fe82ebb0SRobert Mustacchi 		return;
486fe82ebb0SRobert Mustacchi 	}
487fe82ebb0SRobert Mustacchi 
488fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32(si, key, data);
489fe82ebb0SRobert Mustacchi }
490fe82ebb0SRobert Mustacchi 
491fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_cas(spd_info_t * si,uint32_t off,uint32_t len,const char * key)492fe82ebb0SRobert Mustacchi spd_parse_ddr5_cas(spd_info_t *si, uint32_t off, uint32_t len,
493fe82ebb0SRobert Mustacchi     const char *key)
494fe82ebb0SRobert Mustacchi {
495fe82ebb0SRobert Mustacchi 	uint32_t cas[40] = { 0 };
496fe82ebb0SRobert Mustacchi 	uint_t ncas = 0;
497fe82ebb0SRobert Mustacchi 	uint32_t cas_base = 20;
498fe82ebb0SRobert Mustacchi 
499fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 5);
500fe82ebb0SRobert Mustacchi 
501fe82ebb0SRobert Mustacchi 	for (uint32_t byte = 0; byte < len; byte++) {
502*8119dad8SRobert Mustacchi 		uint32_t data = si->si_data[off + byte];
503fe82ebb0SRobert Mustacchi 
504fe82ebb0SRobert Mustacchi 		for (uint32_t i = 0; i < NBBY; i++) {
505fe82ebb0SRobert Mustacchi 			if (bitx8(data, i, i) == 1) {
506fe82ebb0SRobert Mustacchi 				cas[ncas] = cas_base + 2 * (i + NBBY * byte);
507fe82ebb0SRobert Mustacchi 				ncas++;
508fe82ebb0SRobert Mustacchi 			}
509fe82ebb0SRobert Mustacchi 		}
510fe82ebb0SRobert Mustacchi 	}
511fe82ebb0SRobert Mustacchi 
512fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32_array(si, key, cas, ncas);
513fe82ebb0SRobert Mustacchi }
514fe82ebb0SRobert Mustacchi 
515fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_raammt_norm_range = {
516fe82ebb0SRobert Mustacchi 	.svr_min = SPD_DDR5_RFM0_RAAMMT_NORM_MIN,
517fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_RFM0_RAAMMT_NORM_MAX,
518fe82ebb0SRobert Mustacchi 	.svr_mult = SPD_DDR5_RFM0_RAAMMT_NORM_MULT
519fe82ebb0SRobert Mustacchi };
520fe82ebb0SRobert Mustacchi 
521fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_raammt_fgr_range = {
522fe82ebb0SRobert Mustacchi 	.svr_min = SPD_DDR5_RFM0_RAAMMT_FGR_MIN,
523fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_RFM0_RAAMMT_FGR_MAX,
524fe82ebb0SRobert Mustacchi 	.svr_mult = SPD_DDR5_RFM0_RAAMMT_FGR_MULT
525fe82ebb0SRobert Mustacchi };
526fe82ebb0SRobert Mustacchi 
527fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_raaimt_norm_range = {
528fe82ebb0SRobert Mustacchi 	.svr_min = SPD_DDR5_RFM0_RAAIMT_NORM_MIN,
529fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_RFM0_RAAIMT_NORM_MAX,
530fe82ebb0SRobert Mustacchi 	.svr_mult = SPD_DDR5_RFM0_RAAIMT_NORM_MULT
531fe82ebb0SRobert Mustacchi };
532fe82ebb0SRobert Mustacchi 
533fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_raaimt_fgr_range = {
534fe82ebb0SRobert Mustacchi 	.svr_min = SPD_DDR5_RFM0_RAAIMT_FGR_MIN,
535fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_RFM0_RAAIMT_FGR_MAX,
536fe82ebb0SRobert Mustacchi 	.svr_mult = SPD_DDR5_RFM0_RAAIMT_FGR_MULT
537fe82ebb0SRobert Mustacchi };
538fe82ebb0SRobert Mustacchi 
539fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_brc_cfg_range = {
540fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_RFM1_BRC_CFG_MAX,
541fe82ebb0SRobert Mustacchi 	.svr_base = SPD_DDR5_RFM1_BRC_CFG_BASE
542fe82ebb0SRobert Mustacchi };
543fe82ebb0SRobert Mustacchi 
544fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_raa_ctr_map[] = {
545fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RFM1_CTR_1X, 1, false },
546fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RFM1_CTR_2X, 2, false }
547fe82ebb0SRobert Mustacchi };
548fe82ebb0SRobert Mustacchi 
549fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rfm_flags(spd_info_t * si,uint8_t rfm0,uint8_t rfm1,const char * key)550fe82ebb0SRobert Mustacchi spd_parse_ddr5_rfm_flags(spd_info_t *si, uint8_t rfm0, uint8_t rfm1,
551fe82ebb0SRobert Mustacchi     const char *key)
552fe82ebb0SRobert Mustacchi {
553fe82ebb0SRobert Mustacchi 	spd_rfm_flags_t flags = 0;
554fe82ebb0SRobert Mustacchi 
555fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RFM0_RFM_REQ(rfm0) != 0)
556fe82ebb0SRobert Mustacchi 		flags |= SPD_RFM_F_REQUIRED;
557fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0)
558fe82ebb0SRobert Mustacchi 		flags |= SPD_RFM_F_DRFM_SUP;
559fe82ebb0SRobert Mustacchi 
560fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32(si, key, flags);
561fe82ebb0SRobert Mustacchi }
562fe82ebb0SRobert Mustacchi 
563fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_arfm_flags(spd_info_t * si,uint8_t rfm1,const char * key)564fe82ebb0SRobert Mustacchi spd_parse_ddr5_arfm_flags(spd_info_t *si, uint8_t rfm1, const char *key)
565fe82ebb0SRobert Mustacchi {
566fe82ebb0SRobert Mustacchi 	spd_rfm_flags_t flags = 0;
567fe82ebb0SRobert Mustacchi 
568fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0)
569fe82ebb0SRobert Mustacchi 		flags |= SPD_RFM_F_DRFM_SUP;
570fe82ebb0SRobert Mustacchi 
571fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32(si, key, flags);
572fe82ebb0SRobert Mustacchi }
573fe82ebb0SRobert Mustacchi 
574fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rfm_common(spd_info_t * si,uint8_t rfm0,uint8_t rfm1,const char * raaimt_key,const char * raaimt_fgr_key,const char * raammt_key,const char * raammt_fgr_key,const char * brc_cfg_key,const char * brc_sup_key,const char * raa_ctr_key)575fe82ebb0SRobert Mustacchi spd_parse_ddr5_rfm_common(spd_info_t *si, uint8_t rfm0, uint8_t rfm1,
576fe82ebb0SRobert Mustacchi     const char *raaimt_key, const char *raaimt_fgr_key, const char *raammt_key,
577fe82ebb0SRobert Mustacchi     const char *raammt_fgr_key, const char *brc_cfg_key,
578fe82ebb0SRobert Mustacchi     const char *brc_sup_key, const char *raa_ctr_key)
579fe82ebb0SRobert Mustacchi {
580fe82ebb0SRobert Mustacchi 	const uint8_t raammt = SPD_DDR5_RFM0_RAAMMT_NORM(rfm0);
581fe82ebb0SRobert Mustacchi 	const uint8_t raammt_fgr = SPD_DDR5_RFM0_RAAMMT_FGR(rfm0);
582fe82ebb0SRobert Mustacchi 	const uint8_t raaimt = SPD_DDR5_RFM0_RAAIMT_NORM(rfm0);
583fe82ebb0SRobert Mustacchi 	const uint8_t raaimt_fgr = SPD_DDR5_RFM0_RAAIMT_FGR(rfm0);
584fe82ebb0SRobert Mustacchi 	const uint8_t brc_cfg = SPD_DDR5_RFM1_BRC_CFG(rfm1);
585fe82ebb0SRobert Mustacchi 	const uint8_t brc_sup = SPD_DDR5_RFM1_BRC_SUP(rfm1);
586fe82ebb0SRobert Mustacchi 	const uint8_t raa_ctr = SPD_DDR5_RFM1_CTR(rfm1);
587fe82ebb0SRobert Mustacchi 	spd_brc_flags_t brc_flags = SPD_BRC_F_LVL_2;
588fe82ebb0SRobert Mustacchi 
589fe82ebb0SRobert Mustacchi 	if (brc_sup == SPD_DDR5_RFM1_BRC_SUP_234)
590fe82ebb0SRobert Mustacchi 		brc_flags |= SPD_BRC_F_LVL_3 | SPD_BRC_F_LVL_4;
591fe82ebb0SRobert Mustacchi 
592*8119dad8SRobert Mustacchi 	if (SPD_DDR5_RFM0_RFM_REQ(rfm0) != 0) {
593*8119dad8SRobert Mustacchi 		spd_insert_range(si, raaimt_key, raaimt,
594*8119dad8SRobert Mustacchi 		    &spd_ddr5_raaimt_norm_range);
595fe82ebb0SRobert Mustacchi 		spd_insert_range(si, raaimt_fgr_key, raaimt_fgr,
596fe82ebb0SRobert Mustacchi 		    &spd_ddr5_raaimt_fgr_range);
597*8119dad8SRobert Mustacchi 		spd_insert_range(si, raammt_key, raammt,
598*8119dad8SRobert Mustacchi 		    &spd_ddr5_raammt_norm_range);
599fe82ebb0SRobert Mustacchi 		spd_insert_range(si, raammt_fgr_key, raammt_fgr,
600fe82ebb0SRobert Mustacchi 		    &spd_ddr5_raammt_fgr_range);
601fe82ebb0SRobert Mustacchi 		spd_insert_map(si, raa_ctr_key, raa_ctr, spd_ddr5_raa_ctr_map,
602fe82ebb0SRobert Mustacchi 		    ARRAY_SIZE(spd_ddr5_raa_ctr_map));
603fe82ebb0SRobert Mustacchi 	}
604fe82ebb0SRobert Mustacchi 
605*8119dad8SRobert Mustacchi 	if (SPD_DDR5_RFM1_DRFM_SUP(rfm1) != 0) {
606*8119dad8SRobert Mustacchi 		spd_insert_range(si, brc_cfg_key, brc_cfg,
607*8119dad8SRobert Mustacchi 		    &spd_ddr5_brc_cfg_range);
608*8119dad8SRobert Mustacchi 		spd_nvl_insert_u32(si, brc_sup_key, brc_flags);
609*8119dad8SRobert Mustacchi 	}
610*8119dad8SRobert Mustacchi }
611*8119dad8SRobert Mustacchi 
612fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rfm_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)613fe82ebb0SRobert Mustacchi spd_parse_ddr5_rfm_pri(spd_info_t *si, uint32_t off, uint32_t len,
614fe82ebb0SRobert Mustacchi     const char *key)
615fe82ebb0SRobert Mustacchi {
616fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 2);
617fe82ebb0SRobert Mustacchi 
618fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1],
619fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_FLAGS_PRI);
620fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
621fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_RAAIMT_PRI, SPD_KEY_DDR5_RFM_RAAIMT_FGR_PRI,
622fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_RAAMMT_PRI, SPD_KEY_DDR5_RFM_RAAMMT_FGR_PRI,
623fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_BRC_CFG_PRI, SPD_KEY_DDR5_RFM_BRC_SUP_PRI,
624fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_RAA_DEC_PRI);
625fe82ebb0SRobert Mustacchi }
626fe82ebb0SRobert Mustacchi 
627fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rfm_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)628fe82ebb0SRobert Mustacchi spd_parse_ddr5_rfm_sec(spd_info_t *si, uint32_t off, uint32_t len,
629fe82ebb0SRobert Mustacchi     const char *key)
630fe82ebb0SRobert Mustacchi {
631fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
632fe82ebb0SRobert Mustacchi 		return;
633fe82ebb0SRobert Mustacchi 
634fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_flags(si, si->si_data[off], si->si_data[off + 1],
635fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_FLAGS_SEC);
636fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
637fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_RAAIMT_SEC, SPD_KEY_DDR5_RFM_RAAIMT_FGR_SEC,
638fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_RAAMMT_SEC, SPD_KEY_DDR5_RFM_RAAMMT_FGR_SEC,
639fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_BRC_CFG_SEC, SPD_KEY_DDR5_RFM_BRC_SUP_SEC,
640fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_RFM_RAA_DEC_SEC);
641fe82ebb0SRobert Mustacchi }
642fe82ebb0SRobert Mustacchi 
643fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_arfma_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)644fe82ebb0SRobert Mustacchi spd_parse_ddr5_arfma_pri(spd_info_t *si, uint32_t off, uint32_t len,
645fe82ebb0SRobert Mustacchi     const char *key)
646fe82ebb0SRobert Mustacchi {
647fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 2);
648fe82ebb0SRobert Mustacchi 
649fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
650fe82ebb0SRobert Mustacchi 		return;
651fe82ebb0SRobert Mustacchi 
652fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
653fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_FLAGS_PRI);
654fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
655fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_RAAIMT_PRI, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_PRI,
656fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_RAAMMT_PRI, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_PRI,
657fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMA_BRC_SUP_PRI,
658fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_RAA_DEC_PRI);
659fe82ebb0SRobert Mustacchi }
660fe82ebb0SRobert Mustacchi 
661fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_arfma_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)662fe82ebb0SRobert Mustacchi spd_parse_ddr5_arfma_sec(spd_info_t *si, uint32_t off, uint32_t len,
663fe82ebb0SRobert Mustacchi     const char *key)
664fe82ebb0SRobert Mustacchi {
665fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
666fe82ebb0SRobert Mustacchi 		return;
667fe82ebb0SRobert Mustacchi 
668fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
669fe82ebb0SRobert Mustacchi 		return;
670fe82ebb0SRobert Mustacchi 
671fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
672fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_FLAGS_SEC);
673fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
674fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_RAAIMT_SEC, SPD_KEY_DDR5_ARFMA_RAAIMT_FGR_SEC,
675fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_RAAMMT_SEC, SPD_KEY_DDR5_ARFMA_RAAMMT_FGR_SEC,
676fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMA_BRC_SUP_SEC,
677fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMA_RAA_DEC_SEC);
678fe82ebb0SRobert Mustacchi }
679fe82ebb0SRobert Mustacchi 
680fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_arfmb_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)681fe82ebb0SRobert Mustacchi spd_parse_ddr5_arfmb_pri(spd_info_t *si, uint32_t off, uint32_t len,
682fe82ebb0SRobert Mustacchi     const char *key)
683fe82ebb0SRobert Mustacchi {
684fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 2);
685fe82ebb0SRobert Mustacchi 
686fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
687fe82ebb0SRobert Mustacchi 		return;
688fe82ebb0SRobert Mustacchi 
689fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
690fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_FLAGS_PRI);
691fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
692fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_RAAIMT_PRI, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_PRI,
693fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_RAAMMT_PRI, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_PRI,
694fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMB_BRC_SUP_PRI,
695fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_RAA_DEC_PRI);
696fe82ebb0SRobert Mustacchi }
697fe82ebb0SRobert Mustacchi 
698fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_arfmb_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)699fe82ebb0SRobert Mustacchi spd_parse_ddr5_arfmb_sec(spd_info_t *si, uint32_t off, uint32_t len,
700fe82ebb0SRobert Mustacchi     const char *key)
701fe82ebb0SRobert Mustacchi {
702fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
703fe82ebb0SRobert Mustacchi 		return;
704fe82ebb0SRobert Mustacchi 
705fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
706fe82ebb0SRobert Mustacchi 		return;
707fe82ebb0SRobert Mustacchi 
708fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
709fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_FLAGS_SEC);
710fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
711fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_RAAIMT_SEC, SPD_KEY_DDR5_ARFMB_RAAIMT_FGR_SEC,
712fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_RAAMMT_SEC, SPD_KEY_DDR5_ARFMB_RAAMMT_FGR_SEC,
713fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMB_BRC_SUP_SEC,
714fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMB_RAA_DEC_SEC);
715fe82ebb0SRobert Mustacchi }
716fe82ebb0SRobert Mustacchi 
717fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_arfmc_pri(spd_info_t * si,uint32_t off,uint32_t len,const char * key)718fe82ebb0SRobert Mustacchi spd_parse_ddr5_arfmc_pri(spd_info_t *si, uint32_t off, uint32_t len,
719fe82ebb0SRobert Mustacchi     const char *key)
720fe82ebb0SRobert Mustacchi {
721fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 2);
722fe82ebb0SRobert Mustacchi 
723fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
724fe82ebb0SRobert Mustacchi 		return;
725fe82ebb0SRobert Mustacchi 
726fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
727fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_FLAGS_PRI);
728fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
729fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_RAAIMT_PRI, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_PRI,
730fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_RAAMMT_PRI, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_PRI,
731fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_BRC_CFG_PRI, SPD_KEY_DDR5_ARFMC_BRC_SUP_PRI,
732fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_RAA_DEC_PRI);
733fe82ebb0SRobert Mustacchi }
734fe82ebb0SRobert Mustacchi 
735fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_arfmc_sec(spd_info_t * si,uint32_t off,uint32_t len,const char * key)736fe82ebb0SRobert Mustacchi spd_parse_ddr5_arfmc_sec(spd_info_t *si, uint32_t off, uint32_t len,
737fe82ebb0SRobert Mustacchi     const char *key)
738fe82ebb0SRobert Mustacchi {
739fe82ebb0SRobert Mustacchi 	if (!spd_parse_ddr5_isassym(si))
740fe82ebb0SRobert Mustacchi 		return;
741fe82ebb0SRobert Mustacchi 
742fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_ARFM_SUP(si->si_data[off]) == 0)
743fe82ebb0SRobert Mustacchi 		return;
744fe82ebb0SRobert Mustacchi 
745fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_arfm_flags(si, si->si_data[off + 1],
746fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_FLAGS_SEC);
747fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_rfm_common(si, si->si_data[off], si->si_data[off + 1],
748fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_RAAIMT_SEC, SPD_KEY_DDR5_ARFMC_RAAIMT_FGR_SEC,
749fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_RAAMMT_SEC, SPD_KEY_DDR5_ARFMC_RAAMMT_FGR_SEC,
750fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_BRC_CFG_SEC, SPD_KEY_DDR5_ARFMC_BRC_SUP_SEC,
751fe82ebb0SRobert Mustacchi 	    SPD_KEY_DDR5_ARFMC_RAA_DEC_SEC);
752fe82ebb0SRobert Mustacchi }
753fe82ebb0SRobert Mustacchi 
754fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_base[] = {
755fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_NBYTES, .sp_parse = spd_parse_ddr5_nbytes },
756fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_SPD_REV, .sp_parse = spd_parse_rev },
757fe82ebb0SRobert Mustacchi 	/*
758fe82ebb0SRobert Mustacchi 	 * We have previously validated that the DRAM type is something that we
759fe82ebb0SRobert Mustacchi 	 * understand. We pass through the raw enum to users here.
760fe82ebb0SRobert Mustacchi 	 */
761fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DRAM_TYPE, .sp_key = SPD_KEY_DRAM_TYPE,
762fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_raw_u8 },
763fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_TYPE, .sp_parse = spd_parse_ddr5_mod_type },
764fe82ebb0SRobert Mustacchi 	/*
765fe82ebb0SRobert Mustacchi 	 * All secondary values must check whether an asymmetrical module is
766fe82ebb0SRobert Mustacchi 	 * present in Byte 234. As such, for the secondary versions we set LEN
767fe82ebb0SRobert Mustacchi 	 * to include that value. They then move to a common function.
768fe82ebb0SRobert Mustacchi 	 */
769fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DENPKG1, .sp_parse = spd_parse_ddr5_denpkg_pri },
770fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DENPKG2, .sp_parse = spd_parse_ddr5_denpkg_sec,
771fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_DENPKG2 + 1 },
772fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ADDR1, .sp_parse = spd_parse_ddr5_addr_pri },
773fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ADDR2, .sp_parse = spd_parse_ddr5_addr_sec,
774fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ADDR2 + 1 },
775fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_WIDTH1, .sp_parse = spd_parse_ddr5_width_pri },
776fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_WIDTH2, .sp_parse = spd_parse_ddr5_width_sec,
777fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_WIDTH2 + 1 },
778fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_BANKS1, .sp_parse = spd_parse_ddr5_banks_pri },
779fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_BANKS2, .sp_parse = spd_parse_ddr5_banks_sec,
780fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_BANKS2 + 1 },
781fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_PPR, .sp_parse = spd_parse_ddr5_ppr },
782fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_SDA, .sp_parse = spd_parse_ddr5_dca },
783fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_FLT, .sp_parse = spd_parse_ddr5_flt },
784fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DRAM_VDD, .sp_key = SPD_KEY_NOM_VDD,
785fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_vdd },
786fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DRAM_VDDQ, .sp_key = SPD_KEY_NOM_VDDQ,
787fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_vddq },
788fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DRAM_VPP, .sp_key = SPD_KEY_NOM_VPP,
789fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_vpp },
790fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TIME, .sp_parse = spd_parse_ddr5_time },
791fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCKAVG_MIN_LSB, .sp_len = 2,
792fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TCKAVG_MIN, .sp_parse = spd_parse_ddr5_ps },
793fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCKAVG_MAX_LSB, .sp_len = 2,
794fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TCKAVG_MAX, .sp_parse = spd_parse_ddr5_ps },
795fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_CAS_SUP0, .sp_len = 5, .sp_key = SPD_KEY_CAS,
796fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_cas },
797fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TAA_LSB, .sp_len = 2,
798fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TAA_MIN, .sp_parse = spd_parse_ddr5_ps },
799fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRCD_LSB, .sp_len = 2,
800fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRCD_MIN, .sp_parse = spd_parse_ddr5_ps },
801fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRP_LSB, .sp_len = 2,
802fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRP_MIN, .sp_parse = spd_parse_ddr5_ps },
803fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRAS_LSB, .sp_len = 2,
804fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRAS_MIN, .sp_parse = spd_parse_ddr5_ps },
805fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRC_LSB, .sp_len = 2,
806fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRC_MIN, .sp_parse = spd_parse_ddr5_ps },
807fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TWR_LSB, .sp_len = 2,
808fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TWR_MIN, .sp_parse = spd_parse_ddr5_ps },
809fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRFC1_LSB, .sp_len = 2,
810fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRFC1_MIN, .sp_parse = spd_parse_ddr5_ns },
811fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRFC2_LSB, .sp_len = 2,
812fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRFC2_MIN, .sp_parse = spd_parse_ddr5_ns },
813fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRFCSB_LSB, .sp_len = 2,
814fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRFCSB, .sp_parse = spd_parse_ddr5_ns },
815fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_3DS_TRFC1_LSB, .sp_len = 2,
816fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRFC1_DLR, .sp_parse = spd_parse_ddr5_3ds_ns },
817fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_3DS_TRFC2_LSB, .sp_len = 2,
818fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRFC2_DLR, .sp_parse = spd_parse_ddr5_3ds_ns },
819fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_3DS_TRFCSB_LSB, .sp_len = 2,
820fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRFCSB_DLR, .sp_parse = spd_parse_ddr5_3ds_ns },
821fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RFM0_SDRAM0, .sp_len = 2,
822fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rfm_pri },
823fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RFM0_SDRAM1, .sp_parse = spd_parse_ddr5_rfm_sec,
824fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_RFM0_SDRAM1 + 1 },
825fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ARFM0_A_SDRAM0, .sp_len = 2,
826fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_arfma_pri },
827fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ARFM0_A_SDRAM1,
828fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_A_SDRAM1 + 1,
829fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_arfma_sec },
830fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ARFM0_B_SDRAM0, .sp_len = 2,
831fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_arfmb_pri },
832fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ARFM0_B_SDRAM1,
833fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_B_SDRAM1 + 1,
834fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_arfmb_sec },
835fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ARFM0_C_SDRAM0, .sp_len = 2,
836fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_arfmc_pri },
837fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_ARFM0_C_SDRAM1,
838fe82ebb0SRobert Mustacchi 	    .sp_len = SPD_DDR5_COM_ORG - SPD_DDR5_ARFM0_C_SDRAM1 + 1,
839fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_arfmc_sec },
840fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRRD_L_LSB, .sp_len = 2,
841fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRRD_L_MIN, .sp_parse = spd_parse_ddr5_ps },
842*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRRD_L_NCK, .sp_key = SPD_KEY_TRRD_L_NCK,
843fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
844fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_LSB, .sp_len = 2,
845fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCD_L_MIN, .sp_parse = spd_parse_ddr5_ps },
846*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_NCK, .sp_key = SPD_KEY_TCCD_L_NCK,
847fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
848fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_WR_LSB, .sp_len = 2,
849fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCDLWR, .sp_parse = spd_parse_ddr5_ps },
850fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_WR_NCK, .sp_key = SPD_KEY_TCCDLWR_NCK,
851fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
852fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_WR2_LSB, .sp_len = 2,
853fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCDLWR2, .sp_parse = spd_parse_ddr5_ps },
854fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_WR2_NCK, .sp_key = SPD_KEY_TCCDLWR2_NCK,
855fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
856fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TFAW_LSB, .sp_len = 2,
857fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TFAW, .sp_parse = spd_parse_ddr5_ps },
858fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TFAW_NCK, .sp_key = SPD_KEY_TFAW_NCK,
859fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
860fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_WTR_LSB, .sp_len = 2,
861fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCDLWTR, .sp_parse = spd_parse_ddr5_ps },
862fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_L_WTR_NCK, .sp_key = SPD_KEY_TCCDLWTR_NCK,
863fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
864fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_S_WTR_LSB, .sp_len = 2,
865fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCDSWTR, .sp_parse = spd_parse_ddr5_ps },
866fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_S_WTR_NCK, .sp_key = SPD_KEY_TCCDSWTR_NCK,
867fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
868fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRTP_LSB, .sp_len = 2,
869fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_TRTP, .sp_parse = spd_parse_ddr5_ps },
870fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TRTP_NCK, .sp_key = SPD_KEY_TRTP_NCK,
871fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck }
872fe82ebb0SRobert Mustacchi };
873fe82ebb0SRobert Mustacchi 
874*8119dad8SRobert Mustacchi /*
875*8119dad8SRobert Mustacchi  * These are additional fields that were added in v1.2 of the SPD data.
876*8119dad8SRobert Mustacchi  */
877*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr5_base_1v2[] = {
878*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_M_LSB, .sp_len = 2,
879*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCDM, .sp_parse = spd_parse_ddr5_ps },
880*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_M_NCK, .sp_key = SPD_KEY_TCCDM_NCK,
881*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
882*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_M_WR_LSB, .sp_len = 2,
883*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCDMWR, .sp_parse = spd_parse_ddr5_ps },
884*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_M_WR_NCK, .sp_key = SPD_KEY_TCCDMWR_NCK,
885*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck },
886*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_M_WTR_LSB, .sp_len = 2,
887*8119dad8SRobert Mustacchi 	    .sp_key = SPD_KEY_TCCDMWTR, .sp_parse = spd_parse_ddr5_ps },
888*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_TCCD_M_WTR_NCK, .sp_key = SPD_KEY_TCCDMWTR_NCK,
889*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_nck }
890*8119dad8SRobert Mustacchi 
891*8119dad8SRobert Mustacchi };
892*8119dad8SRobert Mustacchi 
893fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_mod_rev(spd_info_t * si,uint32_t off,uint32_t len,const char * key)894fe82ebb0SRobert Mustacchi spd_parse_ddr5_mod_rev(spd_info_t *si, uint32_t off, uint32_t len,
895fe82ebb0SRobert Mustacchi     const char *key)
896fe82ebb0SRobert Mustacchi {
897fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
898fe82ebb0SRobert Mustacchi 	const uint8_t enc = SPD_DDR5_SPD_REV_ENC(data);
899*8119dad8SRobert Mustacchi 	const uint8_t add = SPD_DDR5_SPD_REV_ADD(data);
900fe82ebb0SRobert Mustacchi 
901fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ENC, enc);
902fe82ebb0SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_MOD_REV_ADD, add);
903fe82ebb0SRobert Mustacchi }
904fe82ebb0SRobert Mustacchi 
905fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_hash_map[] = {
906fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_HASH_NONE, 0, true },
907fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_HASH_ALG1, SPD_HASH_SEQ_ALG_1, false }
908fe82ebb0SRobert Mustacchi };
909fe82ebb0SRobert Mustacchi 
910fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_hash_seq(spd_info_t * si,uint32_t off,uint32_t len,const char * key)911fe82ebb0SRobert Mustacchi spd_parse_ddr5_hash_seq(spd_info_t *si, uint32_t off, uint32_t len,
912fe82ebb0SRobert Mustacchi     const char *key)
913fe82ebb0SRobert Mustacchi {
914fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
915fe82ebb0SRobert Mustacchi 	const uint8_t alg = SPD_DDR5_COM_HASH_HASH(data);
916fe82ebb0SRobert Mustacchi 
917fe82ebb0SRobert Mustacchi 	spd_insert_map(si, key, alg, spd_ddr5_hash_map,
918fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_hash_map));
919fe82ebb0SRobert Mustacchi }
920fe82ebb0SRobert Mustacchi 
921fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_dev_common(spd_info_t * si,uint32_t off,spd_device_t flags,const char * id_key,const char * id_str_key,const char * rev_key,const char * type_key,const spd_value_map_t * type_map,size_t ntypes)922fe82ebb0SRobert Mustacchi spd_parse_ddr5_dev_common(spd_info_t *si, uint32_t off, spd_device_t flags,
923fe82ebb0SRobert Mustacchi     const char *id_key, const char *id_str_key, const char *rev_key,
924fe82ebb0SRobert Mustacchi     const char *type_key, const spd_value_map_t *type_map, size_t ntypes)
925fe82ebb0SRobert Mustacchi {
926fe82ebb0SRobert Mustacchi 	const uint8_t type = SPD_DDR5_COM_INFO_TYPE(si->si_data[off + 2]);
927fe82ebb0SRobert Mustacchi 
928fe82ebb0SRobert Mustacchi 	spd_parse_jedec_id(si, off, 2, id_key);
929fe82ebb0SRobert Mustacchi 	spd_parse_jedec_id_str(si, off, 2, id_str_key);
930fe82ebb0SRobert Mustacchi 	spd_parse_hex_vers(si, off + 3, 1, rev_key);
931fe82ebb0SRobert Mustacchi 	spd_upsert_flag(si, SPD_KEY_DEVS, flags);
932fe82ebb0SRobert Mustacchi 	spd_insert_map(si, type_key, type, type_map, ntypes);
933fe82ebb0SRobert Mustacchi }
934fe82ebb0SRobert Mustacchi 
935fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_spd_type_map[] = {
936fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_SPD5118, SPD_SPD_T_SPD5118, false },
937fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_ESPD5216, SPD_SPD_T_ESPD5216, false }
938fe82ebb0SRobert Mustacchi };
939fe82ebb0SRobert Mustacchi 
940fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_spd(spd_info_t * si,uint32_t off,uint32_t len,const char * key)941fe82ebb0SRobert Mustacchi spd_parse_ddr5_spd(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
942fe82ebb0SRobert Mustacchi {
943fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
944fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
945fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
946fe82ebb0SRobert Mustacchi 		return;
947fe82ebb0SRobert Mustacchi 
948fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_SPD, SPD_KEY_DEV_SPD_MFG,
949fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_SPD_MFG_NAME, SPD_KEY_DEV_SPD_REV, SPD_KEY_DEV_SPD_TYPE,
950fe82ebb0SRobert Mustacchi 	    spd_ddr5_spd_type_map, ARRAY_SIZE(spd_ddr5_spd_type_map));
951fe82ebb0SRobert Mustacchi }
952fe82ebb0SRobert Mustacchi 
953fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_pmic_type_map[] = {
954fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5000, SPD_PMIC_T_PMIC5000, false },
955fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5010, SPD_PMIC_T_PMIC5010, false },
956fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5100, SPD_PMIC_T_PMIC5100, false },
957*8119dad8SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5020, SPD_PMIC_T_PMIC5020, false },
958*8119dad8SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5120, SPD_PMIC_T_PMIC5120, false },
959*8119dad8SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5200, SPD_PMIC_T_PMIC5200, false },
960*8119dad8SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_PMIC5030, SPD_PMIC_T_PMIC5030, false },
961fe82ebb0SRobert Mustacchi };
962fe82ebb0SRobert Mustacchi 
963fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_pmic0(spd_info_t * si,uint32_t off,uint32_t len,const char * key)964fe82ebb0SRobert Mustacchi spd_parse_ddr5_pmic0(spd_info_t *si, uint32_t off, uint32_t len,
965fe82ebb0SRobert Mustacchi     const char *key)
966fe82ebb0SRobert Mustacchi {
967fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
968fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
969fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
970fe82ebb0SRobert Mustacchi 		return;
971fe82ebb0SRobert Mustacchi 
972fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_0,
973fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_PMIC0_MFG, SPD_KEY_DEV_PMIC0_MFG_NAME,
974fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_PMIC0_REV, SPD_KEY_DEV_PMIC0_TYPE,
975fe82ebb0SRobert Mustacchi 	    spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map));
976fe82ebb0SRobert Mustacchi }
977fe82ebb0SRobert Mustacchi 
978fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_pmic1(spd_info_t * si,uint32_t off,uint32_t len,const char * key)979fe82ebb0SRobert Mustacchi spd_parse_ddr5_pmic1(spd_info_t *si, uint32_t off, uint32_t len,
980fe82ebb0SRobert Mustacchi     const char *key)
981fe82ebb0SRobert Mustacchi {
982fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
983fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
984fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
985fe82ebb0SRobert Mustacchi 		return;
986fe82ebb0SRobert Mustacchi 
987fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_1,
988fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_PMIC1_MFG, SPD_KEY_DEV_PMIC1_MFG_NAME,
989fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_PMIC1_REV, SPD_KEY_DEV_PMIC1_TYPE,
990fe82ebb0SRobert Mustacchi 	    spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map));
991fe82ebb0SRobert Mustacchi }
992fe82ebb0SRobert Mustacchi 
993fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_pmic2(spd_info_t * si,uint32_t off,uint32_t len,const char * key)994fe82ebb0SRobert Mustacchi spd_parse_ddr5_pmic2(spd_info_t *si, uint32_t off, uint32_t len,
995fe82ebb0SRobert Mustacchi     const char *key)
996fe82ebb0SRobert Mustacchi {
997fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
998fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
999fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1000fe82ebb0SRobert Mustacchi 		return;
1001fe82ebb0SRobert Mustacchi 
1002fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_PMIC_2,
1003fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_PMIC2_MFG, SPD_KEY_DEV_PMIC2_MFG_NAME,
1004fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_PMIC2_REV, SPD_KEY_DEV_PMIC2_TYPE,
1005fe82ebb0SRobert Mustacchi 	    spd_ddr5_pmic_type_map, ARRAY_SIZE(spd_ddr5_pmic_type_map));
1006fe82ebb0SRobert Mustacchi }
1007fe82ebb0SRobert Mustacchi 
1008fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_temp_type_map[] = {
1009fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_TS5111, SPD_TEMP_T_TS5111, false },
1010*8119dad8SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_TS5110, SPD_TEMP_T_TS5110, false },
1011*8119dad8SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_TS5211, SPD_TEMP_T_TS5211, false },
1012*8119dad8SRobert Mustacchi 	{ SPD_DDR5_COM_INFO_TYPE_TS5210, SPD_TEMP_T_TS5210, false }
1013fe82ebb0SRobert Mustacchi };
1014fe82ebb0SRobert Mustacchi 
1015fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_ts(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1016fe82ebb0SRobert Mustacchi spd_parse_ddr5_ts(spd_info_t *si, uint32_t off, uint32_t len, const char *key)
1017fe82ebb0SRobert Mustacchi {
1018fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1019fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1020fe82ebb0SRobert Mustacchi 	spd_device_t flags = 0;
1021fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) != 0)
1022fe82ebb0SRobert Mustacchi 		flags |= SPD_DEVICE_TEMP_1;
1023fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_TS1_PRES(type) != 0)
1024fe82ebb0SRobert Mustacchi 		flags |= SPD_DEVICE_TEMP_2;
1025fe82ebb0SRobert Mustacchi 	if (flags == 0)
1026fe82ebb0SRobert Mustacchi 		return;
1027fe82ebb0SRobert Mustacchi 
1028fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, flags, SPD_KEY_DEV_TEMP_MFG,
1029fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_TEMP_MFG_NAME, SPD_KEY_DEV_TEMP_REV,
1030fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_TEMP_TYPE, spd_ddr5_temp_type_map,
1031fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_temp_type_map));
1032fe82ebb0SRobert Mustacchi }
1033fe82ebb0SRobert Mustacchi 
1034*8119dad8SRobert Mustacchi /*
1035*8119dad8SRobert Mustacchi  * While DDR5 uses similar constants as earlier DDR standards, less values have
1036*8119dad8SRobert Mustacchi  * been officially defined yet so we use a different table from the others.
1037*8119dad8SRobert Mustacchi  */
1038fe82ebb0SRobert Mustacchi static const spd_str_map_t spd_ddr5_design_map[] = {
1039fe82ebb0SRobert Mustacchi 	{ 0, "A", false },
1040fe82ebb0SRobert Mustacchi 	{ 1, "B", false },
1041fe82ebb0SRobert Mustacchi 	{ 2, "C", false },
1042fe82ebb0SRobert Mustacchi 	{ 3, "D", false },
1043fe82ebb0SRobert Mustacchi 	{ 4, "E", false },
1044fe82ebb0SRobert Mustacchi 	{ 5, "F", false },
1045fe82ebb0SRobert Mustacchi 	{ 6, "G", false },
1046fe82ebb0SRobert Mustacchi 	{ 7, "H", false },
1047fe82ebb0SRobert Mustacchi 	{ 8, "J", false },
1048fe82ebb0SRobert Mustacchi 	{ 9, "K", false },
1049fe82ebb0SRobert Mustacchi 	{ 10, "L", false },
1050fe82ebb0SRobert Mustacchi 	{ 11, "M", false },
1051fe82ebb0SRobert Mustacchi 	{ 12, "N", false },
1052fe82ebb0SRobert Mustacchi 	{ 13, "P", false },
1053fe82ebb0SRobert Mustacchi 	{ 14, "R", false },
1054fe82ebb0SRobert Mustacchi 	{ 15, "T", false },
1055fe82ebb0SRobert Mustacchi 	{ 16, "U", false },
1056fe82ebb0SRobert Mustacchi 	{ 17, "V", false },
1057fe82ebb0SRobert Mustacchi 	{ 18, "W", false },
1058fe82ebb0SRobert Mustacchi 	{ 19, "Y", false },
1059fe82ebb0SRobert Mustacchi 	{ 20, "AA", false },
1060fe82ebb0SRobert Mustacchi 	{ 21, "AB", false },
1061fe82ebb0SRobert Mustacchi 	{ 22, "AC", false },
1062fe82ebb0SRobert Mustacchi 	{ 23, "AD", false },
1063fe82ebb0SRobert Mustacchi 	{ 24, "AE", false },
1064fe82ebb0SRobert Mustacchi 	{ 25, "AF", false },
1065fe82ebb0SRobert Mustacchi 	{ 26, "AG", false },
1066fe82ebb0SRobert Mustacchi 	{ 27, "AH", false },
1067fe82ebb0SRobert Mustacchi 	{ 28, "AJ", false },
1068fe82ebb0SRobert Mustacchi 	{ 29, "AK", false },
1069fe82ebb0SRobert Mustacchi 	{ 31, "ZZ", false }
1070fe82ebb0SRobert Mustacchi };
1071fe82ebb0SRobert Mustacchi 
1072fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_design_rev_range = {
1073fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_COM_REF_REV_MAX
1074fe82ebb0SRobert Mustacchi };
1075fe82ebb0SRobert Mustacchi 
1076fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_design(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1077fe82ebb0SRobert Mustacchi spd_parse_ddr5_design(spd_info_t *si, uint32_t off, uint32_t len,
1078fe82ebb0SRobert Mustacchi     const char *key)
1079fe82ebb0SRobert Mustacchi {
1080fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1081fe82ebb0SRobert Mustacchi 	const uint8_t rev = SPD_DDR5_COM_REF_REV(data);
1082*8119dad8SRobert Mustacchi 	const uint8_t card = SPD_DDR5_COM_REF_CARD(data);
1083fe82ebb0SRobert Mustacchi 
1084fe82ebb0SRobert Mustacchi 	spd_insert_str_map(si, SPD_KEY_MOD_REF_DESIGN, card,
1085fe82ebb0SRobert Mustacchi 	    spd_ddr5_design_map, ARRAY_SIZE(spd_ddr5_design_map));
1086fe82ebb0SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_MOD_DESIGN_REV, rev,
1087fe82ebb0SRobert Mustacchi 	    &spd_ddr5_design_rev_range);
1088fe82ebb0SRobert Mustacchi }
1089fe82ebb0SRobert Mustacchi 
1090fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_attr_nrows_map[] = {
1091fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_NROWS_UNDEF, 0, true },
1092fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_NROWS_1, 1, false },
1093fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_NROWS_2, 2, false }
1094fe82ebb0SRobert Mustacchi };
1095fe82ebb0SRobert Mustacchi 
1096fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_attr_otr_map[] = {
1097fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_A1T, JEDEC_TEMP_CASE_A1T, false },
1098fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_A2T, JEDEC_TEMP_CASE_A2T, false },
1099fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_A3T, JEDEC_TEMP_CASE_A3T, false },
1100fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_IT, JEDEC_TEMP_CASE_IT, false },
1101fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_ST, JEDEC_TEMP_CASE_ST, false },
1102fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_ET, JEDEC_TEMP_CASE_ET, false },
1103fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_RT, JEDEC_TEMP_CASE_RT, false },
1104fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_NT, JEDEC_TEMP_CASE_NT, false },
1105fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_ATTR_OTR_XT, JEDEC_TEMP_CASE_XT, false }
1106fe82ebb0SRobert Mustacchi };
1107fe82ebb0SRobert Mustacchi 
1108fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_attr(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1109fe82ebb0SRobert Mustacchi spd_parse_ddr5_attr(spd_info_t *si, uint32_t off, uint32_t len,
1110fe82ebb0SRobert Mustacchi     const char *key)
1111fe82ebb0SRobert Mustacchi {
1112fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1113fe82ebb0SRobert Mustacchi 	const uint8_t otr = SPD_DDR5_COM_ATTR_OTR(data);
1114fe82ebb0SRobert Mustacchi 	const uint8_t nrows = SPD_DDR5_COM_ATTR_NROWS(data);
1115fe82ebb0SRobert Mustacchi 
1116fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_ATTR_SPREAD(data) != 0)
1117fe82ebb0SRobert Mustacchi 		spd_upsert_flag(si, SPD_KEY_DEVS, SPD_DEVICE_HS);
1118fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_NROWS, nrows,
1119fe82ebb0SRobert Mustacchi 	    spd_ddr5_attr_nrows_map, ARRAY_SIZE(spd_ddr5_attr_nrows_map));
1120fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_MOD_OPER_TEMP, otr,
1121fe82ebb0SRobert Mustacchi 	    spd_ddr5_attr_otr_map, ARRAY_SIZE(spd_ddr5_attr_otr_map));
1122fe82ebb0SRobert Mustacchi }
1123fe82ebb0SRobert Mustacchi 
1124fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_nrank_range = {
1125fe82ebb0SRobert Mustacchi 	.svr_base = SPD_DDR5_COM_ORG_NRANK_BASE
1126fe82ebb0SRobert Mustacchi };
1127fe82ebb0SRobert Mustacchi 
1128fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_mod_org(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1129fe82ebb0SRobert Mustacchi spd_parse_ddr5_mod_org(spd_info_t *si, uint32_t off, uint32_t len,
1130fe82ebb0SRobert Mustacchi     const char *key)
1131fe82ebb0SRobert Mustacchi {
1132fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1133fe82ebb0SRobert Mustacchi 	const uint8_t nranks = SPD_DDR4_MOD_ORG_NPKG_RANK(data);
1134fe82ebb0SRobert Mustacchi 
1135fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_ORG_MIX(data) == SPD_DDR5_COM_ORG_MIX_ASYM)
1136fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_RANK_ASYM);
1137fe82ebb0SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_NRANKS, nranks, &spd_ddr5_nrank_range);
1138fe82ebb0SRobert Mustacchi }
1139fe82ebb0SRobert Mustacchi 
1140fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_ext_width[] = {
1141fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_BUS_WIDTH_EXT_NONE, 0, false },
1142fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_BUS_WIDTH_EXT_4b, 4, false },
1143fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_BUS_WIDTH_EXT_8b, 8, false }
1144fe82ebb0SRobert Mustacchi };
1145fe82ebb0SRobert Mustacchi 
1146fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_pri_width[] = {
1147fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_8b, 8, false },
1148fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_16b, 16, false },
1149fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_32b, 32, false },
1150fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_COM_BUS_WIDTH_PRI_64b, 64, false },
1151fe82ebb0SRobert Mustacchi };
1152fe82ebb0SRobert Mustacchi 
1153fe82ebb0SRobert Mustacchi static const spd_value_range_t spd_ddr5_nsc_range = {
1154fe82ebb0SRobert Mustacchi 	.svr_max = SPD_DDR5_COM_BUS_WIDTH_NSC_MAX,
1155*8119dad8SRobert Mustacchi 	.svr_exp = true
1156fe82ebb0SRobert Mustacchi };
1157fe82ebb0SRobert Mustacchi 
1158fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_bus_width(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1159fe82ebb0SRobert Mustacchi spd_parse_ddr5_bus_width(spd_info_t *si, uint32_t off, uint32_t len,
1160fe82ebb0SRobert Mustacchi     const char *key)
1161fe82ebb0SRobert Mustacchi {
1162fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1163fe82ebb0SRobert Mustacchi 	const uint8_t nsc = SPD_DDR5_COM_BUS_WIDTH_NSC(data);
1164fe82ebb0SRobert Mustacchi 	const uint8_t ext = SPD_DDR5_COM_BUS_WIDTH_EXT(data);
1165fe82ebb0SRobert Mustacchi 	const uint8_t pri = SPD_DDR5_COM_BUS_WIDTH_PRI(data);
1166fe82ebb0SRobert Mustacchi 
1167fe82ebb0SRobert Mustacchi 	spd_insert_range(si, SPD_KEY_NSUBCHAN, nsc, &spd_ddr5_nsc_range);
1168*8119dad8SRobert Mustacchi 	spd_nvl_insert_u32(si, SPD_KEY_DRAM_NCHAN, 1);
1169fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_ECC_WIDTH, ext, spd_ddr5_ext_width,
1170fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ext_width));
1171fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DATA_WIDTH, pri, spd_ddr5_pri_width,
1172fe82ebb0SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_pri_width));
1173fe82ebb0SRobert Mustacchi }
1174fe82ebb0SRobert Mustacchi 
1175fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_module[] = {
1176fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_REV, .sp_parse = spd_parse_ddr5_mod_rev },
1177fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_HASH, .sp_parse = spd_parse_ddr5_hash_seq,
1178fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_HASH_SEQ },
1179fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_SPD, .sp_len = 4,
1180fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_spd },
1181fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC0, .sp_len = 4,
1182fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_pmic0 },
1183fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC1, .sp_len = 4,
1184fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_pmic1 },
1185fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_PMIC2, .sp_len = 4,
1186fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_pmic2 },
1187fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4,
1188fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_ts },
1189fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_HEIGHT, .sp_key = SPD_KEY_MOD_HEIGHT,
1190fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_height },
1191fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_THICK, .sp_parse = spd_parse_thickness },
1192fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_REF, .sp_parse = spd_parse_ddr5_design },
1193fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_ATTR, .sp_parse = spd_parse_ddr5_attr },
1194fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_ORG, .sp_parse = spd_parse_ddr5_mod_org },
1195fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_BUS_WIDTH,
1196fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_bus_width },
1197fe82ebb0SRobert Mustacchi 	/* We include the DDR5 CRC in this group as it's considered common */
1198fe82ebb0SRobert Mustacchi 	{ .sp_len = SPD_DDR5_CRC_MSB + 1, .sp_key = SPD_KEY_CRC_DDR5,
1199fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_crc },
1200fe82ebb0SRobert Mustacchi };
1201fe82ebb0SRobert Mustacchi 
1202fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_mfg[] = {
1203fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2,
1204fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_MFG_ID, .sp_parse = spd_parse_jedec_id },
1205fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_MFG_ID0, .sp_len = 2,
1206fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_MFG_NAME,
1207fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id_str },
1208fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2,
1209fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_ID, .sp_parse = spd_parse_jedec_id },
1210fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DRAM_MFG_ID0, .sp_len = 2,
1211fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_DRAM_MFG_NAME,
1212fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_jedec_id_str },
1213fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_MFG_LOC, .sp_key = SPD_KEY_MFG_MOD_LOC_ID,
1214fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_raw_u8 },
1215fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_MFG_YEAR, .sp_key = SPD_KEY_MFG_MOD_YEAR,
1216fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_hex_string },
1217fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_MFG_WEEK, .sp_key = SPD_KEY_MFG_MOD_WEEK,
1218fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_hex_string },
1219fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_SN, .sp_len = SPD_DDR5_MOD_SN_LEN,
1220fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_SN, .sp_parse = spd_parse_hex_string },
1221fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_PN, .sp_len = SPD_DDR5_MOD_PN_LEN,
1222fe82ebb0SRobert Mustacchi 	    .sp_key = SPD_KEY_MFG_MOD_PN, .sp_parse = spd_parse_string },
1223fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MOD_REV, .sp_key = SPD_KEY_MFG_MOD_REV,
1224fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_dram_step },
1225fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DRAM_STEP, .sp_key = SPD_KEY_MFG_DRAM_STEP,
1226fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_dram_step }
1227fe82ebb0SRobert Mustacchi };
1228fe82ebb0SRobert Mustacchi 
1229fe82ebb0SRobert Mustacchi /*
1230fe82ebb0SRobert Mustacchi  * Annex A.2 UDIMM and SODIMM specific processing.
1231fe82ebb0SRobert Mustacchi  */
1232fe82ebb0SRobert Mustacchi 
1233fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_cd_type_map[] = {
1234fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_UDIMM_INFO_TYPE_DDR5CK01, SPD_CD_T_DDR5CK01, false }
1235fe82ebb0SRobert Mustacchi };
1236fe82ebb0SRobert Mustacchi 
1237fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_udimm_cd(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1238fe82ebb0SRobert Mustacchi spd_parse_ddr5_udimm_cd(spd_info_t *si, uint32_t off, uint32_t len,
1239fe82ebb0SRobert Mustacchi     const char *key)
1240fe82ebb0SRobert Mustacchi {
1241fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1242fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1243fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1244fe82ebb0SRobert Mustacchi 		return;
1245fe82ebb0SRobert Mustacchi 
1246*8119dad8SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_0,
1247*8119dad8SRobert Mustacchi 	    SPD_KEY_DEV_CD0_MFG, SPD_KEY_DEV_CD0_MFG_NAME,
1248*8119dad8SRobert Mustacchi 	    SPD_KEY_DEV_CD0_REV, SPD_KEY_DEV_CD0_TYPE,
1249fe82ebb0SRobert Mustacchi 	    spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map));
1250fe82ebb0SRobert Mustacchi }
1251fe82ebb0SRobert Mustacchi 
1252*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_udimm_ckd_cfg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1253*8119dad8SRobert Mustacchi spd_parse_ddr5_udimm_ckd_cfg(spd_info_t *si, uint32_t off, uint32_t len,
1254*8119dad8SRobert Mustacchi     const char *key)
1255*8119dad8SRobert Mustacchi {
1256*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1257*8119dad8SRobert Mustacchi 
1258*8119dad8SRobert Mustacchi 	if (SPD_DDR5_UDIMM_CKD_CFG_CHAQCK0(data) == 0)
1259*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHAQCK0_EN);
1260*8119dad8SRobert Mustacchi 	if (SPD_DDR5_UDIMM_CKD_CFG_CHAQCK1(data) == 0)
1261*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHAQCK1_EN);
1262*8119dad8SRobert Mustacchi 	if (SPD_DDR5_UDIMM_CKD_CFG_CHBQCK0(data) == 0)
1263*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHBQCK0_EN);
1264*8119dad8SRobert Mustacchi 	if (SPD_DDR5_UDIMM_CKD_CFG_CHBQCK1(data) == 0)
1265*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_CKD_CHBQCK1_EN);
1266*8119dad8SRobert Mustacchi }
1267*8119dad8SRobert Mustacchi 
1268*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_ckd_ds_map[] = {
1269*8119dad8SRobert Mustacchi 	{ SPD_DDR5_UDIMM_CKD_DRV_LIGHT, SPD_DRIVE_LIGHT, false },
1270*8119dad8SRobert Mustacchi 	{ SPD_DDR5_UDIMM_CKD_DRV_MODERATE, SPD_DRIVE_MODERATE, false },
1271*8119dad8SRobert Mustacchi 	{ SPD_DDR5_UDIMM_CKD_DRV_STRONG, SPD_DRIVE_STRONG, false },
1272*8119dad8SRobert Mustacchi 	{ SPD_DDR5_UDIMM_CKD_DRV_WEAK, SPD_DRIVE_WEAK, false }
1273*8119dad8SRobert Mustacchi };
1274*8119dad8SRobert Mustacchi 
1275*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_udimm_ckd_drv(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1276*8119dad8SRobert Mustacchi spd_parse_ddr5_udimm_ckd_drv(spd_info_t *si, uint32_t off, uint32_t len,
1277*8119dad8SRobert Mustacchi     const char *key)
1278*8119dad8SRobert Mustacchi {
1279*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1280*8119dad8SRobert Mustacchi 	const uint8_t qck0a = SPD_DDR5_UDIMM_CKD_DRV_CHAQCK0_DRIVE(data);
1281*8119dad8SRobert Mustacchi 	const uint8_t qck1a = SPD_DDR5_UDIMM_CKD_DRV_CHAQCK1_DRIVE(data);
1282*8119dad8SRobert Mustacchi 	const uint8_t qck0b = SPD_DDR5_UDIMM_CKD_DRV_CHBQCK0_DRIVE(data);
1283*8119dad8SRobert Mustacchi 	const uint8_t qck1b = SPD_DDR5_UDIMM_CKD_DRV_CHBQCK1_DRIVE(data);
1284*8119dad8SRobert Mustacchi 
1285*8119dad8SRobert Mustacchi 
1286*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_CKD_CHAQCK0_DS, qck0a,
1287*8119dad8SRobert Mustacchi 	    spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1288*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_CKD_CHAQCK1_DS, qck1a,
1289*8119dad8SRobert Mustacchi 	    spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1290*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_CKD_CHBQCK0_DS, qck0b,
1291*8119dad8SRobert Mustacchi 	    spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1292*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_CKD_CHBQCK1_DS, qck1b,
1293*8119dad8SRobert Mustacchi 	    spd_ddr5_ckd_ds_map, ARRAY_SIZE(spd_ddr5_ckd_ds_map));
1294*8119dad8SRobert Mustacchi }
1295*8119dad8SRobert Mustacchi 
1296*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_ckd_slew_map[] = {
1297*8119dad8SRobert Mustacchi 	{ SPD_DDR5_UDIMM_CKD_SLEW_SLEW_MODERATE, SPD_SLEW_MODERATE, false },
1298*8119dad8SRobert Mustacchi 	{ SPD_DDR5_UDIMM_CKD_SLEW_SLEW_FAST, SPD_SLEW_FAST, false }
1299*8119dad8SRobert Mustacchi };
1300*8119dad8SRobert Mustacchi 
1301*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_udimm_ckd_slew(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1302*8119dad8SRobert Mustacchi spd_parse_ddr5_udimm_ckd_slew(spd_info_t *si, uint32_t off, uint32_t len,
1303*8119dad8SRobert Mustacchi     const char *key)
1304*8119dad8SRobert Mustacchi {
1305*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1306*8119dad8SRobert Mustacchi 	const uint8_t qcka = SPD_DDR5_UDIMM_CKD_SLEW_CHAQCK_SLEW(data);
1307*8119dad8SRobert Mustacchi 	const uint8_t qckb = SPD_DDR5_UDIMM_CKD_SLEW_CHBQCK_SLEW(data);
1308*8119dad8SRobert Mustacchi 
1309*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_CKD_CHAQCK_SLEW, qcka,
1310*8119dad8SRobert Mustacchi 	    spd_ddr5_ckd_slew_map, ARRAY_SIZE(spd_ddr5_ckd_slew_map));
1311*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_CKD_CHBQCK_SLEW, qckb,
1312*8119dad8SRobert Mustacchi 	    spd_ddr5_ckd_slew_map, ARRAY_SIZE(spd_ddr5_ckd_slew_map));
1313*8119dad8SRobert Mustacchi }
1314*8119dad8SRobert Mustacchi 
1315fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_udimm[] = {
1316fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_COM_MFG_ID0_TS, .sp_len = 4,
1317fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_udimm_cd }
1318fe82ebb0SRobert Mustacchi };
1319fe82ebb0SRobert Mustacchi 
1320*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr5_udimm_1v1[] = {
1321*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_UDIMM_CKD_CFG,
1322*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_udimm_ckd_cfg },
1323*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_UDIMM_CKD_DRV,
1324*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_udimm_ckd_drv },
1325*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_UDIMM_CKD_SLEW,
1326*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_udimm_ckd_slew }
1327*8119dad8SRobert Mustacchi };
1328*8119dad8SRobert Mustacchi 
1329fe82ebb0SRobert Mustacchi /*
1330fe82ebb0SRobert Mustacchi  * Annex A.3 RDIMM and LRDIMM specific processing. Because certain fields are
1331fe82ebb0SRobert Mustacchi  * LRDIMM-only, we use two different top-level tables to drive them; however,
1332fe82ebb0SRobert Mustacchi  * they generally overlap otherwise. Items that are LRDIMM only will contain
1333fe82ebb0SRobert Mustacchi  * lrdimm in the name. All items named rdimm are shared between both the LRDIMM
1334fe82ebb0SRobert Mustacchi  * and RDIMM processing.
1335fe82ebb0SRobert Mustacchi  */
1336fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_rcd_type_map[] = {
1337fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD01, SPD_RCD_T_DDR5RCD01, false },
1338fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD02, SPD_RCD_T_DDR5RCD02, false },
1339*8119dad8SRobert Mustacchi 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD03, SPD_RCD_T_DDR5RCD03, false },
1340*8119dad8SRobert Mustacchi 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD04, SPD_RCD_T_DDR5RCD04, false },
1341*8119dad8SRobert Mustacchi 	{ SPD_DDR5_RDIMM_INFO_TYPE_RCD05, SPD_RCD_T_DDR5RCD05, false }
1342fe82ebb0SRobert Mustacchi };
1343fe82ebb0SRobert Mustacchi 
1344fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_db_type_map[] = {
1345fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RDIMM_INFO_TYPE_DB01, SPD_DB_T_DDR5DB01, false },
1346fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RDIMM_INFO_TYPE_DB02, SPD_DB_T_DDR5DB02, false }
1347fe82ebb0SRobert Mustacchi };
1348fe82ebb0SRobert Mustacchi 
1349fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rdimm_rcd(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1350fe82ebb0SRobert Mustacchi spd_parse_ddr5_rdimm_rcd(spd_info_t *si, uint32_t off, uint32_t len,
1351fe82ebb0SRobert Mustacchi     const char *key)
1352fe82ebb0SRobert Mustacchi {
1353fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1354fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1355fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1356fe82ebb0SRobert Mustacchi 		return;
1357fe82ebb0SRobert Mustacchi 
1358fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_RCD,
1359fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_RCD_MFG, SPD_KEY_DEV_RCD_MFG_NAME,
1360fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_RCD_REV, SPD_KEY_DEV_RCD_TYPE,
1361fe82ebb0SRobert Mustacchi 	    spd_ddr5_rcd_type_map, ARRAY_SIZE(spd_ddr5_rcd_type_map));
1362fe82ebb0SRobert Mustacchi }
1363fe82ebb0SRobert Mustacchi 
1364fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_lrdimm_db(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1365fe82ebb0SRobert Mustacchi spd_parse_ddr5_lrdimm_db(spd_info_t *si, uint32_t off, uint32_t len,
1366fe82ebb0SRobert Mustacchi     const char *key)
1367fe82ebb0SRobert Mustacchi {
1368fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1369fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1370fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1371fe82ebb0SRobert Mustacchi 		return;
1372fe82ebb0SRobert Mustacchi 
1373fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DB,
1374fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_DB_MFG, SPD_KEY_DEV_DB_MFG_NAME,
1375fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_DB_REV, SPD_KEY_DEV_DB_TYPE,
1376fe82ebb0SRobert Mustacchi 	    spd_ddr5_db_type_map, ARRAY_SIZE(spd_ddr5_db_type_map));
1377fe82ebb0SRobert Mustacchi }
1378fe82ebb0SRobert Mustacchi 
1379fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rdimm_clken(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1380fe82ebb0SRobert Mustacchi spd_parse_ddr5_rdimm_clken(spd_info_t *si, uint32_t off, uint32_t len,
1381fe82ebb0SRobert Mustacchi     const char *key)
1382fe82ebb0SRobert Mustacchi {
1383fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1384fe82ebb0SRobert Mustacchi 
1385fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_CLKEN_QACK(data) == 0)
1386fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACK_EN);
1387fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_CLKEN_QBCK(data) == 0)
1388fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCK_EN);
1389fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_CLKEN_QCCK(data) == 0)
1390fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QCCK_EN);
1391fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_CLKEN_QDCK(data) == 0)
1392fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QDCK_EN);
1393fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_CLKEN_BCK(data) == 0)
1394fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCK_EN);
1395fe82ebb0SRobert Mustacchi }
1396fe82ebb0SRobert Mustacchi 
1397fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rdimm_rwen(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1398fe82ebb0SRobert Mustacchi spd_parse_ddr5_rdimm_rwen(spd_info_t *si, uint32_t off, uint32_t len,
1399fe82ebb0SRobert Mustacchi     const char *key)
1400fe82ebb0SRobert Mustacchi {
1401fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1402fe82ebb0SRobert Mustacchi 
1403fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_RW09_QBCS(data) == 0)
1404fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCS_EN);
1405fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_RW09_QACS(data) == 0)
1406fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACS_EN);
1407fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_RW09_QXCA13(data) == 0)
1408fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QxCA13_EN);
1409fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_RW09_BCS(data) == 0)
1410fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_BCS_EN);
1411fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_RW09_DCS(data) == 0)
1412*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QxCS_EN);
1413fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_RW09_QBCA(data) == 0)
1414fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QBCA_EN);
1415fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_RDIMM_RW09_QACA(data) == 0)
1416fe82ebb0SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_RCD_QACA_EN);
1417fe82ebb0SRobert Mustacchi }
1418fe82ebb0SRobert Mustacchi 
1419*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_ds_map[] = {
1420*8119dad8SRobert Mustacchi 	{ SPD_DDR5_RDIMM_DRV_LIGHT, SPD_DRIVE_LIGHT, false },
1421*8119dad8SRobert Mustacchi 	{ SPD_DDR5_RDIMM_DRV_MODERATE, SPD_DRIVE_MODERATE, false },
1422*8119dad8SRobert Mustacchi 	{ SPD_DDR5_RDIMM_DRV_STRONG, SPD_DRIVE_STRONG, false }
1423fe82ebb0SRobert Mustacchi };
1424fe82ebb0SRobert Mustacchi 
1425fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rdimm_clkimp(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1426fe82ebb0SRobert Mustacchi spd_parse_ddr5_rdimm_clkimp(spd_info_t *si, uint32_t off, uint32_t len,
1427fe82ebb0SRobert Mustacchi     const char *key)
1428fe82ebb0SRobert Mustacchi {
1429fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1430fe82ebb0SRobert Mustacchi 	const uint8_t qack = SPD_DDR5_RDIMM_QCK_DRV_QACK(data);
1431fe82ebb0SRobert Mustacchi 	const uint8_t qbck = SPD_DDR5_RDIMM_QCK_DRV_QBCK(data);
1432fe82ebb0SRobert Mustacchi 	const uint8_t qcck = SPD_DDR5_RDIMM_QCK_DRV_QCCK(data);
1433fe82ebb0SRobert Mustacchi 	const uint8_t qdck = SPD_DDR5_RDIMM_QCK_DRV_QDCK(data);
1434fe82ebb0SRobert Mustacchi 
1435*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QACK_DS, qack, spd_ddr5_ds_map,
1436*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1437*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QBCK_DS, qbck, spd_ddr5_ds_map,
1438*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1439*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCCK_DS, qcck, spd_ddr5_ds_map,
1440*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1441*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QDCK_DS, qdck, spd_ddr5_ds_map,
1442*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1443fe82ebb0SRobert Mustacchi }
1444fe82ebb0SRobert Mustacchi 
1445fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rdimm_casimp(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1446fe82ebb0SRobert Mustacchi spd_parse_ddr5_rdimm_casimp(spd_info_t *si, uint32_t off, uint32_t len,
1447fe82ebb0SRobert Mustacchi     const char *key)
1448fe82ebb0SRobert Mustacchi {
1449fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1450fe82ebb0SRobert Mustacchi 	const uint8_t cs = SPD_DDR5_RDIMM_QCA_DRV_CS(data);
1451fe82ebb0SRobert Mustacchi 	const uint8_t ca = SPD_DDR5_RDIMM_QCA_DRV_CA(data);
1452fe82ebb0SRobert Mustacchi 
1453*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QxCS_DS, cs, spd_ddr5_ds_map,
1454*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1455*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_CA_DS, ca, spd_ddr5_ds_map,
1456*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1457fe82ebb0SRobert Mustacchi }
1458fe82ebb0SRobert Mustacchi 
1459fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_lrdimm_dbimp(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1460fe82ebb0SRobert Mustacchi spd_parse_ddr5_lrdimm_dbimp(spd_info_t *si, uint32_t off, uint32_t len,
1461fe82ebb0SRobert Mustacchi     const char *key)
1462fe82ebb0SRobert Mustacchi {
1463fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1464fe82ebb0SRobert Mustacchi 	const uint8_t bck = SPD_DDR5_LRDIMM_DB_DRV_BCK(data);
1465fe82ebb0SRobert Mustacchi 	const uint8_t bcom = SPD_DDR5_LRDIMM_DB_DRV_BCOM(data);
1466fe82ebb0SRobert Mustacchi 
1467*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_DS, bck, spd_ddr5_ds_map,
1468*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1469*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_DS, bcom, spd_ddr5_ds_map,
1470*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_ds_map));
1471fe82ebb0SRobert Mustacchi }
1472fe82ebb0SRobert Mustacchi 
1473*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_rcd_slew_map[] = {
1474fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false },
1475fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RDIMM_SLEW_FAST, SPD_SLEW_FAST, false },
1476fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_RDIMM_SLEW_SLOW, SPD_SLEW_SLOW, false }
1477fe82ebb0SRobert Mustacchi };
1478fe82ebb0SRobert Mustacchi 
1479fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_rdimm_qslew(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1480fe82ebb0SRobert Mustacchi spd_parse_ddr5_rdimm_qslew(spd_info_t *si, uint32_t off, uint32_t len,
1481fe82ebb0SRobert Mustacchi     const char *key)
1482fe82ebb0SRobert Mustacchi {
1483fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1484fe82ebb0SRobert Mustacchi 	const uint8_t qcs = SPD_DDR5_RDIMM_QXX_SLEW_QCS(data);
1485fe82ebb0SRobert Mustacchi 	const uint8_t qca = SPD_DDR5_RDIMM_QXX_SLEW_QCA(data);
1486fe82ebb0SRobert Mustacchi 	const uint8_t qck = SPD_DDR5_RDIMM_QXX_SLEW_QCK(data);
1487fe82ebb0SRobert Mustacchi 
1488*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCK_SLEW, qck,
1489*8119dad8SRobert Mustacchi 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1490*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCA_SLEW, qca,
1491*8119dad8SRobert Mustacchi 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1492*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCS_SLEW, qcs,
1493*8119dad8SRobert Mustacchi 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1494fe82ebb0SRobert Mustacchi }
1495fe82ebb0SRobert Mustacchi 
1496fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_lrdimm_bslew(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1497fe82ebb0SRobert Mustacchi spd_parse_ddr5_lrdimm_bslew(spd_info_t *si, uint32_t off, uint32_t len,
1498fe82ebb0SRobert Mustacchi     const char *key)
1499fe82ebb0SRobert Mustacchi {
1500fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1501fe82ebb0SRobert Mustacchi 	const uint8_t bck = SPD_DDR5_LRDIMM_BXX_SLEW_BCK(data);
1502fe82ebb0SRobert Mustacchi 	const uint8_t bcom = SPD_DDR5_LRDIMM_BXX_SLEW_BCOM(data);
1503fe82ebb0SRobert Mustacchi 
1504*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCK_SLEW, bck,
1505*8119dad8SRobert Mustacchi 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1506fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_BCOM_SLEW, bcom,
1507*8119dad8SRobert Mustacchi 	    spd_ddr5_rcd_slew_map, ARRAY_SIZE(spd_ddr5_rcd_slew_map));
1508fe82ebb0SRobert Mustacchi }
1509fe82ebb0SRobert Mustacchi 
1510fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_rtt_term_map[] = {
1511fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_OFF, 0, true },
1512fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_240R, 240, false },
1513fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_120R, 120, false },
1514fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_80R, 80, false },
1515fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_60R, 60, false },
1516fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_48R, 48, false },
1517fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_40R, 40, false },
1518fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_LDRIMM_PARK_34R, 34, false }
1519fe82ebb0SRobert Mustacchi };
1520fe82ebb0SRobert Mustacchi 
1521fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_lrdimm_rtt(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1522fe82ebb0SRobert Mustacchi spd_parse_ddr5_lrdimm_rtt(spd_info_t *si, uint32_t off, uint32_t len,
1523fe82ebb0SRobert Mustacchi     const char *key)
1524fe82ebb0SRobert Mustacchi {
1525fe82ebb0SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1526fe82ebb0SRobert Mustacchi 	const uint8_t rtt = SPD_DDR5_LRDIMM_PARK_TERM(data);
1527fe82ebb0SRobert Mustacchi 
1528fe82ebb0SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_RTT_TERM, rtt,
1529fe82ebb0SRobert Mustacchi 	    spd_ddr5_rtt_term_map, ARRAY_SIZE(spd_ddr5_rtt_term_map));
1530fe82ebb0SRobert Mustacchi }
1531fe82ebb0SRobert Mustacchi 
1532fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_rdimm[] = {
1533fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4,
1534fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_rcd },
1535fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_CLKEN,
1536fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_clken },
1537fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_RW09,
1538fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_rwen },
1539fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_QCK_DRV,
1540fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_clkimp },
1541fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_QCA_DRV,
1542fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_casimp },
1543fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_QXX_SLEW,
1544fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_qslew }
1545fe82ebb0SRobert Mustacchi };
1546fe82ebb0SRobert Mustacchi 
1547fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_lrdimm[] = {
1548fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_MFG_ID0_RCD, .sp_len = 4,
1549fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_rcd },
1550fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_MFG_ID0_DB, .sp_len = 4,
1551fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_lrdimm_db },
1552fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_CLKEN,
1553fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_clken },
1554fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_RW09,
1555fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_rwen },
1556fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_QCK_DRV,
1557fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_clkimp },
1558fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_QCA_DRV,
1559fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_casimp },
1560fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_LRDIMM_DB_DRV,
1561fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_lrdimm_dbimp },
1562fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_RDIMM_QXX_SLEW,
1563fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_rdimm_qslew },
1564fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_LRDIMM_BXX_SLEW,
1565fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_lrdimm_bslew },
1566fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_LRDIMM_PARK,
1567fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_lrdimm_rtt },
1568fe82ebb0SRobert Mustacchi };
1569fe82ebb0SRobert Mustacchi 
1570fe82ebb0SRobert Mustacchi /*
1571fe82ebb0SRobert Mustacchi  * Annex A.4 MRDIMM specific processing.
1572fe82ebb0SRobert Mustacchi  */
1573fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_mrcd_type_map[] = {
1574*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MRCD01, SPD_MRCD_T_DDR5MRCD01, false },
1575*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MRCD02, SPD_MRCD_T_DDR5MRCD02, false }
1576fe82ebb0SRobert Mustacchi };
1577fe82ebb0SRobert Mustacchi 
1578fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_mdb_type_map[] = {
1579*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MDB01, SPD_MDB_T_DDR5MDB01, false },
1580*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_INFO_TYPE_MDB02, SPD_MDB_T_DDR5MDB02, false }
1581fe82ebb0SRobert Mustacchi };
1582fe82ebb0SRobert Mustacchi 
1583fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_mrcd(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1584fe82ebb0SRobert Mustacchi spd_parse_ddr5_mrdimm_mrcd(spd_info_t *si, uint32_t off, uint32_t len,
1585fe82ebb0SRobert Mustacchi     const char *key)
1586fe82ebb0SRobert Mustacchi {
1587fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1588fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1589fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1590fe82ebb0SRobert Mustacchi 		return;
1591fe82ebb0SRobert Mustacchi 
1592fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MRCD,
1593fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_MRCD_MFG, SPD_KEY_DEV_MRCD_MFG_NAME,
1594fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_MRCD_REV, SPD_KEY_DEV_MRCD_TYPE,
1595fe82ebb0SRobert Mustacchi 	    spd_ddr5_mrcd_type_map, ARRAY_SIZE(spd_ddr5_mrcd_type_map));
1596fe82ebb0SRobert Mustacchi }
1597fe82ebb0SRobert Mustacchi 
1598fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_mdb(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1599fe82ebb0SRobert Mustacchi spd_parse_ddr5_mrdimm_mdb(spd_info_t *si, uint32_t off, uint32_t len,
1600fe82ebb0SRobert Mustacchi     const char *key)
1601fe82ebb0SRobert Mustacchi {
1602fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1603fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1604fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1605fe82ebb0SRobert Mustacchi 		return;
1606fe82ebb0SRobert Mustacchi 
1607fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_MDB,
1608fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_MDB_MFG, SPD_KEY_DEV_MDB_MFG_NAME,
1609fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_MDB_REV, SPD_KEY_DEV_MDB_TYPE,
1610fe82ebb0SRobert Mustacchi 	    spd_ddr5_mdb_type_map, ARRAY_SIZE(spd_ddr5_mdb_type_map));
1611fe82ebb0SRobert Mustacchi }
1612fe82ebb0SRobert Mustacchi 
1613fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_mrdimm[] = {
1614fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MRCD, .sp_len = 4,
1615fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_mrcd },
1616fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_MFG_ID0_MDB, .sp_len = 4,
1617fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_mdb }
1618fe82ebb0SRobert Mustacchi };
1619fe82ebb0SRobert Mustacchi 
1620*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_cden(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1621*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_cden(spd_info_t *si, uint32_t off, uint32_t len,
1622*8119dad8SRobert Mustacchi     const char *key)
1623*8119dad8SRobert Mustacchi {
1624*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1625*8119dad8SRobert Mustacchi 
1626*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QACK(data) == 0)
1627*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACK_EN);
1628*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QBCK(data) == 0)
1629*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCK_EN);
1630*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QCCK(data) == 0)
1631*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QCCK_EN);
1632*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QDCK(data) == 0)
1633*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QDCK_EN);
1634*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_BCK(data) == 0)
1635*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_BCK_EN);
1636*8119dad8SRobert Mustacchi }
1637*8119dad8SRobert Mustacchi 
1638*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_oacen(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1639*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_oacen(spd_info_t *si, uint32_t off, uint32_t len,
1640*8119dad8SRobert Mustacchi     const char *key)
1641*8119dad8SRobert Mustacchi {
1642*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1643*8119dad8SRobert Mustacchi 
1644*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QACA(data) == 0)
1645*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACA_EN);
1646*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QBCA(data) == 0)
1647*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCA_EN);
1648*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QxCS1(data) == 0)
1649*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QxCS_EN);
1650*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_BCS(data) == 0)
1651*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_BCS_EN);
1652*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QCA13(data) == 0)
1653*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QxCA13_EN);
1654*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QACS(data) == 0)
1655*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QACS_EN);
1656*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_QBCS(data) == 0)
1657*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_QBCS_EN);
1658*8119dad8SRobert Mustacchi 	if (SPD_DDR5_MRDIMM_CDEN_DCS1(data) == 0)
1659*8119dad8SRobert Mustacchi 		spd_nvl_insert_key(si, SPD_KEY_DDR5_MRCD_DCS1_EN);
1660*8119dad8SRobert Mustacchi }
1661*8119dad8SRobert Mustacchi 
1662*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_mrcd_ds_map[] = {
1663*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_DRV_LIGHT, SPD_DRIVE_LIGHT, false },
1664*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_DRV_MODERATE, SPD_DRIVE_MODERATE, false },
1665*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_DRV_STRONG, SPD_DRIVE_STRONG, false }
1666*8119dad8SRobert Mustacchi };
1667*8119dad8SRobert Mustacchi 
1668*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_qck_drv(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1669*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_qck_drv(spd_info_t *si, uint32_t off, uint32_t len,
1670*8119dad8SRobert Mustacchi     const char *key)
1671*8119dad8SRobert Mustacchi {
1672*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1673*8119dad8SRobert Mustacchi 	const uint8_t qack = SPD_DDR5_MRDIMM_QCK_DRV_QACK(data);
1674*8119dad8SRobert Mustacchi 	const uint8_t qbck = SPD_DDR5_MRDIMM_QCK_DRV_QBCK(data);
1675*8119dad8SRobert Mustacchi 	const uint8_t qcck = SPD_DDR5_MRDIMM_QCK_DRV_QCCK(data);
1676*8119dad8SRobert Mustacchi 	const uint8_t qdck = SPD_DDR5_MRDIMM_QCK_DRV_QDCK(data);
1677*8119dad8SRobert Mustacchi 
1678*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QACK_DS, qack, spd_ddr5_mrcd_ds_map,
1679*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1680*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QBCK_DS, qbck, spd_ddr5_mrcd_ds_map,
1681*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1682*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QCCK_DS, qcck, spd_ddr5_mrcd_ds_map,
1683*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1684*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_RCD_QDCK_DS, qdck, spd_ddr5_mrcd_ds_map,
1685*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1686*8119dad8SRobert Mustacchi 
1687*8119dad8SRobert Mustacchi }
1688*8119dad8SRobert Mustacchi 
1689*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_mrcd_out[] = {
1690*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_NORM, SPD_MRCD_OUT_NORMAL, false },
1691*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_DIS, SPD_MRCD_OUT_DISABLED, false },
1692*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT_LOW, SPD_MRCD_OUT_LOW, false }
1693*8119dad8SRobert Mustacchi };
1694*8119dad8SRobert Mustacchi 
1695*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_qca_drv(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1696*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_qca_drv(spd_info_t *si, uint32_t off, uint32_t len,
1697*8119dad8SRobert Mustacchi     const char *key)
1698*8119dad8SRobert Mustacchi {
1699*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1700*8119dad8SRobert Mustacchi 	const uint8_t cs = SPD_DDR5_MRDIMM_QCA_DRV_CS(data);
1701*8119dad8SRobert Mustacchi 	const uint8_t ca = SPD_DDR5_MRDIMM_QCA_DRV_CA(data);
1702*8119dad8SRobert Mustacchi 	const uint8_t out = SPD_DDR5_MRDIMM_QCA_DRV_QCS1_OUT(data);
1703*8119dad8SRobert Mustacchi 
1704*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QxCS_DS, cs, spd_ddr5_mrcd_ds_map,
1705*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1706*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_CA_DS, ca, spd_ddr5_mrcd_ds_map,
1707*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1708*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QxCS_OUT, out, spd_ddr5_mrcd_out,
1709*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_out));
1710*8119dad8SRobert Mustacchi }
1711*8119dad8SRobert Mustacchi 
1712*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_db_drv(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1713*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_db_drv(spd_info_t *si, uint32_t off, uint32_t len,
1714*8119dad8SRobert Mustacchi     const char *key)
1715*8119dad8SRobert Mustacchi {
1716*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1717*8119dad8SRobert Mustacchi 	const uint8_t bck = SPD_DDR5_MRDIMM_DB_DRV_BCK(data);
1718*8119dad8SRobert Mustacchi 	const uint8_t bcom = SPD_DDR5_MRDIMM_DB_DRV_BCOM(data);
1719*8119dad8SRobert Mustacchi 
1720*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCK_DS, bck, spd_ddr5_mrcd_ds_map,
1721*8119dad8SRobert Mustacchi 	    ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1722*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCOM_DS, bcom,
1723*8119dad8SRobert Mustacchi 	    spd_ddr5_mrcd_ds_map, ARRAY_SIZE(spd_ddr5_mrcd_ds_map));
1724*8119dad8SRobert Mustacchi }
1725*8119dad8SRobert Mustacchi 
1726*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_mrcd_slew_map[] = {
1727*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_SLEW_MODERTE, SPD_SLEW_MODERATE, false },
1728*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_SLEW_FAST, SPD_SLEW_FAST, false },
1729*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_SLEW_SLOW, SPD_SLEW_SLOW, false }
1730*8119dad8SRobert Mustacchi };
1731*8119dad8SRobert Mustacchi 
1732*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_qxx_slew(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1733*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_qxx_slew(spd_info_t *si, uint32_t off, uint32_t len,
1734*8119dad8SRobert Mustacchi     const char *key)
1735*8119dad8SRobert Mustacchi {
1736*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1737*8119dad8SRobert Mustacchi 	const uint8_t qcs = SPD_DDR5_MRDIMM_QXX_SLEW_QCS(data);
1738*8119dad8SRobert Mustacchi 	const uint8_t qca = SPD_DDR5_MRDIMM_QXX_SLEW_QCA(data);
1739*8119dad8SRobert Mustacchi 	const uint8_t qck = SPD_DDR5_MRDIMM_QXX_SLEW_QCK(data);
1740*8119dad8SRobert Mustacchi 
1741*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCK_SLEW, qck,
1742*8119dad8SRobert Mustacchi 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1743*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCA_SLEW, qca,
1744*8119dad8SRobert Mustacchi 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1745*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_QCS_SLEW, qcs,
1746*8119dad8SRobert Mustacchi 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1747*8119dad8SRobert Mustacchi }
1748*8119dad8SRobert Mustacchi 
1749*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_bxx_slew(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1750*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_bxx_slew(spd_info_t *si, uint32_t off, uint32_t len,
1751*8119dad8SRobert Mustacchi     const char *key)
1752*8119dad8SRobert Mustacchi {
1753*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1754*8119dad8SRobert Mustacchi 	const uint8_t bck = SPD_DDR5_MRDIMM_BXX_SLEW_BCK(data);
1755*8119dad8SRobert Mustacchi 	const uint8_t bcom = SPD_DDR5_MRDIMM_BXX_SLEW_BCOM(data);
1756*8119dad8SRobert Mustacchi 
1757*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCK_SLEW, bck,
1758*8119dad8SRobert Mustacchi 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1759*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_BCOM_SLEW, bcom,
1760*8119dad8SRobert Mustacchi 	    spd_ddr5_mrcd_slew_map, ARRAY_SIZE(spd_ddr5_mrcd_slew_map));
1761*8119dad8SRobert Mustacchi 
1762*8119dad8SRobert Mustacchi }
1763*8119dad8SRobert Mustacchi 
1764*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_mrcd_dca_map[] = {
1765*8119dad8SRobert Mustacchi 	{ 0, SPD_MRCD_DCA_CFG_0, false },
1766*8119dad8SRobert Mustacchi 	{ 1, SPD_MRCD_DCA_CFG_1, false }
1767*8119dad8SRobert Mustacchi };
1768*8119dad8SRobert Mustacchi 
1769*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_dca_cfg(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1770*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_dca_cfg(spd_info_t *si, uint32_t off, uint32_t len,
1771*8119dad8SRobert Mustacchi     const char *key)
1772*8119dad8SRobert Mustacchi {
1773*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1774*8119dad8SRobert Mustacchi 	const uint8_t cfg = SPD_DDR5_MRDIMM_DCA_CFG_CFG(data);
1775*8119dad8SRobert Mustacchi 
1776*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRCD_DCA_CFG, cfg,
1777*8119dad8SRobert Mustacchi 	    spd_ddr5_mrcd_dca_map, ARRAY_SIZE(spd_ddr5_mrcd_dca_map));
1778*8119dad8SRobert Mustacchi }
1779*8119dad8SRobert Mustacchi 
1780*8119dad8SRobert Mustacchi static const spd_value_map_t spd_ddr5_mrdimm_irxt_map[] = {
1781*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_IRXTYPE_TYPE_UNMATCHED, SPD_MRDIMM_IRXT_UNMATCHED,
1782*8119dad8SRobert Mustacchi 	    false },
1783*8119dad8SRobert Mustacchi 	{ SPD_DDR5_MRDIMM_IRXTYPE_TYPE_MATCHED, SPD_MRDIMM_IRXT_MATCHED,
1784*8119dad8SRobert Mustacchi 	    false }
1785*8119dad8SRobert Mustacchi };
1786*8119dad8SRobert Mustacchi 
1787*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_mrdimm_irxtype(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1788*8119dad8SRobert Mustacchi spd_parse_ddr5_mrdimm_irxtype(spd_info_t *si, uint32_t off, uint32_t len,
1789*8119dad8SRobert Mustacchi     const char *key)
1790*8119dad8SRobert Mustacchi {
1791*8119dad8SRobert Mustacchi 	const uint8_t data = si->si_data[off];
1792*8119dad8SRobert Mustacchi 	const uint8_t irxt = SPD_DDR5_MRDIMM_IRXTYPE_TYPE(data);
1793*8119dad8SRobert Mustacchi 
1794*8119dad8SRobert Mustacchi 	spd_insert_map(si, SPD_KEY_DDR5_MRDIMM_IRXT, irxt,
1795*8119dad8SRobert Mustacchi 	    spd_ddr5_mrdimm_irxt_map, ARRAY_SIZE(spd_ddr5_mrdimm_irxt_map));
1796*8119dad8SRobert Mustacchi }
1797*8119dad8SRobert Mustacchi 
1798*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr5_mrdimm_1v1[] = {
1799*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_CDEN,
1800*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_cden },
1801*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_OACEN,
1802*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_oacen },
1803*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_QCK_DRV,
1804*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_qck_drv },
1805*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_QCA_DRV,
1806*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_qca_drv },
1807*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_DB_DRV,
1808*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_db_drv },
1809*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_QXX_SLEW,
1810*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_qxx_slew },
1811*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_BXX_SLEW,
1812*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_bxx_slew },
1813*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_DCA_CFG,
1814*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_dca_cfg },
1815*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_MRDIMM_IRXTYPE,
1816*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_mrdimm_irxtype }
1817*8119dad8SRobert Mustacchi };
1818*8119dad8SRobert Mustacchi 
1819fe82ebb0SRobert Mustacchi /*
1820*8119dad8SRobert Mustacchi  * Annex A.5 DDIMM specific processing.
1821fe82ebb0SRobert Mustacchi  */
1822fe82ebb0SRobert Mustacchi static const spd_value_map_t spd_ddr5_dmb_type_map[] = {
1823fe82ebb0SRobert Mustacchi 	{ SPD_DDR5_DDIMM_INFO_TYPE_DMB501, SPD_DMB_T_DMB5011, false }
1824fe82ebb0SRobert Mustacchi };
1825fe82ebb0SRobert Mustacchi 
1826fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_ddimm_dmb(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1827fe82ebb0SRobert Mustacchi spd_parse_ddr5_ddimm_dmb(spd_info_t *si, uint32_t off, uint32_t len,
1828fe82ebb0SRobert Mustacchi     const char *key)
1829fe82ebb0SRobert Mustacchi {
1830fe82ebb0SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1831fe82ebb0SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1832fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1833fe82ebb0SRobert Mustacchi 		return;
1834fe82ebb0SRobert Mustacchi 
1835fe82ebb0SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_DMB,
1836fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_DMB_MFG, SPD_KEY_DEV_DMB_MFG_NAME,
1837fe82ebb0SRobert Mustacchi 	    SPD_KEY_DEV_DMB_REV, SPD_KEY_DEV_DMB_TYPE,
1838fe82ebb0SRobert Mustacchi 	    spd_ddr5_dmb_type_map, ARRAY_SIZE(spd_ddr5_dmb_type_map));
1839fe82ebb0SRobert Mustacchi }
1840fe82ebb0SRobert Mustacchi 
1841fe82ebb0SRobert Mustacchi static const spd_parse_t spd_ddr5_ddimm[] = {
1842fe82ebb0SRobert Mustacchi 	{ .sp_off = SPD_DDR5_DDIMM_MFG_ID0_DMB, .sp_len = 4,
1843fe82ebb0SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_ddimm_dmb },
1844fe82ebb0SRobert Mustacchi };
1845fe82ebb0SRobert Mustacchi 
1846*8119dad8SRobert Mustacchi /*
1847*8119dad8SRobert Mustacchi  * Annex A.8 CAMM2 specific processing.
1848*8119dad8SRobert Mustacchi  */
1849*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_camm2_ckd0(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1850*8119dad8SRobert Mustacchi spd_parse_ddr5_camm2_ckd0(spd_info_t *si, uint32_t off, uint32_t len,
1851*8119dad8SRobert Mustacchi     const char *key)
1852*8119dad8SRobert Mustacchi {
1853*8119dad8SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1854*8119dad8SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1855*8119dad8SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1856*8119dad8SRobert Mustacchi 		return;
1857*8119dad8SRobert Mustacchi 
1858*8119dad8SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_0,
1859*8119dad8SRobert Mustacchi 	    SPD_KEY_DEV_CD0_MFG, SPD_KEY_DEV_CD0_MFG_NAME,
1860*8119dad8SRobert Mustacchi 	    SPD_KEY_DEV_CD0_REV, SPD_KEY_DEV_CD0_TYPE,
1861*8119dad8SRobert Mustacchi 	    spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map));
1862*8119dad8SRobert Mustacchi }
1863*8119dad8SRobert Mustacchi 
1864*8119dad8SRobert Mustacchi static void
spd_parse_ddr5_camm2_ckd1(spd_info_t * si,uint32_t off,uint32_t len,const char * key)1865*8119dad8SRobert Mustacchi spd_parse_ddr5_camm2_ckd1(spd_info_t *si, uint32_t off, uint32_t len,
1866*8119dad8SRobert Mustacchi     const char *key)
1867*8119dad8SRobert Mustacchi {
1868*8119dad8SRobert Mustacchi 	ASSERT3U(len, ==, 4);
1869*8119dad8SRobert Mustacchi 	const uint8_t type = si->si_data[off + 2];
1870*8119dad8SRobert Mustacchi 	if (SPD_DDR5_COM_INFO_PRES(type) == 0)
1871*8119dad8SRobert Mustacchi 		return;
1872*8119dad8SRobert Mustacchi 
1873*8119dad8SRobert Mustacchi 	spd_parse_ddr5_dev_common(si, off, SPD_DEVICE_CD_1,
1874*8119dad8SRobert Mustacchi 	    SPD_KEY_DEV_CD1_MFG, SPD_KEY_DEV_CD1_MFG_NAME,
1875*8119dad8SRobert Mustacchi 	    SPD_KEY_DEV_CD1_REV, SPD_KEY_DEV_CD1_TYPE,
1876*8119dad8SRobert Mustacchi 	    spd_ddr5_cd_type_map, ARRAY_SIZE(spd_ddr5_cd_type_map));
1877*8119dad8SRobert Mustacchi }
1878*8119dad8SRobert Mustacchi 
1879*8119dad8SRobert Mustacchi static const spd_parse_t spd_ddr5_camm2[] = {
1880*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_CAMM2_MFG_ID0_CKD0, .sp_len = 4,
1881*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_camm2_ckd0 },
1882*8119dad8SRobert Mustacchi 	{ .sp_off = SPD_DDR5_CAMM2_MFG_ID0_CKD1, .sp_len = 4,
1883*8119dad8SRobert Mustacchi 	    .sp_parse = spd_parse_ddr5_camm2_ckd1 },
1884*8119dad8SRobert Mustacchi };
1885*8119dad8SRobert Mustacchi 
1886fe82ebb0SRobert Mustacchi static void
spd_parse_ddr5_mod_specific(spd_info_t * si)1887fe82ebb0SRobert Mustacchi spd_parse_ddr5_mod_specific(spd_info_t *si)
1888fe82ebb0SRobert Mustacchi {
1889fe82ebb0SRobert Mustacchi 	uint32_t type;
1890fe82ebb0SRobert Mustacchi 
1891fe82ebb0SRobert Mustacchi 	if (nvlist_lookup_uint32(si->si_nvl, SPD_KEY_MOD_TYPE, &type) != 0)
1892fe82ebb0SRobert Mustacchi 		return;
1893fe82ebb0SRobert Mustacchi 
1894fe82ebb0SRobert Mustacchi 	switch (type) {
1895fe82ebb0SRobert Mustacchi 	case SPD_MOD_TYPE_RDIMM:
1896fe82ebb0SRobert Mustacchi 		spd_parse(si, spd_ddr5_rdimm, ARRAY_SIZE(spd_ddr5_rdimm));
1897fe82ebb0SRobert Mustacchi 		break;
1898fe82ebb0SRobert Mustacchi 	case SPD_MOD_TYPE_LRDIMM:
1899fe82ebb0SRobert Mustacchi 		spd_parse(si, spd_ddr5_lrdimm, ARRAY_SIZE(spd_ddr5_lrdimm));
1900fe82ebb0SRobert Mustacchi 		break;
1901fe82ebb0SRobert Mustacchi 	case SPD_MOD_TYPE_UDIMM:
1902fe82ebb0SRobert Mustacchi 	case SPD_MOD_TYPE_SODIMM:
1903*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_CUDIMM:
1904*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_CSODIMM:
1905fe82ebb0SRobert Mustacchi 		spd_parse(si, spd_ddr5_udimm, ARRAY_SIZE(spd_ddr5_udimm));
1906*8119dad8SRobert Mustacchi 		if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 1) {
1907*8119dad8SRobert Mustacchi 			spd_parse(si, spd_ddr5_udimm_1v1,
1908*8119dad8SRobert Mustacchi 			    ARRAY_SIZE(spd_ddr5_udimm_1v1));
1909*8119dad8SRobert Mustacchi 		}
1910fe82ebb0SRobert Mustacchi 		break;
1911fe82ebb0SRobert Mustacchi 	case SPD_MOD_TYPE_MRDIMM:
1912fe82ebb0SRobert Mustacchi 		spd_parse(si, spd_ddr5_mrdimm, ARRAY_SIZE(spd_ddr5_mrdimm));
1913*8119dad8SRobert Mustacchi 		if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 1) {
1914*8119dad8SRobert Mustacchi 			spd_parse(si, spd_ddr5_mrdimm_1v1,
1915*8119dad8SRobert Mustacchi 			    ARRAY_SIZE(spd_ddr5_mrdimm_1v1));
1916*8119dad8SRobert Mustacchi 		}
1917fe82ebb0SRobert Mustacchi 		break;
1918fe82ebb0SRobert Mustacchi 	case SPD_MOD_TYPE_DDIMM:
1919fe82ebb0SRobert Mustacchi 		spd_parse(si, spd_ddr5_ddimm, ARRAY_SIZE(spd_ddr5_ddimm));
1920fe82ebb0SRobert Mustacchi 		break;
1921*8119dad8SRobert Mustacchi 	case SPD_MOD_TYPE_CAMM2:
1922*8119dad8SRobert Mustacchi 		spd_parse(si, spd_ddr5_camm2, ARRAY_SIZE(spd_ddr5_camm2));
1923*8119dad8SRobert Mustacchi 		break;
1924fe82ebb0SRobert Mustacchi 	/*
1925fe82ebb0SRobert Mustacchi 	 * Soldered DIMMs don't have any data.
1926fe82ebb0SRobert Mustacchi 	 */
1927fe82ebb0SRobert Mustacchi 	case SPD_MOD_TYPE_SOLDER:
1928fe82ebb0SRobert Mustacchi 	default:
1929fe82ebb0SRobert Mustacchi 		break;
1930fe82ebb0SRobert Mustacchi 	}
1931fe82ebb0SRobert Mustacchi }
1932fe82ebb0SRobert Mustacchi 
1933fe82ebb0SRobert Mustacchi /*
1934*8119dad8SRobert Mustacchi  * This is a common entry point for all of the common pieces of DDR5 and LPDDR5.
1935*8119dad8SRobert Mustacchi  * They use the same offsets and meanings and therefore this is called by both.
1936*8119dad8SRobert Mustacchi  * While strictly speaking LPDDR5 doesn't support all of the different types of
1937*8119dad8SRobert Mustacchi  * module types that DDR5 does, we will parse whatever is claimed.
1938*8119dad8SRobert Mustacchi  */
1939*8119dad8SRobert Mustacchi void
spd_parse_ddr5_common(spd_info_t * si)1940*8119dad8SRobert Mustacchi spd_parse_ddr5_common(spd_info_t *si)
1941*8119dad8SRobert Mustacchi {
1942*8119dad8SRobert Mustacchi 	spd_parse(si, spd_ddr5_module, ARRAY_SIZE(spd_ddr5_module));
1943*8119dad8SRobert Mustacchi 	spd_parse(si, spd_ddr5_mfg, ARRAY_SIZE(spd_ddr5_mfg));
1944*8119dad8SRobert Mustacchi 	spd_parse_ddr5_mod_specific(si);
1945*8119dad8SRobert Mustacchi }
1946*8119dad8SRobert Mustacchi 
1947*8119dad8SRobert Mustacchi /*
1948fe82ebb0SRobert Mustacchi  * DDR5 has two different revisions. One that is present in the base region and
1949fe82ebb0SRobert Mustacchi  * one that is present in the common module region that covers the
1950fe82ebb0SRobert Mustacchi  * module-related pieces. We check that both are present and go from there. We
1951fe82ebb0SRobert Mustacchi  * may want to relax this in the future so that it's easier to just decode a
1952fe82ebb0SRobert Mustacchi  * subset of this, but for the time being, we require both.
1953fe82ebb0SRobert Mustacchi  */
1954fe82ebb0SRobert Mustacchi void
spd_parse_ddr5(spd_info_t * si)1955fe82ebb0SRobert Mustacchi spd_parse_ddr5(spd_info_t *si)
1956fe82ebb0SRobert Mustacchi {
1957fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_SPD_REV]) !=
1958fe82ebb0SRobert Mustacchi 	    SPD_DDR5_SPD_REV_V1) {
1959fe82ebb0SRobert Mustacchi 		si->si_error = LIBJEDEC_SPD_UNSUP_REV;
1960fe82ebb0SRobert Mustacchi 		return;
1961fe82ebb0SRobert Mustacchi 	}
1962fe82ebb0SRobert Mustacchi 
1963fe82ebb0SRobert Mustacchi 	if (si->si_nbytes <= SPD_DDR5_COM_REV) {
1964fe82ebb0SRobert Mustacchi 		si->si_error = LIBJEDEC_SPD_TOOSHORT;
1965fe82ebb0SRobert Mustacchi 		return;
1966fe82ebb0SRobert Mustacchi 	}
1967fe82ebb0SRobert Mustacchi 
1968fe82ebb0SRobert Mustacchi 	if (SPD_DDR5_SPD_REV_ENC(si->si_data[SPD_DDR5_COM_REV]) !=
1969fe82ebb0SRobert Mustacchi 	    SPD_DDR5_SPD_REV_V1) {
1970fe82ebb0SRobert Mustacchi 		si->si_error = LIBJEDEC_SPD_UNSUP_REV;
1971fe82ebb0SRobert Mustacchi 		return;
1972fe82ebb0SRobert Mustacchi 	}
1973fe82ebb0SRobert Mustacchi 
1974fe82ebb0SRobert Mustacchi 	spd_parse(si, spd_ddr5_base, ARRAY_SIZE(spd_ddr5_base));
1975*8119dad8SRobert Mustacchi 	if (SPD_DDR5_SPD_REV_ADD(si->si_data[SPD_DDR5_COM_REV]) >= 2)
1976*8119dad8SRobert Mustacchi 		spd_parse(si, spd_ddr5_base_1v2, ARRAY_SIZE(spd_ddr5_base_1v2));
1977*8119dad8SRobert Mustacchi 	spd_parse_ddr5_common(si);
1978fe82ebb0SRobert Mustacchi }
1979