coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
spd.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cbfs.h>
4 #include <cbmem.h>
5 #include <console/console.h>
6 #include <gpio.h>
7 #include <lib.h>
8 #include <memory_info.h>
9 #include <smbios.h>
10 #include <spd.h>
11 #include <soc/gpio.h>
12 #include <soc/romstage.h>
13 #include <string.h>
14 #include <spd_bin.h>
15 #include "spd_util.h"
16 
18 {
19  gpio_t spd_gpios[] = {
20  GP_SW_80, /* SATA_GP3, RAMID0 */
21  GP_SW_67, /* I2C3_SCL, RAMID1 */
22  GP_SE_02, /* MF_PLT_CLK1, RAMID2 */
23  GP_SW_64, /* I2C3_SDA, RAMID3 */
24  };
25 
26  return gpio_base2_value(spd_gpios, ARRAY_SIZE(spd_gpios));
27 }
28 
29 static void *get_spd_pointer(int *dual)
30 {
31  char *spd_file;
32  size_t spd_file_len;
33  int total_spds;
34  int ram_id = 0;
35  int spd_index = 0;
36 
37  /* Find the SPD data in CBFS. */
38  spd_file = cbfs_map("spd.bin", &spd_file_len);
39  if (!spd_file)
40  die("SPD data not found.");
41 
42  if (spd_file_len < SPD_PAGE_LEN)
43  die("Missing SPD data.");
44  total_spds = spd_file_len / SPD_PAGE_LEN;
45 
46  ram_id = get_ramid();
47  printk(BIOS_DEBUG, "ram_id=%d, total_spds: %d\n", ram_id, total_spds);
48 
49  spd_index = get_variant_spd_index(ram_id, dual);
50  if (spd_index >= total_spds) {
51  printk(BIOS_ERR, "SPD index > total SPDs\n");
52  return NULL;
53  }
54  /* Return the serial product data for the RAM */
55  return &spd_file[SPD_PAGE_LEN * spd_index];
56 }
57 
58 /* Copy SPD data for on-board memory */
59 void spd_memory_init_params(MEMORY_INIT_UPD *memory_params)
60 {
61  void *spd_content;
62  int dual_channel = 0;
63 
64  /*
65  * Both channels are always present in SPD data. Always use matched
66  * DIMMs so use the same SPD data for each DIMM.
67  */
68  spd_content = get_spd_pointer(&dual_channel);
69  if (CONFIG(DISPLAY_SPD_DATA) && spd_content != NULL) {
70  printk(BIOS_DEBUG, "SPD Data:\n");
71  hexdump(spd_content, SPD_PAGE_LEN);
72  printk(BIOS_DEBUG, "\n");
73  }
74 
75  /*
76  * Set SPD and memory configuration:
77  * Memory type: 0=DimmInstalled,
78  * 1=SolderDownMemory,
79  * 2=DimmDisabled
80  */
81  if (spd_content != NULL) {
82  memory_params->PcdMemChannel0Config = 1;
83  printk(BIOS_DEBUG, "Channel 0 DIMM soldered down\n");
84  if (dual_channel) {
85  printk(BIOS_DEBUG, "Channel 1 DIMM soldered down\n");
86  memory_params->PcdMemChannel1Config = 1;
87  } else {
88  printk(BIOS_DEBUG, "Channel 1 DIMM not installed\n");
89  memory_params->PcdMemChannel1Config = 2;
90  }
91  }
92 
93  /* Update SPD data */
94  if (CONFIG(BOARD_GOOGLE_CYAN)) {
95  memory_params->PcdMemoryTypeEnable = MEM_DDR3;
96  memory_params->PcdMemorySpdPtr = (uintptr_t)spd_content;
97  } else {
98  memory_params->PcdMemoryTypeEnable = MEM_LPDDR3;
99  }
100 }
101 
102 static void set_dimm_info(const uint8_t *spd, struct dimm_info *dimm)
103 {
104  const int spd_capmb[8] = { 1, 2, 4, 8, 16, 32, 64, 0 };
105  const int spd_ranks[8] = { 1, 2, 3, 4, -1, -1, -1, -1 };
106  const int spd_devw[8] = { 4, 8, 16, 32, -1, -1, -1, -1 };
107  const int spd_busw[8] = { 8, 16, 32, 64, -1, -1, -1, -1 };
108 
109  int capmb = spd_capmb[spd[SPD_DENSITY_BANKS] & 7] * 256;
110  int ranks = spd_ranks[(spd[DDR3_ORGANIZATION] >> 3) & 7];
111  int devw = spd_devw[spd[DDR3_ORGANIZATION] & 7];
112  int busw = spd_busw[spd[DDR3_BUS_DEV_WIDTH] & 7];
113 
114  void *hob_list_ptr;
115  EFI_HOB_GUID_TYPE *hob_ptr;
116  FSP_SMBIOS_MEMORY_INFO *memory_info_hob;
117  const EFI_GUID memory_info_hob_guid = FSP_SMBIOS_MEMORY_INFO_GUID;
118 
119  /* Locate the memory info HOB, presence validated by raminit */
120  hob_list_ptr = fsp_get_hob_list();
121  hob_ptr = get_guid_hob(&memory_info_hob_guid, hob_list_ptr);
122  if (hob_ptr != NULL) {
123  memory_info_hob = (FSP_SMBIOS_MEMORY_INFO *)(hob_ptr + 1);
124  dimm->ddr_frequency = memory_info_hob->MemoryFrequencyInMHz;
125  } else {
126  printk(BIOS_ERR, "Can't get memory info hob pointer\n");
127  dimm->ddr_frequency = 0;
128  }
129 
130  /* Parse the SPD data to determine the DIMM information */
131  if (CONFIG(BOARD_GOOGLE_CYAN)) {
132  dimm->ddr_type = MEMORY_TYPE_DDR3;
133  } else {
135  }
136  dimm->dimm_size = capmb / 8 * busw / devw * ranks; /* MiB */
137  dimm->mod_type = spd[3] & 0xf;
138  strncpy((char *)&dimm->module_part_number[0], (char *)&spd[0x80],
141  dimm->mod_id = *(uint16_t *)&spd[0x94];
142 
143  switch (busw) {
144  default:
145  case 8:
147  break;
148 
149  case 16:
151  break;
152 
153  case 32:
155  break;
156 
157  case 64:
159  break;
160  }
161 }
162 
164 {
165  const void *spd_content;
166  int dual_channel;
167  struct dimm_info *dimm;
168  struct memory_info *mem_info;
169 
170  spd_content = get_spd_pointer(&dual_channel);
171  if (spd_content == NULL)
172  return;
173 
174  /*
175  * Allocate CBMEM area for DIMM information used to populate SMBIOS
176  * table 17
177  */
178  mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info));
179  printk(BIOS_DEBUG, "CBMEM entry for DIMM info: %p\n", mem_info);
180  if (mem_info == NULL)
181  return;
182  memset(mem_info, 0, sizeof(*mem_info));
183 
184  /* Describe the first channel memory */
185  dimm = &mem_info->dimm[0];
186  set_dimm_info(spd_content, dimm);
187  mem_info->dimm_cnt = 1;
188 
189  /* Describe the second channel memory */
190  if (dual_channel) {
191  dimm = &mem_info->dimm[1];
192  set_dimm_info(spd_content, dimm);
193  dimm->channel_num = 1;
194  mem_info->dimm_cnt = 2;
195  }
196 }
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
static struct sdram_info params
Definition: sdram_configs.c:83
#define ARRAY_SIZE(a)
Definition: helpers.h:12
static void * cbfs_map(const char *name, size_t *size_out)
Definition: cbfs.h:246
void * cbmem_add(u32 id, u64 size)
Definition: imd_cbmem.c:144
#define CBMEM_ID_MEMINFO
Definition: cbmem_id.h:33
#define printk(level,...)
Definition: stdlib.h:16
void __noreturn die(const char *fmt,...)
Definition: die.c:17
int get_variant_spd_index(int ram_id, int *dual)
Definition: spd_util.c:21
@ CONFIG
Definition: dsi_common.h:201
void * fsp_get_hob_list(void)
Definition: fsp_util.c:202
void * get_guid_hob(const EFI_GUID *guid, const void *hob_start)
Definition: hob.c:48
uint32_t gpio_base2_value(const gpio_t gpio[], int num_gpio)
Definition: gpio.c:30
@ MEMORY_BUS_WIDTH_32
Definition: smbios.h:136
@ MEMORY_BUS_WIDTH_64
Definition: smbios.h:137
@ MEMORY_BUS_WIDTH_16
Definition: smbios.h:135
@ MEMORY_BUS_WIDTH_8
Definition: smbios.h:134
@ MEMORY_TYPE_DDR3
Definition: smbios.h:185
@ MEMORY_TYPE_LPDDR3
Definition: smbios.h:190
void hexdump(const void *memory, size_t length)
Definition: hexdump.c:7
#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 SPD_DENSITY_BANKS
Definition: spd.c:15
__weak uint8_t get_ramid(void)
Definition: spd.c:17
static void set_dimm_info(const uint8_t *spd, struct dimm_info *dimm)
Definition: spd.c:102
void spd_memory_init_params(MEMORY_INIT_UPD *memory_params)
Definition: spd.c:59
void mainboard_save_dimm_info(struct romstage_params *params)
Definition: spd.c:163
static void * get_spd_pointer(int *dual)
Definition: spd.c:29
static const int spd_index[32]
Definition: memory.c:10
const struct smm_save_state_ops *legacy_ops __weak
Definition: save_state.c:8
#define FSP_SMBIOS_MEMORY_INFO_GUID
Definition: romstage.c:23
#define GP_SW_64
Definition: gpio_defs.h:43
#define GP_SE_02
Definition: gpio_defs.h:151
#define GP_SW_80
Definition: gpio_defs.h:52
#define GP_SW_67
Definition: gpio_defs.h:46
#define MEM_DDR3
Definition: romstage.h:17
#define MEM_LPDDR3
Definition: romstage.h:18
#define LPDDR3_SPD_PART_LEN
Definition: spd_bin.h:33
#define SPD_PAGE_LEN
Definition: spd_bin.h:9
#define DDR3_BUS_DEV_WIDTH
Definition: spd_bin.h:26
#define DDR3_ORGANIZATION
Definition: spd_bin.h:25
#define NULL
Definition: stddef.h:19
unsigned short uint16_t
Definition: stdint.h:11
unsigned long uintptr_t
Definition: stdint.h:21
unsigned char uint8_t
Definition: stdint.h:8
char * strncpy(char *to, const char *from, int count)
Definition: string.c:72
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 channel_num
Definition: memory_info.h:36
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
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