summaryrefslogtreecommitdiff
path: root/config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2024-08-10 14:43:19 +0100
committerLeah Rowe <leah@libreboot.org>2024-08-10 14:48:01 +0100
commit877f5d6aeb6a1a62f09c95cc214c874d057310d6 (patch)
tree4a40b0d1a0ec5edb5f501087e5ed881262b896b1 /config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch
parenta15347ef1e677ca711ce706877db2416ddfd451a (diff)
coreboot/default: merge coreboot/haswell
Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch')
-rw-r--r--config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch272
1 files changed, 272 insertions, 0 deletions
diff --git a/config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch b/config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch
new file mode 100644
index 00000000..881b81d6
--- /dev/null
+++ b/config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch
@@ -0,0 +1,272 @@
+From 36ec2cfa730ba720ef7ded21cc3e84c47f4e2623 Mon Sep 17 00:00:00 2001
+From: Angel Pons <th3fanbus@gmail.com>
+Date: Sun, 8 May 2022 11:58:59 +0200
+Subject: [PATCH 12/17] haswell NRI: Add function to change margins
+
+Implement a function to change margin parameters. Haswell provides a
+register to apply an offset to margin parameters during training, so
+make use of it. There are other margin parameters that have not been
+implemented yet, as they are not needed for now and special handling
+is needed to provide offset training functionality.
+
+Change-Id: I5392380e13de3c44e77b7bc9f3b819e2661d1e2d
+Signed-off-by: Angel Pons <th3fanbus@gmail.com>
+---
+ .../haswell/native_raminit/change_margin.c | 136 ++++++++++++++++++
+ .../haswell/native_raminit/raminit_native.h | 39 +++++
+ .../haswell/native_raminit/reg_structs.h | 12 ++
+ .../intel/haswell/registers/mchbar.h | 1 +
+ 4 files changed, 188 insertions(+)
+
+diff --git a/src/northbridge/intel/haswell/native_raminit/change_margin.c b/src/northbridge/intel/haswell/native_raminit/change_margin.c
+index 055c666eee..299c44a6b0 100644
+--- a/src/northbridge/intel/haswell/native_raminit/change_margin.c
++++ b/src/northbridge/intel/haswell/native_raminit/change_margin.c
+@@ -1,5 +1,6 @@
+ /* SPDX-License-Identifier: GPL-2.0-or-later */
+
++#include <assert.h>
+ #include <commonlib/bsd/clamp.h>
+ #include <console/console.h>
+ #include <delay.h>
+@@ -152,3 +153,138 @@ void download_regfile(
+ ddr_data_control_0.read_rf_rank = phys_rank;
+ mchbar_write32(reg, ddr_data_control_0.raw);
+ }
++
++static void update_data_offset_train(
++ struct sysinfo *ctrl,
++ const uint8_t param,
++ const uint8_t en_multicast,
++ const uint8_t channel_in,
++ const uint8_t rank,
++ const uint8_t byte_in,
++ const bool update_ctrl,
++ const enum regfile_mode regfile,
++ const uint32_t value)
++{
++ bool is_rd = false;
++ bool is_wr = false;
++ switch (param) {
++ case RdT:
++ case RdV:
++ case RcvEna:
++ is_rd = true;
++ break;
++ case WrT:
++ case WrDqsT:
++ is_wr = true;
++ break;
++ default:
++ die("%s: Invalid margin parameter %u\n", __func__, param);
++ }
++ if (en_multicast) {
++ mchbar_write32(DDR_DATA_OFFSET_TRAIN, value);
++ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
++ if (!does_ch_exist(ctrl, channel))
++ continue;
++
++ download_regfile(ctrl, channel, true, rank, regfile, 0, is_rd, is_wr);
++ if (update_ctrl) {
++ for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
++ ctrl->data_offset_train[channel][byte] = value;
++ }
++ }
++ } else {
++ mchbar_write32(DDR_DATA_OFFSET_TRAIN_ch_b(channel_in, byte_in), value);
++ download_regfile(ctrl, channel_in, false, rank, regfile, byte_in, is_rd, is_wr);
++ if (update_ctrl)
++ ctrl->data_offset_train[channel_in][byte_in] = value;
++ }
++}
++
++static uint32_t get_max_margin(const enum margin_parameter param)
++{
++ switch (param) {
++ case RcvEna:
++ case RdT:
++ case WrT:
++ case WrDqsT:
++ return MAX_POSSIBLE_TIME;
++ case RdV:
++ return MAX_POSSIBLE_VREF;
++ default:
++ die("%s: Invalid margin parameter %u\n", __func__, param);
++ }
++}
++
++void change_margin(
++ struct sysinfo *ctrl,
++ const enum margin_parameter param,
++ const int32_t value0,
++ const bool en_multicast,
++ const uint8_t channel,
++ const uint8_t rank,
++ const uint8_t byte,
++ const bool update_ctrl,
++ const enum regfile_mode regfile)
++{
++ /** FIXME: Remove this **/
++ if (rank == 0xff)
++ die("%s: rank is 0xff\n", __func__);
++
++ if (!en_multicast && !does_ch_exist(ctrl, channel))
++ die("%s: Tried to change margin of empty channel %u\n", __func__, channel);
++
++ const uint32_t max_value = get_max_margin(param);
++ const int32_t v0 = clamp_s32(-max_value, value0, max_value);
++
++ union ddr_data_offset_train_reg ddr_data_offset_train = {
++ .raw = en_multicast ? 0 : ctrl->data_offset_train[channel][byte],
++ };
++ bool update_offset_train = false;
++ switch (param) {
++ case RcvEna:
++ ddr_data_offset_train.rcven = v0;
++ update_offset_train = true;
++ break;
++ case RdT:
++ ddr_data_offset_train.rx_dqs = v0;
++ update_offset_train = true;
++ break;
++ case WrT:
++ ddr_data_offset_train.tx_dq = v0;
++ update_offset_train = true;
++ break;
++ case WrDqsT:
++ ddr_data_offset_train.tx_dqs = v0;
++ update_offset_train = true;
++ break;
++ case RdV:
++ ddr_data_offset_train.vref = v0;
++ update_offset_train = true;
++ break;
++ default:
++ die("%s: Invalid margin parameter %u\n", __func__, param);
++ }
++ if (update_offset_train) {
++ update_data_offset_train(
++ ctrl,
++ param,
++ en_multicast,
++ channel,
++ rank,
++ byte,
++ update_ctrl,
++ regfile,
++ ddr_data_offset_train.raw);
++ }
++}
++
++void change_1d_margin_multicast(
++ struct sysinfo *ctrl,
++ const enum margin_parameter param,
++ const int32_t value0,
++ const uint8_t rank,
++ const bool update_ctrl,
++ const enum regfile_mode regfile)
++{
++ change_margin(ctrl, param, value0, true, 0, rank, 0, update_ctrl, regfile);
++}
+diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
+index eaaaedad1e..1c8473056b 100644
+--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
++++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
+@@ -36,6 +36,18 @@
+
+ #define RTTNOM_MASK (BIT(9) | BIT(6) | BIT(2))
+
++/* Margin parameter limits */
++#define MAX_POSSIBLE_TIME 31
++#define MAX_POSSIBLE_VREF 54
++
++#define MAX_POSSIBLE_BOTH MAX_POSSIBLE_VREF
++
++#define MIN_TIME (-MAX_POSSIBLE_TIME)
++#define MAX_TIME (MAX_POSSIBLE_TIME)
++
++#define MIN_VREF (-MAX_POSSIBLE_VREF)
++#define MAX_VREF (MAX_POSSIBLE_VREF)
++
+ #define BASIC_VA_PAT_SPREAD_8 0x01010101
+
+ #define WDB_CACHE_LINE_SIZE 8
+@@ -46,6 +58,14 @@
+ /* Specified in PI ticks. 64 PI ticks == 1 qclk */
+ #define tDQSCK_DRIFT 64
+
++enum margin_parameter {
++ RcvEna,
++ RdT,
++ WrT,
++ WrDqsT,
++ RdV,
++};
++
+ /* ZQ calibration types */
+ enum {
+ ZQ_INIT, /* DDR3: ZQCL with tZQinit, LPDDR3: ZQ Init with tZQinit */
+@@ -515,6 +535,25 @@ void download_regfile(
+ bool read_rf_rd,
+ bool read_rf_wr);
+
++void change_margin(
++ struct sysinfo *ctrl,
++ const enum margin_parameter param,
++ const int32_t value0,
++ const bool en_multicast,
++ const uint8_t channel,
++ const uint8_t rank,
++ const uint8_t byte,
++ const bool update_ctrl,
++ const enum regfile_mode regfile);
++
++void change_1d_margin_multicast(
++ struct sysinfo *ctrl,
++ const enum margin_parameter param,
++ const int32_t value0,
++ const uint8_t rank,
++ const bool update_ctrl,
++ const enum regfile_mode regfile);
++
+ uint8_t get_rx_bias(const struct sysinfo *ctrl);
+
+ uint8_t get_tCWL(uint32_t mem_clock_mhz);
+diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
+index b099f4bb82..a0e36ed082 100644
+--- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
++++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
+@@ -25,6 +25,18 @@ union ddr_data_tx_train_rank_reg {
+ uint32_t raw;
+ };
+
++union ddr_data_offset_train_reg {
++ struct __packed {
++ int32_t rcven : 6; // Bits 5:0
++ int32_t rx_dqs : 6; // Bits 11:6
++ int32_t tx_dq : 6; // Bits 17:12
++ int32_t tx_dqs : 6; // Bits 23:18
++ int32_t vref : 7; // Bits 30:24
++ int32_t : 1; // Bits 31:31
++ };
++ uint32_t raw;
++};
++
+ union ddr_data_control_0_reg {
+ struct __packed {
+ uint32_t rx_training_mode : 1; // Bits 0:0
+diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
+index 9172d4f2b0..0acafbc826 100644
+--- a/src/northbridge/intel/haswell/registers/mchbar.h
++++ b/src/northbridge/intel/haswell/registers/mchbar.h
+@@ -21,6 +21,7 @@
+ #define DDR_DATA_TRAIN_FEEDBACK(ch, byte) _DDRIO_C_R_B(0x0054, ch, 0, byte)
+
+ #define DQ_CONTROL_2(ch, byte) _DDRIO_C_R_B(0x0064, ch, 0, byte)
++#define DDR_DATA_OFFSET_TRAIN_ch_b(ch, byte) _DDRIO_C_R_B(0x0070, ch, 0, byte)
+ #define DQ_CONTROL_0(ch, byte) _DDRIO_C_R_B(0x0074, ch, 0, byte)
+
+ /* DDR CKE per-channel */
+--
+2.39.2
+