coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
ddr4.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <cbmem.h>
5 #include <device/device.h>
6 #include <device/dram/ddr4.h>
7 #include <string.h>
8 #include <memory_info.h>
9 #include <smbios.h>
10 #include <types.h>
11 
19  DDR4_3200
20 };
21 
23  uint32_t min_clock_mhz; // inclusive
24  uint32_t max_clock_mhz; // inclusive
26 };
27 
28 /**
29  * DDR4 speed attributes derived from JEDEC 79-4C tables 169 & 170
30  *
31  * min_clock_mhz = 1000/max_tCk_avg(ns) + 1
32  * Adding 1 to make minimum inclusive
33  * max_clock_mhz = 1000/min_tCk_avg(ns)
34  * reported_mts = Standard reported DDR4 speed in MT/s
35  * May be 1 less than the actual max MT/s
36  */
37 static const struct ddr4_speed_attr ddr4_speeds[] = {
38  [DDR4_1600] = {
39  .min_clock_mhz = 668,
40  .max_clock_mhz = 800,
41  .reported_mts = 1600
42  },
43  [DDR4_1866] = {
44  .min_clock_mhz = 801,
45  .max_clock_mhz = 934,
46  .reported_mts = 1866
47  },
48  [DDR4_2133] = {
49  .min_clock_mhz = 935,
50  .max_clock_mhz = 1067,
51  .reported_mts = 2133
52  },
53  [DDR4_2400] = {
54  .min_clock_mhz = 1068,
55  .max_clock_mhz = 1200,
56  .reported_mts = 2400
57  },
58  [DDR4_2666] = {
59  .min_clock_mhz = 1201,
60  .max_clock_mhz = 1333,
61  .reported_mts = 2666
62  },
63  [DDR4_2933] = {
64  .min_clock_mhz = 1334,
65  .max_clock_mhz = 1466,
66  .reported_mts = 2933
67  },
68  [DDR4_3200] = {
69  .min_clock_mhz = 1467,
70  .max_clock_mhz = 1600,
71  .reported_mts = 3200
72  }
73 };
74 
75 typedef enum {
76  BLOCK_0, /* Base Configuration and DRAM Parameters */
78  BLOCK_1_L, /* Standard Module Parameters */
79  BLOCK_1_H, /* Hybrid Module Parameters */
81  BLOCK_2_L, /* Hybrid Module Extended Function Parameters */
82  BLOCK_2_H, /* Manufacturing Information */
83  BLOCK_3 /* End user programmable */
85 
86 typedef struct {
88  uint16_t start; /* starting offset from beginning of the spd */
89  uint16_t len; /* size of the block */
90  uint16_t crc_start; /* offset from start of crc bytes, 0 if none */
91 } spd_block;
92 
93 /* 'SPD contents architecture' as per datasheet */
94 const spd_block spd_blocks[] = {
95  {.type = BLOCK_0, 0, 128, 126}, {.type = BLOCK_1, 128, 128, 126},
96  {.type = BLOCK_1_L, 128, 64, 0}, {.type = BLOCK_1_H, 192, 64, 0},
97  {.type = BLOCK_2_L, 256, 64, 62}, {.type = BLOCK_2_H, 320, 64, 0},
98  {.type = BLOCK_3, 384, 128, 0} };
99 
100 static bool verify_block(const spd_block *block, spd_raw_data spd)
101 {
102  uint16_t crc, spd_crc;
103 
104  spd_crc = (spd[block->start + block->crc_start + 1] << 8)
105  | spd[block->start + block->crc_start];
106  crc = ddr_crc16(&spd[block->start], block->len - 2);
107 
108  return spd_crc == crc;
109 }
110 
111 /* Check if given block is 'reserved' for a given module type */
112 static bool block_exists(spd_block_type type, u8 dimm_type)
113 {
114  bool is_hybrid;
115 
116  switch (type) {
117  case BLOCK_0: /* fall-through */
118  case BLOCK_1: /* fall-through */
119  case BLOCK_1_L: /* fall-through */
120  case BLOCK_1_H: /* fall-through */
121  case BLOCK_2_H: /* fall-through */
122  case BLOCK_3: /* fall-through */
123  return true;
124  case BLOCK_2_L:
125  is_hybrid = (dimm_type >> 4) & ((1 << 3) - 1);
126  if (is_hybrid)
127  return true;
128  return false;
129  default: /* fall-through */
130  return false;
131  }
132 }
133 
134 /**
135  * Converts DDR4 clock speed in MHz to the standard reported speed in MT/s
136  */
138 {
139  for (enum ddr4_speed_grade speed = 0; speed < ARRAY_SIZE(ddr4_speeds); speed++) {
140  const struct ddr4_speed_attr *speed_attr = &ddr4_speeds[speed];
141  if (speed_mhz >= speed_attr->min_clock_mhz &&
142  speed_mhz <= speed_attr->max_clock_mhz) {
143  return speed_attr->reported_mts;
144  }
145  }
146  printk(BIOS_ERR, "DDR4 speed of %d MHz is out of range\n", speed_mhz);
147  return 0;
148 }
149 
150 /**
151  * \brief Decode the raw SPD data
152  *
153  * Decodes a raw SPD data from a DDR4 DIMM, and organizes it into a
154  * @ref dimm_attr structure. The SPD data must first be read in a contiguous
155  * array, and passed to this function.
156  *
157  * @param dimm pointer to @ref dimm_attr structure where the decoded data is to
158  * be stored
159  * @param spd array of raw data previously read from the SPD.
160  *
161  * @return @ref spd_status enumerator
162  * SPD_STATUS_OK -- decoding was successful
163  * SPD_STATUS_INVALID -- invalid SPD or not a DDR4 SPD
164  * SPD_STATUS_CRC_ERROR -- checksum mismatch
165  */
167 {
168  u8 reg8;
169  u8 bus_width, sdram_width;
170  u16 cap_per_die_mbit;
171  u16 spd_bytes_total, spd_bytes_used;
172  const uint16_t spd_bytes_used_table[] = {0, 128, 256, 384, 512};
173 
174  /* Make sure that the SPD dump is indeed from a DDR4 module */
175  if (spd[2] != SPD_MEMORY_TYPE_DDR4_SDRAM) {
176  printk(BIOS_ERR, "Not a DDR4 SPD!\n");
178  return SPD_STATUS_INVALID;
179  }
180 
181  spd_bytes_total = (spd[0] >> 4) & 0x7;
182  spd_bytes_used = spd[0] & 0xf;
183 
184  if (!spd_bytes_total || !spd_bytes_used) {
185  printk(BIOS_ERR, "SPD failed basic sanity checks\n");
186  return SPD_STATUS_INVALID;
187  }
188 
189  if (spd_bytes_total >= 3)
190  printk(BIOS_WARNING, "SPD Bytes Total value is reserved\n");
191 
192  spd_bytes_total = 256 << (spd_bytes_total - 1);
193 
194  if (spd_bytes_used > 4) {
195  printk(BIOS_ERR, "SPD Bytes Used value is reserved\n");
196  return SPD_STATUS_INVALID;
197  }
198 
199  spd_bytes_used = spd_bytes_used_table[spd_bytes_used];
200 
201  if (spd_bytes_used > spd_bytes_total) {
202  printk(BIOS_ERR, "SPD Bytes Used is greater than SPD Bytes Total\n");
203  return SPD_STATUS_INVALID;
204  }
205 
206  /* Verify CRC of blocks that have them, do not step over 'used' length */
207  for (int i = 0; i < ARRAY_SIZE(spd_blocks); i++) {
208  /* this block is not checksummed */
209  if (spd_blocks[i].crc_start == 0)
210  continue;
211  /* we shouldn't have this block */
212  if (spd_blocks[i].start + spd_blocks[i].len > spd_bytes_used)
213  continue;
214  /* check if block exists in the current schema */
215  if (!block_exists(spd_blocks[i].type, spd[3]))
216  continue;
217  if (!verify_block(&spd_blocks[i], spd)) {
218  printk(BIOS_ERR, "CRC failed for block %d\n", i);
219  return SPD_STATUS_CRC_ERROR;
220  }
221  }
222 
224  dimm->dimm_type = spd[3] & ((1 << 4) - 1);
225 
226  reg8 = spd[13] & ((1 << 4) - 1);
227  dimm->bus_width = reg8;
228  bus_width = 8 << (reg8 & ((1 << 3) - 1));
229 
230  reg8 = spd[12] & ((1 << 3) - 1);
231  dimm->sdram_width = reg8;
232  sdram_width = 4 << reg8;
233 
234  reg8 = spd[4] & ((1 << 4) - 1);
235  dimm->cap_per_die_mbit = reg8;
236  cap_per_die_mbit = (1 << reg8) * 256;
237 
238  reg8 = (spd[12] >> 3) & ((1 << 3) - 1);
239  dimm->ranks = reg8 + 1;
240 
241  if (!bus_width || !sdram_width) {
242  printk(BIOS_ERR, "SPD information is invalid");
243  dimm->size_mb = 0;
244  return SPD_STATUS_INVALID;
245  }
246 
247  /* seems to be only one, in mV */
248  dimm->vdd_voltage = 1200;
249 
250  /* calculate size */
251  dimm->size_mb = cap_per_die_mbit / 8 * bus_width / sdram_width * dimm->ranks;
252 
253  /* make sure we have the manufacturing information block */
254  if (spd_bytes_used > 320) {
255  dimm->manufacturer_id = (spd[351] << 8) | spd[350];
256  memcpy(dimm->part_number, &spd[329], SPD_DDR4_PART_LEN);
257  dimm->part_number[SPD_DDR4_PART_LEN] = 0;
258  memcpy(dimm->serial_number, &spd[325], sizeof(dimm->serial_number));
259  }
260  return SPD_STATUS_OK;
261 }
262 
263 enum cb_err spd_add_smbios17_ddr4(const u8 channel, const u8 slot, const u16 selected_freq,
264  const struct dimm_attr_ddr4_st *info)
265 {
266  struct memory_info *mem_info;
267  struct dimm_info *dimm;
268 
269  /*
270  * Allocate CBMEM area for DIMM information used to populate SMBIOS
271  * table 17
272  */
273  mem_info = cbmem_find(CBMEM_ID_MEMINFO);
274  if (!mem_info) {
275  mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info));
276 
277  printk(BIOS_DEBUG, "CBMEM entry for DIMM info: %p\n", mem_info);
278  if (!mem_info)
279  return CB_ERR;
280 
281  memset(mem_info, 0, sizeof(*mem_info));
282  }
283 
284  if (mem_info->dimm_cnt >= ARRAY_SIZE(mem_info->dimm)) {
285  printk(BIOS_WARNING, "BUG: Too many DIMM infos for %s.\n", __func__);
286  return CB_ERR;
287  }
288 
289  dimm = &mem_info->dimm[mem_info->dimm_cnt];
290  if (info->size_mb) {
291  dimm->ddr_type = MEMORY_TYPE_DDR4;
292  dimm->ddr_frequency = selected_freq;
293  dimm->dimm_size = info->size_mb;
294  dimm->channel_num = channel;
295  dimm->rank_per_dimm = info->ranks;
296  dimm->dimm_num = slot;
297  memcpy(dimm->module_part_number, info->part_number, SPD_DDR4_PART_LEN);
298  dimm->mod_id = info->manufacturer_id;
299 
300  switch (info->dimm_type) {
302  dimm->mod_type = DDR4_SPD_SODIMM;
303  break;
306  break;
308  dimm->mod_type = DDR4_SPD_UDIMM;
309  break;
311  dimm->mod_type = DDR4_SPD_RDIMM;
312  break;
313  default:
314  dimm->mod_type = SPD_UNDEFINED;
315  break;
316  }
317 
318  dimm->bus_width = info->bus_width;
319  memcpy(dimm->serial, info->serial_number,
320  MIN(sizeof(dimm->serial), sizeof(info->serial_number)));
321 
322  dimm->vdd_voltage = info->vdd_voltage;
323  mem_info->dimm_cnt++;
324  }
325 
326  return CB_SUCCESS;
327 }
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define MIN(a, b)
Definition: helpers.h:37
cb_err
coreboot error codes
Definition: cb_err.h:15
@ CB_ERR
Generic error code.
Definition: cb_err.h:17
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
void * cbmem_add(u32 id, u64 size)
Definition: imd_cbmem.c:144
void * cbmem_find(u32 id)
Definition: imd_cbmem.c:166
#define CBMEM_ID_MEMINFO
Definition: cbmem_id.h:33
#define printk(level,...)
Definition: stdlib.h:16
int spd_decode_ddr4(struct dimm_attr_ddr4_st *dimm, spd_raw_data spd)
Decode the raw SPD data.
Definition: ddr4.c:166
static bool verify_block(const spd_block *block, spd_raw_data spd)
Definition: ddr4.c:100
uint16_t ddr4_speed_mhz_to_reported_mts(uint16_t speed_mhz)
Converts DDR4 clock speed in MHz to the standard reported speed in MT/s.
Definition: ddr4.c:137
static const struct ddr4_speed_attr ddr4_speeds[]
DDR4 speed attributes derived from JEDEC 79-4C tables 169 & 170.
Definition: ddr4.c:37
ddr4_speed_grade
Definition: ddr4.c:12
@ DDR4_1866
Definition: ddr4.c:14
@ DDR4_1600
Definition: ddr4.c:13
@ DDR4_2400
Definition: ddr4.c:16
@ DDR4_2133
Definition: ddr4.c:15
@ DDR4_3200
Definition: ddr4.c:19
@ DDR4_2666
Definition: ddr4.c:17
@ DDR4_2933
Definition: ddr4.c:18
const spd_block spd_blocks[]
Definition: ddr4.c:94
enum cb_err spd_add_smbios17_ddr4(const u8 channel, const u8 slot, const u16 selected_freq, const struct dimm_attr_ddr4_st *info)
Definition: ddr4.c:263
spd_block_type
Definition: ddr4.c:75
@ BLOCK_2_L
Definition: ddr4.c:81
@ BLOCK_1
Definition: ddr4.c:77
@ BLOCK_1_L
Definition: ddr4.c:78
@ BLOCK_2
Definition: ddr4.c:80
@ BLOCK_1_H
Definition: ddr4.c:79
@ BLOCK_0
Definition: ddr4.c:76
@ BLOCK_3
Definition: ddr4.c:83
@ BLOCK_2_H
Definition: ddr4.c:82
static bool block_exists(spd_block_type type, u8 dimm_type)
Definition: ddr4.c:112
Utilities for decoding DDR4 SPDs.
@ SPD_DDR4_DIMM_TYPE_SO_DIMM
Definition: ddr4.h:32
@ SPD_DDR4_DIMM_TYPE_UDIMM
Definition: ddr4.h:31
@ SPD_DDR4_DIMM_TYPE_RDIMM
Definition: ddr4.h:30
@ SPD_DDR4_DIMM_TYPE_72B_SO_RDIMM
Definition: ddr4.h:36
#define SPD_DDR4_PART_LEN
Definition: ddr4.h:22
u16 ddr_crc16(const u8 *ptr, int n_crc)
Calculate the CRC of a DDR SPD data.
Definition: ddr_common.c:14
static struct smmstore_params_info info
Definition: ramstage.c:12
@ SPD_STATUS_CRC_ERROR
Definition: common.h:54
@ SPD_STATUS_INVALID
Definition: common.h:53
@ SPD_STATUS_OK
Definition: common.h:52
u8 spd_raw_data[256]
Definition: ddr3.h:156
@ MEMORY_TYPE_DDR4
Definition: smbios.h:187
#define SPD_UNDEFINED
Definition: spd.h:200
@ DDR4_SPD_RDIMM
Definition: spd.h:233
@ DDR4_SPD_72B_SO_RDIMM
Definition: spd.h:239
@ DDR4_SPD_SODIMM
Definition: spd.h:235
@ DDR4_SPD_UDIMM
Definition: spd.h:234
@ SPD_MEMORY_TYPE_DDR4_SDRAM
Definition: spd.h:153
@ SPD_MEMORY_TYPE_UNDEFINED
Definition: spd.h:141
unsigned int type
Definition: edid.c:57
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
uint32_t min_clock_mhz
Definition: ddr4.c:23
uint32_t max_clock_mhz
Definition: ddr4.c:24
uint32_t reported_mts
Definition: ddr4.c:25
DIMM characteristics.
Definition: ddr4.h:49
u8 serial_number[4]
Definition: ddr4.h:53
u16 manufacturer_id
Definition: ddr4.h:59
char part_number[SPD_DDR4_PART_LEN+1]
Definition: ddr4.h:52
enum spd_memory_type dram_type
Definition: ddr4.h:50
enum spd_dimm_type_ddr4 dimm_type
Definition: ddr4.h:51
u16 cap_per_die_mbit
Definition: ddr4.h:57
u16 vdd_voltage
Definition: ddr4.h:60
u8 sdram_width
Definition: ddr4.h:56
If this table is filled and put in CBMEM, then these info in CBMEM will be used to generate smbios ty...
Definition: memory_info.h:19
uint8_t mod_type
Definition: memory_info.h:60
uint8_t rank_per_dimm
Definition: memory_info.h:35
uint8_t channel_num
Definition: memory_info.h:36
uint8_t dimm_num
Definition: memory_info.h:37
uint8_t bus_width
Definition: memory_info.h:80
uint8_t module_part_number[DIMM_INFO_PART_NUMBER_SIZE]
Definition: memory_info.h:48
uint16_t ddr_type
Definition: memory_info.h:29
uint8_t serial[DIMM_INFO_SERIAL_SIZE]
Definition: memory_info.h:42
uint16_t vdd_voltage
Definition: memory_info.h:84
uint16_t ddr_frequency
Definition: memory_info.h:34
uint16_t mod_id
Definition: memory_info.h:52
uint32_t dimm_size
Definition: memory_info.h:23
struct dimm_info dimm[DIMM_INFO_TOTAL]
Definition: memory_info.h:110
uint8_t dimm_cnt
Definition: memory_info.h:109
Definition: ddr4.c:86
spd_block_type type
Definition: ddr4.c:87
uint16_t crc_start
Definition: ddr4.c:90
uint16_t len
Definition: ddr4.c:89
uint16_t start
Definition: ddr4.c:88