123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- 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
|