Matt DeVillier has uploaded this change for review. ( https://review.coreboot.org/21197
Change subject: google/cyan: update SPD functions ......................................................................
google/cyan: update SPD functions
Update cyan's SPD-related functions to more closely mirror those of other Braswell boards, in order to simplify the upcoming baseboard/variant setup for Braswell ChromeOS boards.
TEST: boot google/cyan, observe SPD correctly identified in cbmem log, RAM-related data correct in SMBIOS tables.
Change-Id: Iafe99ec0795764f645e0a91f5b321be5b4c6fd88 Signed-off-by: Matt DeVillier matt.devillier@gmail.com --- M src/mainboard/google/cyan/spd/spd.c A src/mainboard/google/cyan/spd/spd.h 2 files changed, 86 insertions(+), 36 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/97/21197/1
diff --git a/src/mainboard/google/cyan/spd/spd.c b/src/mainboard/google/cyan/spd/spd.c index cbe8ceb..cd263e5 100644 --- a/src/mainboard/google/cyan/spd/spd.c +++ b/src/mainboard/google/cyan/spd/spd.c @@ -25,8 +25,7 @@ #include <soc/gpio.h> #include <soc/romstage.h> #include <string.h> - -#define SPD_SIZE 256 +#include "spd.h"
/* * 0b0000 - 4GiB total - 2 x 2GiB Samsung K4B4G1646Q-HYK0 1600MHz @@ -46,10 +45,10 @@ int ram_id = 0;
gpio_t spd_gpios[] = { - GP_SW_80, /* SATA_GP3,RAMID0 */ - GP_SW_67, /* I2C3_SCL,RAMID1 */ + GP_SW_80, /* SATA_GP3, RAMID0 */ + GP_SW_67, /* I2C3_SCL, RAMID1 */ GP_SE_02, /* MF_PLT_CLK1, RAMID2 */ - GP_SW_64, /* I2C3_SDA RAMID3 */ + GP_SW_64, /* I2C3_SDA, RAMID3 */ };
ram_id = gpio_base2_value(spd_gpios, ARRAY_SIZE(spd_gpios)); @@ -90,7 +89,7 @@ }
/* Return the serial product data for the RAM */ - return &spd_file_content[SPD_SIZE * ram_id]; + return &spd_file_content[SPD_LEN * ram_id]; }
/* Copy SPD data for on-board memory */ @@ -107,7 +106,7 @@ if (!spd_file) die("SPD data not found.");
- if (spd_file_len < SPD_SIZE) + if (spd_file_len < SPD_LEN) die("Missing SPD data.");
/* @@ -115,11 +114,11 @@ * DIMMs so use the same SPD data for each DIMM. */ spd_content = get_spd_pointer(spd_file, - spd_file_len / SPD_SIZE, + spd_file_len / SPD_LEN, &dual_channel); if (IS_ENABLED(CONFIG_DISPLAY_SPD_DATA) && spd_content != NULL) { printk(BIOS_DEBUG, "SPD Data:\n"); - hexdump(spd_content, SPD_SIZE); + hexdump(spd_content, SPD_LEN); printk(BIOS_DEBUG, "\n"); }
@@ -144,48 +143,69 @@ } }
-static void set_dimm_info(uint32_t chips, uint8_t *spd, struct dimm_info *dimm) +static void set_dimm_info(uint8_t *spd, struct dimm_info *dimm) { + const int spd_capmb[8] = { 1, 2, 4, 8, 16, 32, 64, 0 }; + const int spd_ranks[8] = { 1, 2, 3, 4, -1, -1, -1, -1 }; + const int spd_devw[8] = { 4, 8, 16, 32, -1, -1, -1, -1 }; + const int spd_busw[8] = { 8, 16, 32, 64, -1, -1, -1, -1 }; uint16_t clock_frequency; - uint32_t log2_chips; + + int capmb = spd_capmb[spd[SPD_DENSITY_BANKS] & 7] * 256; + int ranks = spd_ranks[(spd[SPD_ORGANIZATION] >> 3) & 7]; + int devw = spd_devw[spd[SPD_ORGANIZATION] & 7]; + int busw = spd_busw[spd[SPD_BUS_DEV_WIDTH] & 7]; + + void *hob_list_ptr; + EFI_HOB_GUID_TYPE *hob_ptr; + FSP_SMBIOS_MEMORY_INFO *memory_info_hob; + const EFI_GUID memory_info_hob_guid = FSP_SMBIOS_MEMORY_INFO_GUID; + + /* Locate the memory info HOB, presence validated by raminit */ + hob_list_ptr = fsp_get_hob_list(); + hob_ptr = get_next_guid_hob(&memory_info_hob_guid, hob_list_ptr); + if (hob_ptr != NULL) { + memory_info_hob = (FSP_SMBIOS_MEMORY_INFO *)(hob_ptr + 1); + dimm->ddr_frequency = memory_info_hob->MemoryFrequencyInMHz; + } else { + printk(BIOS_ERR, "Can't get memory info hob pointer\n"); + dimm->ddr_frequency = 0; + }
/* Parse the SPD data to determine the DIMM information */ - dimm->ddr_type = MEMORY_TYPE_DDR3; - dimm->dimm_size = (chips << (spd[4] & 0xf)) << (28 - 3 - 20); /* MiB */ + dimm->ddr_type = MEMORY_DEVICE_LPDDR3; + dimm->dimm_size = capmb / 8 * busw / devw * ranks; /* MiB */ clock_frequency = 1000 * spd[11] / (spd[10] * spd[12]); /* MHz */ dimm->ddr_frequency = 2 * clock_frequency; /* Double Data Rate */ dimm->mod_type = spd[3] & 0xf; memcpy((char *)&dimm->module_part_number[0], &spd[0x80], sizeof(dimm->module_part_number) - 1); dimm->mod_id = *(uint16_t *)&spd[0x94]; - switch (chips) { - case 1: - log2_chips = 0; - break;
- case 2: - log2_chips = 1; - break; - - case 4: - log2_chips = 2; - break; - - case 8: - log2_chips = 3; - break; - + switch (busw) { default: - log2_chips = 0; + case 8: + dimm->bus_width = MEMORY_BUS_WIDTH_8; + break; + + case 16: + dimm->bus_width = MEMORY_BUS_WIDTH_16; + break; + + case 32: + dimm->bus_width = MEMORY_BUS_WIDTH_32; + break; + + case 64: + dimm->bus_width = MEMORY_BUS_WIDTH_64; + break; } - dimm->bus_width = (uint8_t)(log2_chips + (spd[7] & 7) + 2 - 3); }
void mainboard_save_dimm_info(struct romstage_params *params) { struct dimm_info *dimm; struct memory_info *mem_info; - uint32_t chips;
/* * Allocate CBMEM area for DIMM information used to populate SMBIOS @@ -198,16 +218,15 @@ memset(mem_info, 0, sizeof(*mem_info));
/* Describe the first channel memory */ - chips = 4; dimm = &mem_info->dimm[0]; - set_dimm_info(chips, params->pei_data->spd_data_ch0, dimm); + set_dimm_info(params->pei_data->spd_data_ch0, dimm); mem_info->dimm_cnt = 1;
/* Describe the second channel memory */ if (params->pei_data->spd_ch1_config == 1) { dimm = &mem_info->dimm[1]; - set_dimm_info(chips, params->pei_data->spd_data_ch1, dimm); + set_dimm_info(params->pei_data->spd_data_ch1, dimm); dimm->channel_num = 1; mem_info->dimm_cnt = 2; } -} +} \ No newline at end of file diff --git a/src/mainboard/google/cyan/spd/spd.h b/src/mainboard/google/cyan/spd/spd.h new file mode 100644 index 0000000..ec044d6 --- /dev/null +++ b/src/mainboard/google/cyan/spd/spd.h @@ -0,0 +1,31 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Google Inc. + * Copyright (C) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MAINBOARD_SPD_H_ +#define _MAINBOARD_SPD_H_ + +#define SPD_LEN 256 +#define SPD_DRAM_TYPE 2 +#define SPD_DRAM_DDR3 0x0b +#define SPD_DRAM_LPDDR3 0xf1 +#define SPD_DENSITY_BANKS 4 +#define SPD_ADDRESSING 5 +#define SPD_ORGANIZATION 7 +#define SPD_BUS_DEV_WIDTH 8 +#define SPD_PART_OFF 128 +#define SPD_PART_LEN 18 + +#endif /* _MAINBOARD_SPD_H_ */