aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/cannonlake/Kconfig4
-rw-r--r--src/soc/intel/cannonlake/Makefile.inc1
-rw-r--r--src/soc/intel/cannonlake/cnl_lpddr4_init.c111
-rw-r--r--src/soc/intel/cannonlake/include/soc/cnl_lpddr4_init.h106
4 files changed, 222 insertions, 0 deletions
diff --git a/src/soc/intel/cannonlake/Kconfig b/src/soc/intel/cannonlake/Kconfig
index a19a371374..715cdf4ebb 100644
--- a/src/soc/intel/cannonlake/Kconfig
+++ b/src/soc/intel/cannonlake/Kconfig
@@ -131,6 +131,10 @@ config CPU_BCLK_MHZ
int
default 100
+config SOC_INTEL_CANNONLAKE_LPDDR4_INIT
+ bool
+ default n
+
config SOC_INTEL_COMMON_LPSS_CLOCK_MHZ
int
default 120
diff --git a/src/soc/intel/cannonlake/Makefile.inc b/src/soc/intel/cannonlake/Makefile.inc
index 61318a4282..d4ca4072bd 100644
--- a/src/soc/intel/cannonlake/Makefile.inc
+++ b/src/soc/intel/cannonlake/Makefile.inc
@@ -20,6 +20,7 @@ bootblock-y += memmap.c
bootblock-y += spi.c
bootblock-$(CONFIG_UART_DEBUG) += uart.c
+romstage-$(CONFIG_SOC_INTEL_CANNONLAKE_LPDDR4_INIT) += cnl_lpddr4_init.c
romstage-y += gpio.c
romstage-y += gspi.c
romstage-y += i2c.c
diff --git a/src/soc/intel/cannonlake/cnl_lpddr4_init.c b/src/soc/intel/cannonlake/cnl_lpddr4_init.c
new file mode 100644
index 0000000000..ea8c410267
--- /dev/null
+++ b/src/soc/intel/cannonlake/cnl_lpddr4_init.c
@@ -0,0 +1,111 @@
+/*
+ * 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/cnl_lpddr4_init.h>
+#include <spd_bin.h>
+#include <string.h>
+
+static void meminit_lpddr4(FSP_M_CONFIG *mem_cfg,
+ const struct lpddr4_cfg *board_cfg,
+ size_t spd_data_len, uintptr_t spd_data_ptr)
+{
+ /*
+ * 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[LP4_CH0],
+ sizeof(board_cfg->dq_map[LP4_CH0]));
+
+ memset(&mem_cfg->DqByteMapCh1, 0, sizeof(mem_cfg->DqByteMapCh1));
+ memcpy(&mem_cfg->DqByteMapCh1, &board_cfg->dq_map[LP4_CH1],
+ sizeof(board_cfg->dq_map[LP4_CH1]));
+
+ memcpy(&mem_cfg->DqsMapCpu2DramCh0, &board_cfg->dqs_map[LP4_CH0],
+ sizeof(board_cfg->dqs_map[LP4_CH0]));
+ memcpy(&mem_cfg->DqsMapCpu2DramCh1, &board_cfg->dqs_map[LP4_CH1],
+ sizeof(board_cfg->dqs_map[LP4_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->MemorySpdDataLen = spd_data_len;
+ mem_cfg->MemorySpdPtr00 = spd_data_ptr;
+
+ /* Use the same spd data for channel 1, Dimm 0 */
+ mem_cfg->MemorySpdPtr10 = mem_cfg->MemorySpdPtr00;
+}
+
+/*
+ * Initialize default LPDDR4 settings using spd data contained in a buffer.
+ */
+static void meminit_lpddr4_spd_data(FSP_M_CONFIG *mem_cfg,
+ const struct lpddr4_cfg *cnl_cfg,
+ size_t spd_data_len, uintptr_t spd_data_ptr)
+{
+ assert(spd_data_ptr && spd_data_len);
+ meminit_lpddr4(mem_cfg, cnl_cfg, spd_data_len, spd_data_ptr);
+}
+
+/*
+ * Initialize default LPDDR4 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_lpddr4_cbfs_spd_index(FSP_M_CONFIG *mem_cfg,
+ const struct lpddr4_cfg *cnl_cfg,
+ int spd_index)
+{
+ size_t spd_data_len;
+ uintptr_t spd_data_ptr;
+ 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(IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED));
+ spd_data_ptr = (uintptr_t)rdev_mmap_full(&spd_rdev);
+ meminit_lpddr4_spd_data(mem_cfg, cnl_cfg, spd_data_len, spd_data_ptr);
+}
+
+/* Initialize LPDDR4 settings for CannonLake */
+void cannonlake_lpddr4_init(FSP_M_CONFIG *mem_cfg,
+ const struct lpddr4_cfg *cnl_cfg,
+ const struct spd_info *spd)
+{
+ /* Early Command Training Enabled */
+ mem_cfg->ECT = cnl_cfg->ect;
+ mem_cfg->DqPinsInterleaved = cnl_cfg->dq_pins_interleaved;
+ mem_cfg->RefClk = 0; /* Auto Select CLK freq */
+ mem_cfg->CaVrefConfig = 0; /* VREF_CA->CHA/CHB */
+
+ if (spd->spd_by_index) {
+ meminit_lpddr4_cbfs_spd_index(mem_cfg, cnl_cfg,
+ spd->spd_spec.spd_index);
+ } else {
+ meminit_lpddr4_spd_data(mem_cfg, cnl_cfg,
+ spd->spd_spec.spd_data_ptr_info.spd_data_len,
+ spd->spd_spec.spd_data_ptr_info.spd_data_ptr);
+ }
+}
diff --git a/src/soc/intel/cannonlake/include/soc/cnl_lpddr4_init.h b/src/soc/intel/cannonlake/include/soc/cnl_lpddr4_init.h
new file mode 100644
index 0000000000..db1c3a57c9
--- /dev/null
+++ b/src/soc/intel/cannonlake/include/soc/cnl_lpddr4_init.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#ifndef _SOC_CANNONLAKE_LPDDR4_INIT_H_
+#define _SOC_CANNONLAKE_LPDDR4_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 LPDDR4 packages, where a "package" represents a 64-bit solution.
+ */
+#define LP4_NUM_PACKAGES 2
+
+/* 64-bit Channel identification */
+enum {
+ LP4_CH0,
+ LP4_CH1,
+ LP4_NUM_CHANNELS
+};
+
+struct spd_by_pointer {
+ size_t spd_data_len;
+ uintptr_t spd_data_ptr;
+};
+
+struct spd_info {
+ bool spd_by_index;
+ union spd_data_by {
+ int spd_index;
+ struct spd_by_pointer spd_data_ptr_info;
+ } spd_spec;
+};
+
+/* Board-specific lpddr4 dq mapping information */
+struct lpddr4_cfg {
+ /*
+ * For each channel, there are 3 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, but the last 3 sets are
+ * not used in CNL, so we only define the three sets that are used
+ * and let the meminit_lpddr4() routine take care of clearing the
+ * unused fields for the caller.
+ */
+ const uint8_t dq_map[LP4_NUM_CHANNELS][3][LP4_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.
+ */
+ const uint8_t dqs_map[LP4_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.
+ */
+ const uint16_t rcomp_resistor[3];
+
+ /*
+ * Rcomp target values. These will typically be the following
+ * values for Cannon Lake : { 80, 40, 40, 40, 30 }
+ */
+ const uint16_t rcomp_targets[5];
+
+ /*
+ * Indicates whether memory is interleaved.
+ * Set to 1 for an interleaved design,
+ * set to 0 for non-interleaved design.
+ */
+ const uint8_t dq_pins_interleaved;
+
+ /* Early Command Training Enabled */
+ const uint8_t ect;
+};
+
+/*
+ * Initialize default LPDDR4 settings for CannonLake.
+ */
+void cannonlake_lpddr4_init(FSP_M_CONFIG *mem_cfg,
+ const struct lpddr4_cfg *cnl_cfg,
+ const struct spd_info *spd);
+
+#endif /* _SOC_CANNONLAKE_LPDDR4_INIT_H_ */