summaryrefslogtreecommitdiff
path: root/config/coreboot/default/patches/0047-haswell-NRI-Program-memory-map.patch
blob: 58a2f556cc2a1d5d66df54ae811c06b73d9dced9 (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
From 70d7333e1e0c2b0ce0f2a7e4c4c3ac5c1aca2094 Mon Sep 17 00:00:00 2001
From: Angel Pons <th3fanbus@gmail.com>
Date: Sat, 7 May 2022 21:24:50 +0200
Subject: [PATCH 47/65] haswell NRI: Program memory map

This is very similar to Sandy/Ivy Bridge, except that there's several
registers to program in GDXCBAR. One of these GDXCBAR registers has a
lock bit that must be set in order for the memory controller to allow
normal access to DRAM. And it took me four months to realize this one
bit was the only reason why native raminit did not work.

Change-Id: I3af73a018a7ba948701a542e661e7fefd57591fe
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
---
 .../intel/haswell/native_raminit/Makefile.mk  |   1 +
 .../intel/haswell/native_raminit/memory_map.c | 183 ++++++++++++++++++
 .../haswell/native_raminit/raminit_main.c     |   1 +
 .../haswell/native_raminit/raminit_native.h   |   1 +
 .../intel/haswell/registers/host_bridge.h     |   2 +
 5 files changed, 188 insertions(+)
 create mode 100644 src/northbridge/intel/haswell/native_raminit/memory_map.c

diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
index fc55277a65..37d527e972 100644
--- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
@@ -4,6 +4,7 @@ romstage-y += configure_mc.c
 romstage-y += lookup_timings.c
 romstage-y += init_mpll.c
 romstage-y += io_comp_control.c
+romstage-y += memory_map.c
 romstage-y += raminit_main.c
 romstage-y += raminit_native.c
 romstage-y += spd_bitmunching.c
diff --git a/src/northbridge/intel/haswell/native_raminit/memory_map.c b/src/northbridge/intel/haswell/native_raminit/memory_map.c
new file mode 100644
index 0000000000..e3aded2b37
--- /dev/null
+++ b/src/northbridge/intel/haswell/native_raminit/memory_map.c
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <device/pci_ops.h>
+#include <northbridge/intel/haswell/haswell.h>
+#include <southbridge/intel/lynxpoint/me.h>
+#include <types.h>
+
+#include "raminit_native.h"
+
+/* GDXCBAR */
+#define MPCOHTRK_GDXC_MOT_ADDRESS_LO		0x10
+#define MPCOHTRK_GDXC_MOT_ADDRESS_HI		0x14
+#define MPCOHTRK_GDXC_MOT_REGION		0x18
+
+#define MPCOHTRK_GDXC_OCLA_ADDRESS_LO		0x20
+#define MPCOHTRK_GDXC_OCLA_ADDRESS_HI		0x24
+#define MPCOHTRK_GDXC_OCLA_REGION		0x28
+
+/* This lock bit made me lose what little sanity I had left. - Angel Pons */
+#define MPCOHTRK_GDXC_OCLA_ADDRESS_HI_LOCK	BIT(2)
+
+static inline uint32_t gdxcbar_read32(const uintptr_t offset)
+{
+	return read32p((mchbar_read32(GDXCBAR) & ~1) + offset);
+}
+
+static inline void gdxcbar_write32(const uintptr_t offset, const uint32_t value)
+{
+	write32p((mchbar_read32(GDXCBAR) & ~1) + offset, value);
+}
+
+static inline void gdxcbar_clrsetbits32(const uintptr_t offset, uint32_t clear, uint32_t set)
+{
+	const uintptr_t address = (mchbar_read32(GDXCBAR) & ~1) + offset;
+	clrsetbits32((void *)address, clear, set);
+}
+
+#define gdxcbar_setbits32(offset, set)		gdxcbar_clrsetbits32(offset, 0, set)
+#define gdxcbar_clrbits32(offset, clear)	gdxcbar_clrsetbits32(offset, clear, 0)
+
+/* All values stored in here (except the bool) are specified in MiB */
+struct memory_map_data {
+	uint32_t dpr_size;
+	uint32_t tseg_size;
+	uint32_t gtt_size;
+	uint32_t gms_size;
+	uint32_t me_stolen_size;
+	uint32_t mmio_size;
+	uint32_t touud;
+	uint32_t remaplimit;
+	uint32_t remapbase;
+	uint32_t tom;
+	uint32_t tom_minus_me;
+	uint32_t tolud;
+	uint32_t bdsm_base;
+	uint32_t gtt_base;
+	uint32_t tseg_base;
+	bool reclaim_possible;
+};
+
+static void compute_memory_map(struct memory_map_data *map)
+{
+	map->tom_minus_me = map->tom - map->me_stolen_size;
+
+	/*
+	 * MMIO size will actually be slightly smaller than computed,
+	 * but matches what MRC does and is more MTRR-friendly given
+	 * that TSEG is treated as WB, but SMRR makes TSEG UC anyway.
+	 */
+	const uint32_t mmio_size = MIN(map->tom_minus_me, 4096) / 2;
+	map->gtt_base = ALIGN_DOWN(mmio_size, map->tseg_size);
+	map->tseg_base = map->gtt_base - map->tseg_size;
+	map->bdsm_base = map->gtt_base + map->gtt_size;
+	map->tolud = map->bdsm_base + map->gms_size;
+	map->reclaim_possible = map->tom_minus_me > map->tolud;
+
+	if (map->reclaim_possible) {
+		map->remapbase  = MAX(4096, map->tom_minus_me);
+		map->touud      = MIN(4096, map->tom_minus_me) + map->remapbase - map->tolud;
+		map->remaplimit = map->touud - 1;
+	} else {
+		map->remapbase  = 0;
+		map->remaplimit = 0;
+		map->touud = map->tom_minus_me;
+	}
+}
+
+static void display_memory_map(const struct memory_map_data *map)
+{
+	if (!CONFIG(DEBUG_RAM_SETUP))
+		return;
+
+	printk(BIOS_DEBUG, "============ MEMORY MAP ============\n");
+	printk(BIOS_DEBUG, "\n");
+	printk(BIOS_DEBUG, "dpr_size       = %u MiB\n", map->dpr_size);
+	printk(BIOS_DEBUG, "tseg_size      = %u MiB\n", map->tseg_size);
+	printk(BIOS_DEBUG, "gtt_size       = %u MiB\n", map->gtt_size);
+	printk(BIOS_DEBUG, "gms_size       = %u MiB\n", map->gms_size);
+	printk(BIOS_DEBUG, "me_stolen_size = %u MiB\n", map->me_stolen_size);
+	printk(BIOS_DEBUG, "\n");
+	printk(BIOS_DEBUG, "touud          = %u MiB\n", map->touud);
+	printk(BIOS_DEBUG, "remaplimit     = %u MiB\n", map->remaplimit);
+	printk(BIOS_DEBUG, "remapbase      = %u MiB\n", map->remapbase);
+	printk(BIOS_DEBUG, "tom            = %u MiB\n", map->tom);
+	printk(BIOS_DEBUG, "tom_minus_me   = %u MiB\n", map->tom_minus_me);
+	printk(BIOS_DEBUG, "tolud          = %u MiB\n", map->tolud);
+	printk(BIOS_DEBUG, "bdsm_base      = %u MiB\n", map->bdsm_base);
+	printk(BIOS_DEBUG, "gtt_base       = %u MiB\n", map->gtt_base);
+	printk(BIOS_DEBUG, "tseg_base      = %u MiB\n", map->tseg_base);
+	printk(BIOS_DEBUG, "\n");
+	printk(BIOS_DEBUG, "reclaim_possible = %s\n", map->reclaim_possible ? "Yes" : "No");
+}
+
+static void map_write_reg64(const uint16_t reg, const uint64_t size)
+{
+	const uint64_t value = size << 20;
+	pci_write_config32(HOST_BRIDGE, reg + 4, value >> 32);
+	pci_write_config32(HOST_BRIDGE, reg + 0, value >>  0);
+}
+
+static void map_write_reg32(const uint16_t reg, const uint32_t size)
+{
+	const uint32_t value = size << 20;
+	pci_write_config32(HOST_BRIDGE, reg, value);
+}
+
+static void program_memory_map(const struct memory_map_data *map)
+{
+	map_write_reg64(TOUUD, map->touud);
+	map_write_reg64(TOM,   map->tom);
+	if (map->reclaim_possible) {
+		map_write_reg64(REMAPBASE,  map->remapbase);
+		map_write_reg64(REMAPLIMIT, map->remaplimit);
+	}
+	if (map->me_stolen_size) {
+		map_write_reg64(MESEG_LIMIT, 0x80000 - map->me_stolen_size);
+		map_write_reg64(MESEG_BASE, map->tom_minus_me);
+		pci_or_config32(HOST_BRIDGE, MESEG_LIMIT, ME_STLEN_EN);
+	}
+	map_write_reg32(TOLUD, map->tolud);
+	map_write_reg32(BDSM,  map->bdsm_base);
+	map_write_reg32(BGSM,  map->gtt_base);
+	map_write_reg32(TSEG,  map->tseg_base);
+
+	const uint32_t dpr_reg = map->tseg_base << 20 | map->dpr_size << 4;
+	pci_write_config32(HOST_BRIDGE, DPR, dpr_reg);
+
+	const uint16_t gfx_stolen_size = GGC_IGD_MEM_IN_32MB_UNITS(map->gms_size / 32);
+	const uint16_t ggc = map->gtt_size << 8 | gfx_stolen_size;
+	pci_write_config16(HOST_BRIDGE, GGC, ggc);
+
+	/** TODO: Do not hardcode these? GDXC has weird alignment requirements, though. **/
+	gdxcbar_write32(MPCOHTRK_GDXC_MOT_ADDRESS_LO, 0);
+	gdxcbar_write32(MPCOHTRK_GDXC_MOT_ADDRESS_HI, 0);
+	gdxcbar_write32(MPCOHTRK_GDXC_MOT_REGION, 0);
+
+	gdxcbar_write32(MPCOHTRK_GDXC_OCLA_ADDRESS_LO, 0);
+	gdxcbar_write32(MPCOHTRK_GDXC_OCLA_ADDRESS_HI, 0);
+	gdxcbar_write32(MPCOHTRK_GDXC_OCLA_REGION, 0);
+
+	gdxcbar_setbits32(MPCOHTRK_GDXC_OCLA_ADDRESS_HI, MPCOHTRK_GDXC_OCLA_ADDRESS_HI_LOCK);
+}
+
+enum raminit_status configure_memory_map(struct sysinfo *ctrl)
+{
+	struct memory_map_data memory_map = {
+		.tom            = ctrl->channel_size_mb[0] + ctrl->channel_size_mb[1],
+		.dpr_size       = CONFIG_INTEL_TXT_DPR_SIZE,
+		.tseg_size      = CONFIG_SMM_TSEG_SIZE >> 20,
+		.me_stolen_size = intel_early_me_uma_size(),
+	};
+	/** FIXME: MRC hardcodes iGPU parameters, but we should not **/
+	const bool igpu_on = pci_read_config32(HOST_BRIDGE, DEVEN) & DEVEN_D2EN;
+	if (CONFIG(ONBOARD_VGA_IS_PRIMARY) || igpu_on) {
+		memory_map.gtt_size = 2;
+		memory_map.gms_size = 64;
+		pci_or_config32(HOST_BRIDGE, DEVEN, DEVEN_D2EN);
+	}
+	compute_memory_map(&memory_map);
+	display_memory_map(&memory_map);
+	program_memory_map(&memory_map);
+	return 0;
+}
diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
index fcc981ad04..559dfc3a4e 100644
--- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
@@ -23,6 +23,7 @@ static const struct task_entry cold_boot[] = {
 	{ initialise_mpll,                                        true, "INITMPLL",   },
 	{ convert_timings,                                        true, "CONVTIM",    },
 	{ configure_mc,                                           true, "CONFMC",     },
+	{ configure_memory_map,                                   true, "MEMMAP",     },
 };
 
 /* Return a generic stepping value to make stepping checks simpler */
diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
index 5915a2bab0..8f937c4ccd 100644
--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
@@ -203,6 +203,7 @@ enum raminit_status collect_spd_info(struct sysinfo *ctrl);
 enum raminit_status initialise_mpll(struct sysinfo *ctrl);
 enum raminit_status convert_timings(struct sysinfo *ctrl);
 enum raminit_status configure_mc(struct sysinfo *ctrl);
+enum raminit_status configure_memory_map(struct sysinfo *ctrl);
 
 void configure_timings(struct sysinfo *ctrl);
 void configure_refresh(struct sysinfo *ctrl);
diff --git a/src/northbridge/intel/haswell/registers/host_bridge.h b/src/northbridge/intel/haswell/registers/host_bridge.h
index 1ee0ab2890..0228cf6bb9 100644
--- a/src/northbridge/intel/haswell/registers/host_bridge.h
+++ b/src/northbridge/intel/haswell/registers/host_bridge.h
@@ -34,6 +34,8 @@
 
 #define MESEG_BASE	0x70	/* Management Engine Base */
 #define MESEG_LIMIT	0x78	/* Management Engine Limit */
+#define  MELCK		(1 << 10)	/* ME Range Lock */
+#define  ME_STLEN_EN	(1 << 11)	/* ME Stolen Memory Enable */
 
 #define PAM0		0x80
 #define PAM1		0x81
-- 
2.39.5