diff options
| author | Leah Rowe <leah@libreboot.org> | 2024-08-10 14:43:19 +0100 | 
|---|---|---|
| committer | Leah Rowe <leah@libreboot.org> | 2024-08-10 14:48:01 +0100 | 
| commit | 877f5d6aeb6a1a62f09c95cc214c874d057310d6 (patch) | |
| tree | 4a40b0d1a0ec5edb5f501087e5ed881262b896b1 /config/coreboot/default/patches/0054-haswell-NRI-Add-function-to-change-margins.patch | |
| parent | a15347ef1e677ca711ce706877db2416ddfd451a (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.patch | 272 | 
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 + | 
