1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include <console/console.h>
8 #include <memory_info.h>
11 #include <soc/romstage.h>
16 __weak
uint8_t get_ramid(void)
18 gpio_t spd_gpios
[] = {
19 GP_SW_80
, /* SATA_GP3, RAMID0 */
20 GP_SW_67
, /* I2C3_SCL, RAMID1 */
21 GP_SE_02
, /* MF_PLT_CLK1, RAMID2 */
22 GP_SW_64
, /* I2C3_SDA, RAMID3 */
25 return gpio_base2_value(spd_gpios
, ARRAY_SIZE(spd_gpios
));
28 static void *get_spd_pointer(int *dual
)
36 /* Find the SPD data in CBFS. */
37 spd_file
= cbfs_map("spd.bin", &spd_file_len
);
39 die("SPD data not found.");
41 if (spd_file_len
< SPD_PAGE_LEN
)
42 die("Missing SPD data.");
43 total_spds
= spd_file_len
/ SPD_PAGE_LEN
;
46 printk(BIOS_DEBUG
, "ram_id=%d, total_spds: %d\n", ram_id
, total_spds
);
48 spd_index
= get_variant_spd_index(ram_id
, dual
);
49 if (spd_index
>= total_spds
) {
50 printk(BIOS_ERR
, "SPD index > total SPDs\n");
53 /* Return the serial product data for the RAM */
54 return &spd_file
[SPD_PAGE_LEN
* spd_index
];
57 /* Copy SPD data for on-board memory */
58 void spd_memory_init_params(MEMORY_INIT_UPD
*memory_params
)
64 * Both channels are always present in SPD data. Always use matched
65 * DIMMs so use the same SPD data for each DIMM.
67 spd_content
= get_spd_pointer(&dual_channel
);
68 if (CONFIG(DISPLAY_SPD_DATA
) && spd_content
!= NULL
) {
69 printk(BIOS_DEBUG
, "SPD Data:\n");
70 hexdump(spd_content
, SPD_PAGE_LEN
);
71 printk(BIOS_DEBUG
, "\n");
75 * Set SPD and memory configuration:
76 * Memory type: 0=DimmInstalled,
80 if (spd_content
!= NULL
) {
81 memory_params
->PcdMemChannel0Config
= 1;
82 printk(BIOS_DEBUG
, "Channel 0 DIMM soldered down\n");
84 printk(BIOS_DEBUG
, "Channel 1 DIMM soldered down\n");
85 memory_params
->PcdMemChannel1Config
= 1;
87 printk(BIOS_DEBUG
, "Channel 1 DIMM not installed\n");
88 memory_params
->PcdMemChannel1Config
= 2;
93 if (CONFIG(BOARD_GOOGLE_CYAN
)) {
94 memory_params
->PcdMemoryTypeEnable
= MEM_DDR3
;
95 memory_params
->PcdMemorySpdPtr
= (uintptr_t)spd_content
;
97 memory_params
->PcdMemoryTypeEnable
= MEM_LPDDR3
;
101 static void set_dimm_info(const uint8_t *spd
, struct dimm_info
*dimm
)
103 const int spd_capmb
[8] = { 1, 2, 4, 8, 16, 32, 64, 0 };
104 const int spd_ranks
[8] = { 1, 2, 3, 4, -1, -1, -1, -1 };
105 const int spd_devw
[8] = { 4, 8, 16, 32, -1, -1, -1, -1 };
106 const int spd_busw
[8] = { 8, 16, 32, 64, -1, -1, -1, -1 };
108 int capmb
= spd_capmb
[spd
[SPD_DENSITY_BANKS
] & 7] * 256;
109 int ranks
= spd_ranks
[(spd
[DDR3_ORGANIZATION
] >> 3) & 7];
110 int devw
= spd_devw
[spd
[DDR3_ORGANIZATION
] & 7];
111 int busw
= spd_busw
[spd
[DDR3_BUS_DEV_WIDTH
] & 7];
114 EFI_HOB_GUID_TYPE
*hob_ptr
;
115 FSP_SMBIOS_MEMORY_INFO
*memory_info_hob
;
116 const EFI_GUID memory_info_hob_guid
= FSP_SMBIOS_MEMORY_INFO_GUID
;
118 /* Locate the memory info HOB, presence validated by raminit */
119 hob_list_ptr
= fsp_get_hob_list();
120 hob_ptr
= get_guid_hob(&memory_info_hob_guid
, hob_list_ptr
);
121 if (hob_ptr
!= NULL
) {
122 memory_info_hob
= (FSP_SMBIOS_MEMORY_INFO
*)(hob_ptr
+ 1);
123 dimm
->ddr_frequency
= memory_info_hob
->MemoryFrequencyInMHz
;
125 printk(BIOS_ERR
, "Can't get memory info hob pointer\n");
126 dimm
->ddr_frequency
= 0;
129 /* Parse the SPD data to determine the DIMM information */
130 if (CONFIG(BOARD_GOOGLE_CYAN
)) {
131 dimm
->ddr_type
= MEMORY_TYPE_DDR3
;
133 dimm
->ddr_type
= MEMORY_TYPE_LPDDR3
;
135 dimm
->dimm_size
= capmb
/ 8 * busw
/ devw
* ranks
; /* MiB */
136 dimm
->mod_type
= spd
[3] & 0xf;
137 strncpy((char *)&dimm
->module_part_number
[0], (char *)&spd
[0x80],
138 LPDDR3_SPD_PART_LEN
);
139 dimm
->module_part_number
[LPDDR3_SPD_PART_LEN
] = 0;
140 dimm
->mod_id
= *(uint16_t *)&spd
[0x94];
145 dimm
->bus_width
= MEMORY_BUS_WIDTH_8
;
149 dimm
->bus_width
= MEMORY_BUS_WIDTH_16
;
153 dimm
->bus_width
= MEMORY_BUS_WIDTH_32
;
157 dimm
->bus_width
= MEMORY_BUS_WIDTH_64
;
162 void mainboard_save_dimm_info(struct romstage_params
*params
)
164 const void *spd_content
;
166 struct dimm_info
*dimm
;
167 struct memory_info
*mem_info
;
169 spd_content
= get_spd_pointer(&dual_channel
);
170 if (spd_content
== NULL
)
174 * Allocate CBMEM area for DIMM information used to populate SMBIOS
177 mem_info
= cbmem_add(CBMEM_ID_MEMINFO
, sizeof(*mem_info
));
178 printk(BIOS_DEBUG
, "CBMEM entry for DIMM info: %p\n", mem_info
);
179 if (mem_info
== NULL
)
181 memset(mem_info
, 0, sizeof(*mem_info
));
183 /* Describe the first channel memory */
184 dimm
= &mem_info
->dimm
[0];
185 set_dimm_info(spd_content
, dimm
);
186 mem_info
->dimm_cnt
= 1;
188 /* Describe the second channel memory */
190 dimm
= &mem_info
->dimm
[1];
191 set_dimm_info(spd_content
, dimm
);
192 dimm
->channel_num
= 1;
193 mem_info
->dimm_cnt
= 2;