summaryrefslogtreecommitdiffstats
path: root/resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0045-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
blob: 1437a1f12cd60677b066f63fc130b104081c71da (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
From a43c033cd8bcfd0742d1f52847c09bef8280b5f3 Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Fri, 5 Jun 2015 21:13:30 -0500
Subject: [PATCH 045/143] northbridge/amd/amdfam10: Enable CC6 DRAM save area
 setup

Change-Id: Ibeb35da3395dc77a21a2f92f0e1d0845be53d175
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/northbridge/amd/amdfam10/northbridge.c  |   70 ++++++++++++++
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |  132 +++++++++++++++++++++++++++
 2 files changed, 202 insertions(+)

diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c
index fcf85a7..e5612fa 100644
--- a/src/northbridge/amd/amdfam10/northbridge.c
+++ b/src/northbridge/amd/amdfam10/northbridge.c
@@ -706,6 +706,8 @@ struct chip_operations northbridge_amd_amdfam10_ops = {
 static void amdfam10_domain_read_resources(device_t dev)
 {
 	unsigned reg;
+	uint8_t nvram;
+	uint8_t enable_cc6;
 
 	/* Find the already assigned resource pairs */
 	get_fx_devs();
@@ -749,6 +751,74 @@ static void amdfam10_domain_read_resources(device_t dev)
 	/* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
 	ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
 #endif
+
+	if (is_fam15h()) {
+		enable_cc6 = 0;
+		if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
+			enable_cc6 = !!nvram;
+
+		if (enable_cc6) {
+			uint8_t node;
+			uint8_t interleaved;
+			int8_t range;
+			int8_t max_range;
+			uint8_t max_node;
+			uint64_t max_range_limit;
+			uint32_t dword;
+			uint32_t dword2;
+			uint64_t qword;
+			uint8_t num_nodes;
+
+			/* Find highest DRAM range (DramLimitAddr) */
+			max_node = 0;
+			max_range = -1;
+			interleaved = 0;
+			max_range_limit = 0;
+			for (range = 0; range < 8; range++) {
+				dword = f1_read_config32(0x40 + (range * 0x8));
+				if (!(dword & 0x3))
+					continue;
+
+				if ((dword >> 8) & 0x7)
+					interleaved = 1;
+
+				dword = f1_read_config32(0x44 + (range * 0x8));
+				dword2 = f1_read_config32(0x144 + (range * 0x8));
+				qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
+				qword |= (((uint64_t)dword2) & 0xff) << 40;
+
+				if (qword > max_range_limit) {
+					max_range = range;
+					max_range_limit = qword;
+					max_node = dword & 0x7;
+				}
+			}
+
+			num_nodes = 0;
+			device_t node_dev;
+			for (node = 0; node < FX_DEVS; node++) {
+				node_dev = get_node_pci(node, 0);
+				/* Test for node presence */
+				if ((node_dev) && (pci_read_config32(node_dev, PCI_VENDOR_ID) != 0xffffffff))
+					num_nodes++;
+			}
+
+			/* Calculate CC6 sotrage area size */
+			if (interleaved)
+				qword = (0x1000000 * num_nodes);
+			else
+				qword = 0x1000000;
+
+			/* Reserve the CC6 save segment */
+			reserved_ram_resource(dev, 8, max_range_limit >> 10, qword >> 10);
+
+			/* Set up the C-state base address */
+			msr_t c_state_addr_msr;
+			c_state_addr_msr = rdmsr(0xc0010073);
+			c_state_addr_msr.lo = 0xe0e0;		/* CstateAddr = 0xe0e0 */
+			wrmsr(0xc0010073, c_state_addr_msr);
+		}
+	}
 }
 
 static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index 20e66f2..2798506 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -1188,6 +1188,100 @@ static void compare_nvram_spd_hashes(struct MCTStatStruc *pMCTstat,
 }
 #endif
 
