summaryrefslogtreecommitdiff
path: root/config/coreboot/haswell/patches/0020-haswell-NRI-Add-library-to-change-margins.patch
blob: 30926494891871f2aecce9274c3607c66563242b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
From 54cfbe4cf53d16f747bfcfadd20445a0f5f1e5db Mon Sep 17 00:00:00 2001
From: Angel Pons <th3fanbus@gmail.com>
Date: Sun, 8 May 2022 01:11:03 +0200
Subject: [PATCH 20/26] haswell NRI: Add library to change margins

Implement a library to change Rx/Tx margins. It will be expanded later.

Change-Id: I0b55aba428d8b4d4e16d2fbdec57235ce3ce8adf
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
---
 .../intel/haswell/native_raminit/Makefile.inc |   1 +
 .../haswell/native_raminit/change_margin.c    | 154 ++++++++++++++++++
 .../haswell/native_raminit/raminit_native.h   |  50 ++++++
 .../intel/haswell/registers/mchbar.h          |   9 +
 4 files changed, 214 insertions(+)
 create mode 100644 src/northbridge/intel/haswell/native_raminit/change_margin.c

diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
index 2da950771d..ebe9e9b762 100644
--- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc
+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
@@ -1,5 +1,6 @@
 ## SPDX-License-Identifier: GPL-2.0-or-later
 
+romstage-y += change_margin.c
 romstage-y += configure_mc.c
 romstage-y += ddr3.c
 romstage-y += jedec_reset.c
