diff options
Diffstat (limited to 'src/mainboard/google/cyan/spd')
5 files changed, 340 insertions, 0 deletions
diff --git a/src/mainboard/google/cyan/spd/Makefile.inc b/src/mainboard/google/cyan/spd/Makefile.inc new file mode 100644 index 0000000000..1886a69a97 --- /dev/null +++ b/src/mainboard/google/cyan/spd/Makefile.inc @@ -0,0 +1,42 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2013 Google Inc. +## Copyright (C) 2015 Intel Corp. +## +## 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. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc. +## + +romstage-y += spd.c + +SPD_BIN = $(obj)/spd.bin + +SPD_SOURCES = samsung_2GiB_dimm_K4B4G1646Q-HYK0 +SPD_SOURCES += hynix_2GiB_dimm_HMT425S6CFR6A_H5TC4G63CFR +SPD_SOURCES += samsung_2GiB_dimm_K4B4G1646Q-HYK0 +SPD_SOURCES += hynix_2GiB_dimm_HMT425S6CFR6A_H5TC4G63CFR + +SPD_DEPS := $(foreach f, $(SPD_SOURCES), src/mainboard/$(MAINBOARDDIR)/spd/$(f).spd.hex) + +# Include spd rom data +$(SPD_BIN): $(SPD_DEPS) + for f in $+; \ + do for c in $$(cat $$f | grep -v ^#); \ + do printf $$(printf '\%o' 0x$$c); \ + done; \ + done > $@ + +cbfs-files-y += spd.bin +spd.bin-file := $(SPD_BIN) +spd.bin-type := spd diff --git a/src/mainboard/google/cyan/spd/hynix_2GiB_dimm_H5TC4G63AFR-PBA.spd.hex b/src/mainboard/google/cyan/spd/hynix_2GiB_dimm_H5TC4G63AFR-PBA.spd.hex new file mode 100644 index 0000000000..ff4fd29862 --- /dev/null +++ b/src/mainboard/google/cyan/spd/hynix_2GiB_dimm_H5TC4G63AFR-PBA.spd.hex @@ -0,0 +1,32 @@ +92 12 0b 03 04 19 02 02 +03 52 01 08 0a 00 fe 00 +69 78 69 3c 69 11 18 81 +20 08 3c 3c 01 40 83 01 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 0f 11 62 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 80 ad 01 +00 00 00 00 00 00 ff ab +48 4d 54 34 32 35 53 36 +41 46 52 36 41 2d 50 42 +20 20 4e 30 80 ad 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff +ff ff ff ff ff ff ff ff diff --git a/src/mainboard/google/cyan/spd/hynix_2GiB_dimm_HMT425S6CFR6A_H5TC4G63CFR.spd.hex b/src/mainboard/google/cyan/spd/hynix_2GiB_dimm_HMT425S6CFR6A_H5TC4G63CFR.spd.hex new file mode 100644 index 0000000000..fdd1a43bfa --- /dev/null +++ b/src/mainboard/google/cyan/spd/hynix_2GiB_dimm_HMT425S6CFR6A_H5TC4G63CFR.spd.hex @@ -0,0 +1,32 @@ +92 13 0B 03 04 19 02 02 +03 52 01 08 0A 00 FE 00 +69 78 69 3C 69 11 18 81 +20 08 3C 3C 01 40 83 01 +00 00 00 00 00 00 00 00 +00 88 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 0F 11 62 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 80 AD 01 +00 00 00 00 00 00 C9 C0 +48 4D 54 34 32 35 53 36 +43 46 52 36 41 2D 50 42 +20 20 4E 30 80 AD 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF +FF FF FF FF FF FF FF FF diff --git a/src/mainboard/google/cyan/spd/samsung_2GiB_dimm_K4B4G1646Q-HYK0.spd.hex b/src/mainboard/google/cyan/spd/samsung_2GiB_dimm_K4B4G1646Q-HYK0.spd.hex new file mode 100644 index 0000000000..e0b0ac5f43 --- /dev/null +++ b/src/mainboard/google/cyan/spd/samsung_2GiB_dimm_K4B4G1646Q-HYK0.spd.hex @@ -0,0 +1,32 @@ +92 12 0B 03 04 19 02 02 +03 11 01 08 0A 00 FE 00 +69 78 69 3C 69 11 18 81 +20 08 3C 3C 01 40 83 05 +00 00 00 00 00 00 00 00 +88 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 0F 01 02 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 80 CE 01 +00 00 00 00 00 00 6C F9 +4D 34 37 31 42 35 36 37 +34 51 48 30 2D 59 4B 30 +20 20 00 00 80 CE 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 diff --git a/src/mainboard/google/cyan/spd/spd.c b/src/mainboard/google/cyan/spd/spd.c new file mode 100644 index 0000000000..fd884607a1 --- /dev/null +++ b/src/mainboard/google/cyan/spd/spd.c @@ -0,0 +1,202 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Google Inc. + * Copyright (C) 2015 Intel Corp. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <cbfs.h> +#include <cbmem.h> +#include <console/console.h> +#include <lib.h> +#include <memory_info.h> +#include <smbios.h> +#include <spd.h> +#include <soc/gpio.h> +#include <soc/romstage.h> +#include <string.h> + +#define SPD_SIZE 256 +#define SATA_GP3_PAD_CFG0 0x5828 +#define I2C3_SCL_PAD_CFG0 0x5438 +#define MF_PLT_CLK1_PAD_CFG0 0x4410 +#define I2C3_SDA_PAD_CFG0 0x5420 + +/* + * 0b0000 - 4GiB total - 2 x 2GiB Samsung K4B4G1646Q-HYK0 1600MHz + * 0b0001 - 4GiB total - 2 x 2GiB Hynix H5TC4G63CFR-PBA 1600MHz + * 0b0010 - 2GiB total - 1 x 2GiB Samsung K4B4G1646Q-HYK0 1600MHz + * 0b0011 - 2GiB total - 1 x 2GiB Hynix H5TC4G63CFR-PBA 1600MHz + */ +static const uint32_t dual_channel_config = (1 << 0) | (1 << 1); + +static void configure_ramid_gpios(void) +{ + write32((void *)(COMMUNITY_GPSOUTHWEST_BASE + SATA_GP3_PAD_CFG0), + (PAD_PULL_DISABLE | PAD_GPIO_ENABLE | PAD_CONFIG0_GPI_DEFAULT)); + write32((void *)(COMMUNITY_GPSOUTHEAST_BASE + MF_PLT_CLK1_PAD_CFG0), + (PAD_PULL_DISABLE | PAD_GPIO_ENABLE | PAD_CONFIG0_GPI_DEFAULT)); +} + +static void *get_spd_pointer(char *spd_file_content, int total_spds, int *dual) +{ + int ram_id = 0; + ram_id |= get_gpio(COMMUNITY_GPSOUTHWEST_BASE, SATA_GP3_PAD_CFG0) << 0; + ram_id |= get_gpio(COMMUNITY_GPSOUTHWEST_BASE, I2C3_SCL_PAD_CFG0) << 1; + ram_id |= get_gpio(COMMUNITY_GPSOUTHEAST_BASE, MF_PLT_CLK1_PAD_CFG0) + << 2; + ram_id |= get_gpio(COMMUNITY_GPSOUTHWEST_BASE, I2C3_SDA_PAD_CFG0) << 3; + printk(BIOS_DEBUG, "ram_id=%d, total_spds: %d\n", ram_id, total_spds); + if (ram_id >= total_spds) + return NULL; + + /* Determine if this is a single or dual channel memory system */ + if (dual_channel_config & (1 << ram_id)) + *dual = 1; + + /* Display the RAM type */ + switch (ram_id) { + case 0: + case 2: + printk(BIOS_DEBUG, "2GiB Samsung K4B4G1646Q-HYK0 1600MHz\n"); + break; + case 1: + case 3: + printk(BIOS_DEBUG, "2GiB Hynix H5TC4G63CFR-PBA 1600MHz\n"); + break; + } + + /* Return the serial product data for the RAM */ + return &spd_file_content[SPD_SIZE * ram_id]; +} + +/* Copy SPD data for on-board memory */ +void mainboard_fill_spd_data(struct pei_data *ps) +{ + char *spd_file; + size_t spd_file_len; + void *spd_content; + int dual_channel = 0; + + /* Find the SPD data in CBFS. */ + spd_file = cbfs_boot_map_with_leak("spd.bin", CBFS_TYPE_SPD, + &spd_file_len); + if (!spd_file) + die("SPD data not found."); + + if (spd_file_len < SPD_SIZE) + die("Missing SPD data."); + + configure_ramid_gpios(); + + /* + * Both channels are always present in SPD data. Always use matched + * DIMMs so use the same SPD data for each DIMM. + */ + spd_content = get_spd_pointer(spd_file, + spd_file_len / SPD_SIZE, + &dual_channel); + if (IS_ENABLED(CONFIG_DISPLAY_SPD_DATA) && spd_content != NULL) { + printk(BIOS_DEBUG, "SPD Data:\n"); + hexdump(spd_content, SPD_SIZE); + printk(BIOS_DEBUG, "\n"); + } + + /* + * Set SPD and memory configuration: + * Memory type: 0=DimmInstalled, + * 1=SolderDownMemory, + * 2=DimmDisabled + */ + if (spd_content != NULL) { + ps->spd_data_ch0 = spd_content; + ps->spd_ch0_config = 1; + printk(BIOS_DEBUG, "Channel 0 DIMM soldered down\n"); + if (dual_channel) { + printk(BIOS_DEBUG, "Channel 1 DIMM soldered down\n"); + ps->spd_data_ch1 = spd_content; + ps->spd_ch1_config = 1; + } else { + printk(BIOS_DEBUG, "Channel 1 DIMM not installed\n"); + ps->spd_ch1_config = 2; + } + } +} + +static void set_dimm_info(uint32_t chips, uint8_t *spd, struct dimm_info *dimm) +{ + uint16_t clock_frequency; + uint32_t log2_chips; + + /* 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 */ + 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; + } + 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 + * table 17 + */ + mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info)); + printk(BIOS_DEBUG, "CBMEM entry for DIMM info: 0x%p\n", mem_info); + if (mem_info == NULL) + return; + 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); + 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); + dimm->channel_num = 1; + mem_info->dimm_cnt = 2; + } +} |