273 lines
7.8 KiB
Diff
273 lines
7.8 KiB
Diff
|
From c24b26594bfab47a8709ed7fb5cb77307fb73a53 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/20] 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 b4e8c7de5a..5242b16f28 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 */
|
||
|
@@ -514,6 +534,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
|
||
|
|