diff --git a/src/northbridge/intel/haswell/native_raminit/change_margin.c b/src/northbridge/intel/haswell/native_raminit/change_margin.c
new file mode 100644
index 0000000000..12da59580f
--- /dev/null
+++ b/src/northbridge/intel/haswell/native_raminit/change_margin.c
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <commonlib/clamp.h>
+#include <console/console.h>
+#include <delay.h>
+#include <northbridge/intel/haswell/haswell.h>
+#include <timer.h>
+
+#include "raminit_native.h"
+
+void update_rxt(
+	struct sysinfo *ctrl,
+	const uint8_t channel,
+	const uint8_t rank,
+	const uint8_t byte,
+	const enum rxt_subfield subfield,
+	const int32_t value)
+{
+	union ddr_data_rx_train_rank_reg rxt = {
+		.rcven =  ctrl->rcven[channel][rank][byte],
+		.dqs_p = ctrl->rxdqsp[channel][rank][byte],
+		.rx_eq =  ctrl->rx_eq[channel][rank][byte],
+		.dqs_n = ctrl->rxdqsn[channel][rank][byte],
+		.vref  = ctrl->rxvref[channel][rank][byte],
+	};
+	int32_t new_value;
+	switch (subfield) {
+	case RXT_RCVEN:
+		new_value = clamp_s32(0, value, 511);
+		rxt.rcven = new_value;
+		break;
+	case RXT_RXDQS_P:
+		new_value = clamp_s32(0, value, 63);
+		rxt.dqs_p = new_value;
+		break;
+	case RXT_RX_EQ:
+		new_value = clamp_s32(0, value, 31);
+		rxt.rx_eq = new_value;
+		break;
+	case RXT_RXDQS_N:
+		new_value = clamp_s32(0, value, 63);
+		rxt.dqs_n = new_value;
+		break;
+	case RXT_RX_VREF:
+		new_value = clamp_s32(-32, value, 31);
+		rxt.vref = new_value;
+		break;
+	case RXT_RXDQS_BOTH:
+		new_value = clamp_s32(0, value, 63);
+		rxt.dqs_p = new_value;
+		rxt.dqs_n = new_value;
+		break;
+	case RXT_RESTORE:
+		new_value = value;
+		break;
+	default:
+		die("%s: Unhandled subfield index %u\n", __func__, subfield);
+	}
+
+	if (new_value != value) {
+		printk(BIOS_ERR, "%s: Overflow for subfield %u: %d ---> %d\n",
+			__func__, subfield, value, new_value);
+	}
+	mchbar_write32(RX_TRAIN_ch_r_b(channel, rank, byte), rxt.raw);
+	download_regfile(ctrl, channel, false, rank, REG_FILE_USE_RANK, byte, true, false);
+}
+
+void update_txt(
+	struct sysinfo *ctrl,
+	const uint8_t channel,
+	const uint8_t rank,
+	const uint8_t byte,
+	const enum txt_subfield subfield,
+	const int32_t value)
+{
+	union ddr_data_tx_train_rank_reg txt = {
+		.dq_delay  = ctrl->tx_dq[channel][rank][byte],
+		.dqs_delay = ctrl->txdqs[channel][rank][byte],
+		.tx_eq     = ctrl->tx_eq[channel][rank][byte],
+	};
+	int32_t new_value;
+	switch (subfield) {
+	case TXT_TX_DQ:
+		new_value = clamp_s32(0, value, 511);
+		txt.dq_delay = new_value;
+		break;
+	case TXT_TXDQS:
+		new_value = clamp_s32(0, value, 511);
+		txt.dqs_delay = new_value;
+		break;
+	case TXT_TX_EQ:
+		new_value = clamp_s32(0, value, 63);
+		txt.tx_eq = new_value;
+		break;
+	case TXT_DQDQS_OFF:
+		new_value = value;
+		txt.dqs_delay += new_value;
+		txt.dq_delay  += new_value;
+		break;
+	case TXT_RESTORE:
+		new_value = value;
+		break;
+	default:
+		die("%s: Unhandled subfield index %u\n", __func__, subfield);
+	}
+	if (new_value != value) {
+		printk(BIOS_ERR, "%s: Overflow for subfield %u: %d ---> %d\n",
+			__func__, subfield, value, new_value);
+	}
+	mchbar_write32(TX_TRAIN_ch_r_b(channel, rank, byte), txt.raw);
+	download_regfile(ctrl, channel, false, rank, REG_FILE_USE_RANK, byte, false, true);
+}
+
+void download_regfile(
+	struct sysinfo *ctrl,
+	const uint8_t channel,
+	const bool multicast,
+	const uint8_t rank,
+	const enum regfile_mode regfile,
+	const uint8_t byte,
+	const bool read_rf_rd,
+	const bool read_rf_wr)
+{
+	union reut_seq_base_addr_reg reut_seq_base_addr;
+	switch (regfile) {
+	case REG_FILE_USE_START:
+		reut_seq_base_addr.raw = mchbar_read64(REUT_ch_SEQ_ADDR_START(channel));
+		break;
+	case REG_FILE_USE_CURRENT:
+		reut_seq_base_addr.raw = mchbar_read64(REUT_ch_SEQ_ADDR_CURRENT(channel));
+		break;
+	case REG_FILE_USE_RANK:
+		reut_seq_base_addr.raw = 0;
+		if (rank >= NUM_SLOTRANKS)
+			die("%s: bad rank %u\n", __func__, rank);
+		break;
+	default:
+		die("%s: Invalid regfile param %u\n", __func__, regfile);
+	}
+	uint8_t phys_rank = rank;
+	if (reut_seq_base_addr.raw != 0) {
+		/* Map REUT logical rank to physical rank */
+		const uint32_t log_to_phys = mchbar_read32(REUT_ch_RANK_LOG_TO_PHYS(channel));
+		phys_rank = log_to_phys >> (reut_seq_base_addr.rank_addr * 4) & 0x3;
+	}
+	uint32_t reg = multicast ? DDR_DATA_ch_CONTROL_0(channel) : DQ_CONTROL_0(channel, byte);
+	union ddr_data_control_0_reg ddr_data_control_0 = {
+		.raw = mchbar_read32(reg),
+	};
+	ddr_data_control_0.read_rf_rd   = read_rf_rd;
+	ddr_data_control_0.read_rf_wr   = read_rf_wr;
+	ddr_data_control_0.read_rf_rank = phys_rank;
+	mchbar_write32(reg, ddr_data_control_0.raw);
+}
diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
index 56df36ca8d..7c1a786780 100644
--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
@@ -117,6 +117,30 @@ enum test_stop {
 	ALSOE  = 3,	/* Stop on all lanes error */
 };
 
