blob: b7b0c30c5dc192413b7ce2ce5685112800c9c4c3 [file] [log] [blame]
Lee Leahy89b5fbd2015-05-11 17:24:31 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
5 * Copyright (C) 2015 Intel Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Lee Leahy89b5fbd2015-05-11 17:24:31 -070015 */
16
17#include <cbfs.h>
18#include <cbmem.h>
19#include <console/console.h>
Subrata Banike5e94392015-08-22 11:10:22 +053020#include <gpio.h>
Lee Leahy89b5fbd2015-05-11 17:24:31 -070021#include <lib.h>
22#include <memory_info.h>
23#include <smbios.h>
24#include <spd.h>
25#include <soc/gpio.h>
26#include <soc/romstage.h>
27#include <string.h>
Matt DeVillier869f22f2017-08-24 14:47:28 -050028#include <spd_bin.h>
Matt DeVilliere69a9c72017-08-20 14:48:57 -050029#include "spd_util.h"
Lee Leahy89b5fbd2015-05-11 17:24:31 -070030
Aaron Durbin64031672018-04-21 14:45:32 -060031__weak uint8_t get_ramid(void)
Lee Leahy89b5fbd2015-05-11 17:24:31 -070032{
Subrata Banike5e94392015-08-22 11:10:22 +053033 gpio_t spd_gpios[] = {
Matt DeVillier869f22f2017-08-24 14:47:28 -050034 GP_SW_80, /* SATA_GP3, RAMID0 */
35 GP_SW_67, /* I2C3_SCL, RAMID1 */
Subrata Banike5e94392015-08-22 11:10:22 +053036 GP_SE_02, /* MF_PLT_CLK1, RAMID2 */
Matt DeVillier869f22f2017-08-24 14:47:28 -050037 GP_SW_64, /* I2C3_SDA, RAMID3 */
Subrata Banike5e94392015-08-22 11:10:22 +053038 };
39
Matt DeVilliere69a9c72017-08-20 14:48:57 -050040 return gpio_base2_value(spd_gpios, ARRAY_SIZE(spd_gpios));
41}
42
43static void *get_spd_pointer(char *spd_file_content, int total_spds, int *dual)
44{
45 int ram_id = 0;
46 int spd_index = 0;
47
48 ram_id = get_ramid();
Lee Leahy89b5fbd2015-05-11 17:24:31 -070049 printk(BIOS_DEBUG, "ram_id=%d, total_spds: %d\n", ram_id, total_spds);
Matt DeVilliere69a9c72017-08-20 14:48:57 -050050
51 spd_index = get_variant_spd_index(ram_id, dual);
52 if (spd_index >= total_spds) {
53 printk(BIOS_ERR, "SPD index > total SPDs\n");
Lee Leahy89b5fbd2015-05-11 17:24:31 -070054 return NULL;
Lee Leahy89b5fbd2015-05-11 17:24:31 -070055 }
Lee Leahy89b5fbd2015-05-11 17:24:31 -070056 /* Return the serial product data for the RAM */
Matt DeVilliere69a9c72017-08-20 14:48:57 -050057 return &spd_file_content[SPD_PAGE_LEN * spd_index];
Lee Leahy89b5fbd2015-05-11 17:24:31 -070058}
59
60/* Copy SPD data for on-board memory */
61void mainboard_fill_spd_data(struct pei_data *ps)
62{
63 char *spd_file;
64 size_t spd_file_len;
65 void *spd_content;
66 int dual_channel = 0;
67
68 /* Find the SPD data in CBFS. */
69 spd_file = cbfs_boot_map_with_leak("spd.bin", CBFS_TYPE_SPD,
70 &spd_file_len);
71 if (!spd_file)
72 die("SPD data not found.");
73
Matt DeVillier869f22f2017-08-24 14:47:28 -050074 if (spd_file_len < SPD_PAGE_LEN)
Lee Leahy89b5fbd2015-05-11 17:24:31 -070075 die("Missing SPD data.");
76
Lee Leahy89b5fbd2015-05-11 17:24:31 -070077 /*
78 * Both channels are always present in SPD data. Always use matched
79 * DIMMs so use the same SPD data for each DIMM.
80 */
81 spd_content = get_spd_pointer(spd_file,
Matt DeVillier869f22f2017-08-24 14:47:28 -050082 spd_file_len / SPD_PAGE_LEN,
Lee Leahy89b5fbd2015-05-11 17:24:31 -070083 &dual_channel);
84 if (IS_ENABLED(CONFIG_DISPLAY_SPD_DATA) && spd_content != NULL) {
85 printk(BIOS_DEBUG, "SPD Data:\n");
Matt DeVillier869f22f2017-08-24 14:47:28 -050086 hexdump(spd_content, SPD_PAGE_LEN);
Lee Leahy89b5fbd2015-05-11 17:24:31 -070087 printk(BIOS_DEBUG, "\n");
88 }
89
90 /*
91 * Set SPD and memory configuration:
92 * Memory type: 0=DimmInstalled,
93 * 1=SolderDownMemory,
94 * 2=DimmDisabled
95 */
96 if (spd_content != NULL) {
97 ps->spd_data_ch0 = spd_content;
98 ps->spd_ch0_config = 1;
99 printk(BIOS_DEBUG, "Channel 0 DIMM soldered down\n");
100 if (dual_channel) {
101 printk(BIOS_DEBUG, "Channel 1 DIMM soldered down\n");
102 ps->spd_data_ch1 = spd_content;
103 ps->spd_ch1_config = 1;
104 } else {
105 printk(BIOS_DEBUG, "Channel 1 DIMM not installed\n");
106 ps->spd_ch1_config = 2;
107 }
108 }
109}
110
Matt DeVillier869f22f2017-08-24 14:47:28 -0500111static void set_dimm_info(uint8_t *spd, struct dimm_info *dimm)
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700112{
Matt DeVillier869f22f2017-08-24 14:47:28 -0500113 const int spd_capmb[8] = { 1, 2, 4, 8, 16, 32, 64, 0 };
114 const int spd_ranks[8] = { 1, 2, 3, 4, -1, -1, -1, -1 };
115 const int spd_devw[8] = { 4, 8, 16, 32, -1, -1, -1, -1 };
116 const int spd_busw[8] = { 8, 16, 32, 64, -1, -1, -1, -1 };
117
118 int capmb = spd_capmb[spd[SPD_DENSITY_BANKS] & 7] * 256;
119 int ranks = spd_ranks[(spd[SPD_ORGANIZATION] >> 3) & 7];
120 int devw = spd_devw[spd[SPD_ORGANIZATION] & 7];
121 int busw = spd_busw[spd[SPD_BUS_DEV_WIDTH] & 7];
122
123 void *hob_list_ptr;
124 EFI_HOB_GUID_TYPE *hob_ptr;
125 FSP_SMBIOS_MEMORY_INFO *memory_info_hob;
126 const EFI_GUID memory_info_hob_guid = FSP_SMBIOS_MEMORY_INFO_GUID;
127
128 /* Locate the memory info HOB, presence validated by raminit */
129 hob_list_ptr = fsp_get_hob_list();
130 hob_ptr = get_next_guid_hob(&memory_info_hob_guid, hob_list_ptr);
131 if (hob_ptr != NULL) {
132 memory_info_hob = (FSP_SMBIOS_MEMORY_INFO *)(hob_ptr + 1);
133 dimm->ddr_frequency = memory_info_hob->MemoryFrequencyInMHz;
134 } else {
135 printk(BIOS_ERR, "Can't get memory info hob pointer\n");
136 dimm->ddr_frequency = 0;
137 }
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700138
139 /* Parse the SPD data to determine the DIMM information */
Matt DeVillier4f20a4a2017-08-20 17:56:48 -0500140 if (IS_ENABLED(CONFIG_BOARD_GOOGLE_CYAN)) {
Elyes HAOUAS28114ae2018-11-14 17:51:00 +0100141 dimm->ddr_type = MEMORY_TYPE_DDR3;
Matt DeVillier4f20a4a2017-08-20 17:56:48 -0500142 } else {
Elyes HAOUAS28114ae2018-11-14 17:51:00 +0100143 dimm->ddr_type = MEMORY_TYPE_LPDDR3;
Matt DeVillier4f20a4a2017-08-20 17:56:48 -0500144 }
Matt DeVillier869f22f2017-08-24 14:47:28 -0500145 dimm->dimm_size = capmb / 8 * busw / devw * ranks; /* MiB */
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700146 dimm->mod_type = spd[3] & 0xf;
Richard Spiegel90b30952018-04-17 10:09:17 -0700147 strncpy((char *)&dimm->module_part_number[0], (char *)&spd[0x80],
148 LPDDR3_SPD_PART_LEN);
149 dimm->module_part_number[LPDDR3_SPD_PART_LEN] = 0;
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700150 dimm->mod_id = *(uint16_t *)&spd[0x94];
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700151
Matt DeVillier869f22f2017-08-24 14:47:28 -0500152 switch (busw) {
Ravi Sarawadid077b582015-09-09 14:12:16 -0700153 default:
Matt DeVillier869f22f2017-08-24 14:47:28 -0500154 case 8:
155 dimm->bus_width = MEMORY_BUS_WIDTH_8;
156 break;
157
158 case 16:
159 dimm->bus_width = MEMORY_BUS_WIDTH_16;
160 break;
161
162 case 32:
163 dimm->bus_width = MEMORY_BUS_WIDTH_32;
164 break;
165
166 case 64:
167 dimm->bus_width = MEMORY_BUS_WIDTH_64;
168 break;
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700169 }
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700170}
171
172void mainboard_save_dimm_info(struct romstage_params *params)
173{
174 struct dimm_info *dimm;
175 struct memory_info *mem_info;
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700176
177 /*
178 * Allocate CBMEM area for DIMM information used to populate SMBIOS
179 * table 17
180 */
181 mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info));
182 printk(BIOS_DEBUG, "CBMEM entry for DIMM info: 0x%p\n", mem_info);
183 if (mem_info == NULL)
184 return;
185 memset(mem_info, 0, sizeof(*mem_info));
186
187 /* Describe the first channel memory */
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700188 dimm = &mem_info->dimm[0];
Matt DeVillier869f22f2017-08-24 14:47:28 -0500189 set_dimm_info(params->pei_data->spd_data_ch0, dimm);
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700190 mem_info->dimm_cnt = 1;
191
192 /* Describe the second channel memory */
193 if (params->pei_data->spd_ch1_config == 1) {
194 dimm = &mem_info->dimm[1];
Matt DeVillier869f22f2017-08-24 14:47:28 -0500195 set_dimm_info(params->pei_data->spd_data_ch1, dimm);
Lee Leahy89b5fbd2015-05-11 17:24:31 -0700196 dimm->channel_num = 1;
197 mem_info->dimm_cnt = 2;
198 }
199}