summaryrefslogtreecommitdiff
path: root/config/coreboot/haswell/patches/0022-haswell-NRI-Add-function-to-change-margins.patch
diff options
context:
space:
mode:
Diffstat (limited to 'config/coreboot/haswell/patches/0022-haswell-NRI-Add-function-to-change-margins.patch')
-rw-r--r--config/coreboot/haswell/patches/0022-haswell-NRI-Add-function-to-change-margins.patch272
1 files changed, 272 insertions, 0 deletions
diff --git a/config/coreboot/haswell/patches/0022-haswell-NRI-Add-function-to-change-margins.patch b/config/coreboot/haswell/patches/0022-haswell-NRI-Add-function-to-change-margins.patch
new file mode 100644
index 00000000..2e6de17c
--- /dev/null
+++ b/config/coreboot/haswell/patches/0022-haswell-NRI-Add-function-to-change-margins.patch
@@ -0,0 +1,272 @@
+From 8c3874195c0fc1af9d0b84611496689da1c19d8c Mon Sep 17 00:00:00 2001
+From: Angel Pons <th3fanbus@gmail.com>
+Date: Sun, 8 May 2022 11:58:59 +0200
+Subject: [PATCH 22/26] 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 12da59580f..4ba9cfa5c6 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/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 a36ebfacd1..500fc28909 100644
+--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
++++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
+@@ -35,6 +35,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
+@@ -45,6 +57,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 */
+@@ -516,6 +536,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
+