+enum rxt_subfield {
+	RXT_RCVEN	= 0,
+	RXT_RXDQS_P	= 1,
+	RXT_RX_EQ	= 2,
+	RXT_RXDQS_N	= 3,
+	RXT_RX_VREF	= 4,
+	RXT_RXDQS_BOTH	= 5,
+	RXT_RESTORE	= 255,
+};
+
+enum txt_subfield {
+	TXT_TX_DQ	= 0,
+	TXT_TXDQS	= 1,
+	TXT_TX_EQ	= 2,
+	TXT_DQDQS_OFF	= 3,
+	TXT_RESTORE	= 255,
+};
+
+enum regfile_mode {
+	REG_FILE_USE_RANK,	/* Used when changing parameters for each rank */
+	REG_FILE_USE_START,	/* Used when changing parameters before the test */
+	REG_FILE_USE_CURRENT,	/* Used when changing parameters after the test */
+};
+
 struct wdb_pat {
 	uint32_t start_ptr;	/* Starting pointer in WDB */
 	uint32_t stop_ptr;	/* Stopping pointer in WDB */
@@ -452,6 +476,32 @@ uint8_t select_reut_ranks(struct sysinfo *ctrl, uint8_t channel, uint8_t rankmas
 void run_mpr_io_test(bool clear_errors);
 uint8_t run_io_test(struct sysinfo *ctrl, uint8_t chanmask, uint8_t dq_pat, bool clear_errors);
 
+void update_rxt(
+	struct sysinfo *ctrl,
+	uint8_t channel,
+	uint8_t rank,
+	uint8_t byte,
+	enum rxt_subfield subfield,
+	int32_t value);
+
+void update_txt(
+	struct sysinfo *ctrl,
+	uint8_t channel,
+	uint8_t rank,
+	uint8_t byte,
+	enum txt_subfield subfield,
+	int32_t value);
+
+void download_regfile(
+	struct sysinfo *ctrl,
+	uint8_t channel,
+	bool multicast,
+	uint8_t rank,
+	enum regfile_mode regfile,
+	uint8_t byte,
+	bool read_rf_rd,
+	bool read_rf_wr);
+
 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/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
index 817a9f8bf8..a81559bb1e 100644
--- a/src/northbridge/intel/haswell/registers/mchbar.h
+++ b/src/northbridge/intel/haswell/registers/mchbar.h
@@ -15,7 +15,11 @@
 /* Register definitions */
 
 /* DDR DATA per-channel per-bytelane */
+#define RX_TRAIN_ch_r_b(ch, rank, byte)		_DDRIO_C_R_B(0x0000, ch, rank, byte)
+#define TX_TRAIN_ch_r_b(ch, rank, byte)		_DDRIO_C_R_B(0x0020, ch, rank, byte)
+
 #define DQ_CONTROL_2(ch, byte)			_DDRIO_C_R_B(0x0064, ch, 0, byte)
+#define DQ_CONTROL_0(ch, byte)			_DDRIO_C_R_B(0x0074, ch, 0, byte)
 
 /* DDR CKE per-channel */
 #define DDR_CKE_ch_CMD_COMP_OFFSET(ch)		_DDRIO_C_R_B(0x1204, ch, 0, 0)
@@ -38,6 +42,9 @@
 #define DDR_SCRAMBLE_ch(ch)			(0x2000 + 4 * (ch))
 #define DDR_SCRAM_MISC_CONTROL			0x2008
 
+/* DDR DATA per-channel multicast */
+#define DDR_DATA_ch_CONTROL_0(ch)		_DDRIO_C_R_B(0x3074, ch, 0, 0)
+
 /* DDR CMDN/CMDS per-channel (writes go to both CMDN and CMDS fubs) */
 #define DDR_CMD_ch_COMP_OFFSET(ch)		_DDRIO_C_R_B(0x3204, ch, 0, 0)
 #define DDR_CMD_ch_PI_CODING(ch)		_DDRIO_C_R_B(0x3208, ch, 0, 0)
@@ -147,6 +154,8 @@
 
 #define REUT_ch_SEQ_ADDR_WRAP(ch)		(0x48e8 + 8 * (ch))
 
+#define REUT_ch_SEQ_ADDR_CURRENT(ch)		(0x48f8 + 8 * (ch))
+
 #define REUT_ch_SEQ_MISC_CTL(ch)		(0x4908 + 4 * (ch))
 
 #define REUT_ch_SEQ_ADDR_INC_CTL(ch)		(0x4910 + 8 * (ch))
-- 
2.39.2