Meera Ravindranath has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/39135 )
Change subject: src/soc/tigerlake: Add memory configuration support for Jasper Lake ......................................................................
src/soc/tigerlake: Add memory configuration support for Jasper Lake
BUG=none BRANCH=none TEST=Build and verify boot of WaddleDoo.
Change-Id: I8de502d3f05d52b9dae34e3b013c6d5b1896fa85 Signed-off-by: Meera Ravindranath meera.ravindranath@intel.com --- M src/soc/intel/tigerlake/Makefile.inc A src/soc/intel/tigerlake/include/soc/jsl_memcfg_init.h A src/soc/intel/tigerlake/jsl_memcfg_init.c 3 files changed, 305 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/35/39135/1
diff --git a/src/soc/intel/tigerlake/Makefile.inc b/src/soc/intel/tigerlake/Makefile.inc index 56119f5..c85f9dc 100644 --- a/src/soc/intel/tigerlake/Makefile.inc +++ b/src/soc/intel/tigerlake/Makefile.inc @@ -26,6 +26,7 @@ romstage-y += espi.c romstage-y += gpio.c romstage-$(CONFIG_SOC_INTEL_TIGERLAKE) += meminit_tgl.c +romstage-$(CONFIG_SOC_INTEL_JASPERLAKE) += jsl_memcfg_init.c romstage-y += reset.c
ramstage-y += acpi.c diff --git a/src/soc/intel/tigerlake/include/soc/jsl_memcfg_init.h b/src/soc/intel/tigerlake/include/soc/jsl_memcfg_init.h new file mode 100644 index 0000000..e04ef85 --- /dev/null +++ b/src/soc/intel/tigerlake/include/soc/jsl_memcfg_init.h @@ -0,0 +1,139 @@ +/* + * This file is part of the coreboot project. + * + * Copyright Intel Corporation 2020. + * + * 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 _SOC_JASPERLAKE_MEMCFG_INIT_H_ +#define _SOC_JASPERLAKE_MEMCFG_INIT_H_ + +#include <stddef.h> +#include <stdint.h> +#include <fsp/soc_binding.h> + +/* Number of dq bits controlled per dqs */ +#define DQ_BITS_PER_DQS 8 + +/* Number of memory DIMM slots available on Cannonlake board */ +#define NUM_DIMM_SLOT 4 + +/* + * Number of memory packages, where a "package" represents a 64-bit solution. + */ +#define DDR_NUM_PACKAGES 2 + +/* 64-bit Channel identification */ +enum { + DDR_CH0, + DDR_CH1, + DDR_NUM_CHANNELS +}; + +struct spd_by_pointer { + size_t spd_data_len; + uintptr_t spd_data_ptr; +}; + +enum mem_info_read_type { + NOT_EXISTING, /* No memory in this slot */ + READ_SMBUS, /* Read on-module spd by SMBUS. */ + READ_SPD_CBFS, /* Find spd file in CBFS. */ + READ_SPD_MEMPTR /* Find spd data from pointer. */ +}; + +struct spd_info { + enum mem_info_read_type read_type; + union spd_data_by { + /* To read on-module spd when read_type is READ_SMBUS. */ + uint8_t spd_smbus_address; + + /* To identify spd file when read_type is READ_SPD_CBFS. */ + int spd_index; + + /* To find spd data when read_type is READ_SPD_MEMPTR. */ + struct spd_by_pointer spd_data_ptr_info; + } spd_spec; +}; + +/* Board-specific memory dq mapping information */ +struct jsl_mb_cfg { + /* Parameters required to access SPD for CH0D0/CH0D1/CH1D0/CH1D1. */ + struct spd_info spd[NUM_DIMM_SLOT]; + + /* + * For each channel, there are 6 sets of DQ byte mappings, + * where each set has a package 0 and a package 1 value (package 0 + * represents the first 64-bit lpddr4 chip combination, and package 1 + * represents the second 64-bit lpddr4 chip combination). + * The first three sets are for CLK, CMD, and CTL. + * The fsp package actually expects 6 sets, even though the last 3 sets + * are not used in CNL. + * We let the meminit_lpddr4() routine take care of clearing the + * unused fields for the caller. + * Note that dq_map is only used by LPDDR; it does not need to be + * initialized for designs using DDR4. + */ + uint8_t dq_map[DDR_NUM_CHANNELS][6][DDR_NUM_PACKAGES]; + + /* + * DQS CPU<>DRAM map Ch0 and Ch1. Each array entry represents a + * mapping of a dq bit on the CPU to the bit it's connected to on + * the memory part. The array index represents the dqs bit number + * on the memory part, and the values in the array represent which + * pin on the CPU that DRAM pin connects to. + * dqs_map is only used by LPDDR; same comments apply as for dq_map + * above. + */ + uint8_t dqs_map[DDR_NUM_CHANNELS][DQ_BITS_PER_DQS]; + + /* + * Rcomp resistor values. These values represent the resistance in + * ohms of the three rcomp resistors attached to the DDR_COMP_0, + * DDR_COMP_1, and DDR_COMP_2 pins on the DRAM. + */ + uint16_t rcomp_resistor[3]; + + /* + * Rcomp target values. These will typically be the following + * values for Cannon Lake : { 80, 40, 40, 40, 30 } + */ + uint16_t rcomp_targets[5]; + + /* + * Indicates whether memory is interleaved. + * Set to 1 for an interleaved design, + * set to 0 for non-interleaved design. + */ + uint8_t dq_pins_interleaved; + + /* + * VREF_CA configuration. + * Set to 0 VREF_CA goes to both CH_A and CH_B, + * set to 1 VREF_CA goes to CH_A and VREF_DQ_A goes to CH_B, + * set to 2 VREF_CA goes to CH_A and VREF_DQ_B goes to CH_B. + */ + uint8_t vref_ca_config; + + /* Early Command Training Enabled */ + uint8_t ect; + + /* Board type */ + uint8_t UserBd; +}; + +/* + * Initialize default memory configurations for CannonLake. + */ +void jasperlake_memcfg_init(FSP_M_CONFIG *mem_cfg, + const struct jsl_mb_cfg *jsl_cfg); + +#endif /* _SOC_JASPERLAKE_MEMCFG_INIT_H_ */ diff --git a/src/soc/intel/tigerlake/jsl_memcfg_init.c b/src/soc/intel/tigerlake/jsl_memcfg_init.c new file mode 100644 index 0000000..c8e2c03 --- /dev/null +++ b/src/soc/intel/tigerlake/jsl_memcfg_init.c @@ -0,0 +1,165 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017 Google Inc. + * + * 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. + */ +#include <assert.h> +#include <console/console.h> +#include <fsp/util.h> +#include <soc/jsl_memcfg_init.h> +#include <spd_bin.h> +#include <string.h> + +static void meminit_memcfg(FSP_M_CONFIG *mem_cfg, + const struct jsl_mb_cfg *board_cfg) +{ + /* + * DqByteMapChx expects 12 bytes of data, but the last 6 bytes + * are unused, so client passes in the relevant values and + * we null out the rest of the data. + */ + memset(&mem_cfg->DqByteMapCh0, 0, sizeof(mem_cfg->DqByteMapCh0)); + memcpy(&mem_cfg->DqByteMapCh0, &board_cfg->dq_map[DDR_CH0], + sizeof(board_cfg->dq_map[DDR_CH0])); + + memset(&mem_cfg->DqByteMapCh1, 0, sizeof(mem_cfg->DqByteMapCh1)); + memcpy(&mem_cfg->DqByteMapCh1, &board_cfg->dq_map[DDR_CH1], + sizeof(board_cfg->dq_map[DDR_CH1])); + + memcpy(&mem_cfg->DqsMapCpu2DramCh0, &board_cfg->dqs_map[DDR_CH0], + sizeof(board_cfg->dqs_map[DDR_CH0])); + memcpy(&mem_cfg->DqsMapCpu2DramCh1, &board_cfg->dqs_map[DDR_CH1], + sizeof(board_cfg->dqs_map[DDR_CH1])); + + memcpy(&mem_cfg->RcompResistor, &board_cfg->rcomp_resistor, + sizeof(mem_cfg->RcompResistor)); + + /* Early cannonlake requires rcomp targets to be 0 */ + memcpy(&mem_cfg->RcompTarget, &board_cfg->rcomp_targets, + sizeof(mem_cfg->RcompTarget)); + + mem_cfg->UserBd = board_cfg->UserBd; + +} + +/* + * Initialize default memory settings using spd data contained in a buffer. + */ +static void meminit_spd_data(FSP_M_CONFIG *mem_cfg, uint8_t mem_slot, + size_t spd_data_len, uintptr_t spd_data_ptr) +{ + static size_t last_set_spd_data_len = 0; + + assert(spd_data_ptr != 0 && spd_data_len != 0); + + if (last_set_spd_data_len != 0 && + last_set_spd_data_len != spd_data_len) + die("spd data length disparity among slots"); + + mem_cfg->MemorySpdDataLen = spd_data_len; + last_set_spd_data_len = spd_data_len; + + switch (mem_slot) { + case 0: + mem_cfg->MemorySpdPtr00 = spd_data_ptr; + break; + case 1: + mem_cfg->MemorySpdPtr01 = spd_data_ptr; + break; + case 2: + mem_cfg->MemorySpdPtr10 = spd_data_ptr; + break; + case 3: + mem_cfg->MemorySpdPtr11 = spd_data_ptr; + break; + default: + die("nonexistent memory slot"); + } + printk(BIOS_INFO, "memory slot: %d configuration done.\n", mem_slot); +} + +/* + * Initialize default memory settings using the spd file specified by + * spd_index. The spd_index is an index into the SPD_SOURCES array defined + * in spd/Makefile.inc. + */ +static void meminit_cbfs_spd_index(FSP_M_CONFIG *mem_cfg, + int spd_index, uint8_t mem_slot) +{ + static size_t spd_data_len; + static uintptr_t spd_data_ptr; + static int last_spd_index; + + assert(mem_slot < NUM_DIMM_SLOT); + + if ((spd_data_ptr == 0) || (last_spd_index != spd_index)) { + struct region_device spd_rdev; + + printk(BIOS_DEBUG, "SPD INDEX = %d\n", spd_index); + + if (get_spd_cbfs_rdev(&spd_rdev, spd_index) < 0) + die("spd.bin not found or incorrect index\n"); + + spd_data_len = region_device_sz(&spd_rdev); + + /* Memory leak is ok since we have memory mapped boot media */ + assert(CONFIG(BOOT_DEVICE_MEMORY_MAPPED)); + + spd_data_ptr = (uintptr_t)rdev_mmap_full(&spd_rdev); + last_spd_index = spd_index; + print_spd_info((unsigned char *)spd_data_ptr); + } + + meminit_spd_data(mem_cfg, mem_slot, spd_data_len, spd_data_ptr); +} + +/* Initialize onboard memory configurations for CannonLake */ +void jasperlake_memcfg_init(FSP_M_CONFIG *mem_cfg, + const struct jsl_mb_cfg *jsl_cfg) +{ + const struct spd_info *spdi; + + /* Early Command Training Enabled */ + mem_cfg->ECT = jsl_cfg->ect; + mem_cfg->DqPinsInterleaved = jsl_cfg->dq_pins_interleaved; + mem_cfg->CaVrefConfig = jsl_cfg->vref_ca_config; + + for (int i = 0; i < NUM_DIMM_SLOT; i++) { + spdi = &(jsl_cfg->spd[i]); + switch (spdi->read_type) { + case NOT_EXISTING: + break; + + case READ_SMBUS: + mem_cfg->SpdAddressTable[i] = + spdi->spd_spec.spd_smbus_address; + break; + + case READ_SPD_CBFS: + mem_cfg->SpdAddressTable[i] = 0; + meminit_cbfs_spd_index(mem_cfg, + spdi->spd_spec.spd_index, i); + break; + + case READ_SPD_MEMPTR: + meminit_spd_data(mem_cfg, i, + spdi->spd_spec.spd_data_ptr_info.spd_data_len, + spdi->spd_spec.spd_data_ptr_info.spd_data_ptr); + break; + + default: + die("no valid way to read mem info"); + } + + meminit_memcfg(mem_cfg, jsl_cfg); + } +}