+static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstat, uint8_t num_nodes)
+{
+	uint8_t interleaved;
+	uint8_t destination_node;
+	int8_t range;
+	int8_t max_range;
+	uint8_t max_node;
+	uint64_t max_range_limit;
+	uint32_t dword;
+	uint32_t dword2;
+	uint64_t qword;
+
+	interleaved = 0;
+	if (pMCTstat->GStatus & (1 << GSB_NodeIntlv))
+		interleaved = 1;
+
+	/* Find highest DRAM range (DramLimitAddr) */
+	max_node = 0;
+	max_range = -1;
+	max_range_limit = 0;
+	for (range = 0; range < 8; range++) {
+		dword = Get_NB32(pDCTstat->dev_map, 0x40 + (range * 0x8));
+		if (!(dword & 0x3))
+			continue;
+
+		dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
+		dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
+		qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
+		qword |= (((uint64_t)dword2) & 0xff) << 40;
+
+		if (qword > max_range_limit) {
+			max_range = range;
+			max_range_limit = qword;
+			max_node = dword & 0x7;
+		}
+	}
+
+	if (pDCTstat->Node_ID == max_node) {
+		if (max_range >= 0) {
+			if (interleaved)
+				/* Move upper limit down by 16M * the number of nodes */
+				max_range_limit -= (0x1000000 * num_nodes);
+			else
+				/* Move upper limit down by 16M */
+				max_range_limit -= 0x1000000;
+
+			/* Store modified range */
+			dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
+			dword &= ~(0xffff << 16);		/* DramLimit[39:24] = max_range_limit[39:24] */
+			dword |= (max_range_limit >> 24) & 0xffff;
+			Set_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8), dword);
+
+			dword = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
+			dword &= ~(0xffff << 16);		/* DramLimit[47:40] = max_range_limit[47:40] */
+			dword |= (max_range_limit >> 40) & 0xff;
+			Set_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8), dword);
+		}
+	}
+
+	/* Determine save state destination node */
+	if (interleaved)
+		destination_node = Get_NB32(pDCTstat->dev_host, 0x60) & 0x7;
+	else
+		destination_node = max_node;
+
+	/* Set save state destination node */
+	dword = Get_NB32(pDCTstat->dev_link, 0x128);
+	dword &= ~(0x3f << 12);				/* CoreSaveStateDestNode = destination_node */
+	dword |= (destination_node & 0x3f) << 12;
+	Set_NB32(pDCTstat->dev_link, 0x128, dword);
+}
+
+static void lock_dram_config(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstat)
+{
+	uint32_t dword;
+
+	dword = Get_NB32(pDCTstat->dev_dct, 0x118);
+	dword |= 0x1 << 19;		/* LockDramCfg = 1 */
+	Set_NB32(pDCTstat->dev_dct, 0x118, dword);
+}
+
+static void set_cc6_save_enable(struct MCTStatStruc *pMCTstat,
+				struct DCTStatStruc *pDCTstat, uint8_t enable)
+{
+	uint32_t dword;
+
+	dword = Get_NB32(pDCTstat->dev_dct, 0x118);
+	dword &= ~(0x1 << 18); 		/* CC6SaveEn = enable */
+	dword |= (enable & 0x1) << 18;
+	Set_NB32(pDCTstat->dev_dct, 0x118, dword);
+}
+
 static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
 			struct DCTStatStruc *pDCTstatA)
 {
@@ -1237,6 +1331,7 @@ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
 	u8 Node, NodesWmem;
 	u32 node_sys_base;
 	uint8_t nvram;
+	uint8_t enable_cc6;
 	uint8_t allow_config_restore;
 
 	uint8_t s3resume = acpi_is_wakeup_s3();
@@ -1406,6 +1501,43 @@ restartinit:
 			mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
 		}
 
+		if (is_fam15h()) {
+			enable_cc6 = 0;
+			if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
+				enable_cc6 = !!nvram;
+
+			if (enable_cc6) {
+				uint8_t num_nodes;
+
+				num_nodes = 0;
+				for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+					struct DCTStatStruc *pDCTstat;
+					pDCTstat = pDCTstatA + Node;
+
+					if (pDCTstat->NodePresent)
+						num_nodes++;
+				}
+
+				for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+					struct DCTStatStruc *pDCTstat;
+					pDCTstat = pDCTstatA + Node;
+
+					if (pDCTstat->NodePresent)
+						set_up_cc6_storage_fam15(pMCTstat, pDCTstat, num_nodes);
+				}
+
+				for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+					struct DCTStatStruc *pDCTstat;
+					pDCTstat = pDCTstatA + Node;
+
+					if (pDCTstat->NodePresent) {
+						lock_dram_config(pMCTstat, pDCTstat);
+						set_cc6_save_enable(pMCTstat, pDCTstat, 1);
+					}
+				}
+			}
+		}
+
 		mct_FinalMCT_D(pMCTstat, pDCTstatA);
 		printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", pMCTstat->GStatus);
 	}
-- 
1.7.9.5