blob: 49f856fcf5500516b5812a1691cf17f002b46a91 [file] [log] [blame]
Angel Pons9fdd5572022-05-06 21:12:14 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
Angel Pons1c9a8d82022-05-07 00:26:10 +02003#include <arch/cpu.h>
4#include <assert.h>
5#include <cbmem.h>
6#include <cf9_reset.h>
Angel Pons9fdd5572022-05-06 21:12:14 +02007#include <console/console.h>
Angel Pons1c9a8d82022-05-07 00:26:10 +02008#include <cpu/x86/msr.h>
Angel Pons322b1c32022-05-06 22:18:21 +02009#include <delay.h>
Angel Pons1c9a8d82022-05-07 00:26:10 +020010#include <device/pci_ops.h>
11#include <mrc_cache.h>
Angel Pons567ece42022-05-06 21:56:48 +020012#include <northbridge/intel/haswell/haswell.h>
Angel Pons9fdd5572022-05-06 21:12:14 +020013#include <northbridge/intel/haswell/raminit.h>
Angel Pons322b1c32022-05-06 22:18:21 +020014#include <southbridge/intel/lynxpoint/me.h>
Angel Pons70c61852022-05-06 23:17:39 +020015#include <southbridge/intel/lynxpoint/pch.h>
Angel Pons567ece42022-05-06 21:56:48 +020016#include <types.h>
17
Angel Pons1c9a8d82022-05-07 00:26:10 +020018#include "raminit_native.h"
19
20static void wait_txt_clear(void)
21{
22 const struct cpuid_result cpuid = cpuid_ext(1, 0);
23
24 /* Check if TXT is supported */
25 if (!(cpuid.ecx & BIT(6)))
26 return;
27
28 /* Some TXT public bit */
29 if (!(read32p(0xfed30010) & 1))
30 return;
31
32 /* Wait for TXT clear */
33 do {} while (!(read8p(0xfed40000) & (1 << 7)));
34}
35
36static enum raminit_boot_mode get_boot_mode(void)
37{
38 const uint16_t pmcon_2 = pci_read_config16(PCH_LPC_DEV, GEN_PMCON_2);
39 const uint16_t bitmask = GEN_PMCON_2_DISB | GEN_PMCON_2_MEM_SR;
40 return (pmcon_2 & bitmask) == bitmask ? BOOTMODE_WARM : BOOTMODE_COLD;
41}
42
Angel Pons567ece42022-05-06 21:56:48 +020043static bool early_init_native(int s3resume)
44{
45 printk(BIOS_DEBUG, "Starting native platform initialisation\n");
46
Angel Pons322b1c32022-05-06 22:18:21 +020047 intel_early_me_init();
48 /** TODO: CPU replacement check must be skipped in warm boots and S3 resumes **/
49 const bool cpu_replaced = !s3resume && intel_early_me_cpu_replacement_check();
50
Angel Pons495091892022-05-06 23:43:46 +020051 early_pch_init_native(s3resume);
Angel Pons70c61852022-05-06 23:17:39 +020052
Angel Pons567ece42022-05-06 21:56:48 +020053 if (!CONFIG(INTEL_LYNXPOINT_LP))
54 dmi_early_init();
55
Angel Pons322b1c32022-05-06 22:18:21 +020056 return cpu_replaced;
Angel Pons567ece42022-05-06 21:56:48 +020057}
Angel Pons9fdd5572022-05-06 21:12:14 +020058
Angel Pons1c9a8d82022-05-07 00:26:10 +020059#define MRC_CACHE_VERSION 1
60
61struct mrc_data {
62 const void *buffer;
63 size_t buffer_len;
64};
65
66static void save_mrc_data(struct mrc_data *md)
67{
68 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION, md->buffer, md->buffer_len);
69}
70
71static struct mrc_data prepare_mrc_cache(void)
72{
73 struct mrc_data md = {0};
74 md.buffer = mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
75 MRC_CACHE_VERSION,
76 &md.buffer_len);
77 return md;
78}
79
80static const char *const bm_names[] = {
81 "BOOTMODE_COLD",
82 "BOOTMODE_WARM",
83 "BOOTMODE_S3",
84 "BOOTMODE_FAST",
85};
86
87static void clear_disb(void)
88{
89 pci_and_config16(PCH_LPC_DEV, GEN_PMCON_2, ~GEN_PMCON_2_DISB);
90}
91
92static void raminit_reset(void)
93{
94 clear_disb();
95 system_reset();
96}
97
98static enum raminit_boot_mode do_actual_raminit(
99 struct mrc_data *md,
100 const bool s3resume,
101 const bool cpu_replaced,
102 const enum raminit_boot_mode orig_bootmode)
103{
104 enum raminit_boot_mode bootmode = orig_bootmode;
105
106 bool save_data_valid = md->buffer && md->buffer_len == USHRT_MAX; /** TODO: sizeof() **/
107
108 if (s3resume) {
109 if (bootmode == BOOTMODE_COLD) {
110 printk(BIOS_EMERG, "Memory may not be in self-refresh for S3 resume\n");
111 printk(BIOS_EMERG, "S3 resume and cold boot are mutually exclusive\n");
112 raminit_reset();
113 }
114 /* Only a true mad hatter would replace a CPU in S3 */
115 if (cpu_replaced) {
116 printk(BIOS_EMERG, "Oh no, CPU was replaced during S3\n");
117 /*
118 * No reason to continue, memory consistency is most likely lost
119 * and ME will probably request a reset through DID response too.
120 */
121 /** TODO: Figure out why past self commented this out **/
122 //raminit_reset();
123 }
124 bootmode = BOOTMODE_S3;
125 if (!save_data_valid) {
126 printk(BIOS_EMERG, "No training data, S3 resume is impossible\n");
127 /* Failed S3 resume, reset to come up cleanly */
128 raminit_reset();
129 }
130 }
131 if (!s3resume && cpu_replaced) {
132 printk(BIOS_NOTICE, "CPU was replaced, forcing a cold boot\n");
133 /*
134 * Looks like the ME will get angry if raminit takes too long.
135 * It will report that the CPU has been replaced on next boot.
136 * Try to continue anyway. This should not happen in most cases.
137 */
138 /** TODO: Figure out why past self commented this out **/
139 //save_data_valid = false;
140 }
141 if (bootmode == BOOTMODE_COLD) {
142 /* If possible, promote to a fast boot */
143 if (save_data_valid)
144 bootmode = BOOTMODE_FAST;
145
146 clear_disb();
147 } else if (bootmode == BOOTMODE_WARM) {
148 /* If a warm reset happened before raminit is done, force a cold boot */
149 if (mchbar_read32(SSKPD) == 0 && mchbar_read32(SSKPD + 4) == 0) {
150 printk(BIOS_NOTICE, "Warm reset occurred early in cold boot\n");
151 save_data_valid = false;
152 }
153 if (!save_data_valid)
154 bootmode = BOOTMODE_COLD;
155 }
156 assert(save_data_valid != (bootmode == BOOTMODE_COLD));
157 if (save_data_valid) {
158 printk(BIOS_INFO, "Using cached memory parameters\n");
159 die("RAMINIT: Fast boot is not yet implemented\n");
160 }
161 printk(RAM_DEBUG, "Initial bootmode: %s\n", bm_names[orig_bootmode]);
162 printk(RAM_DEBUG, "Current bootmode: %s\n", bm_names[bootmode]);
163
164 /*
165 * And now, the actual memory initialization thing.
166 */
167 printk(RAM_DEBUG, "\nStarting native raminit\n");
168 raminit_main(bootmode);
169
170 return bootmode;
171}
172
Angel Pons9fdd5572022-05-06 21:12:14 +0200173void perform_raminit(const int s3resume)
174{
175 /*
176 * See, this function's name is a lie. There are more things to
177 * do that memory initialisation, but they are relatively easy.
178 */
Angel Pons567ece42022-05-06 21:56:48 +0200179 const bool cpu_replaced = early_init_native(s3resume);
180
Angel Pons1c9a8d82022-05-07 00:26:10 +0200181 wait_txt_clear();
182 wrmsr(0x2e6, (msr_t) {.lo = 0, .hi = 0});
Angel Pons9fdd5572022-05-06 21:12:14 +0200183
Angel Pons1c9a8d82022-05-07 00:26:10 +0200184 const enum raminit_boot_mode orig_bootmode = get_boot_mode();
185
186 struct mrc_data md = prepare_mrc_cache();
187
188 const enum raminit_boot_mode bootmode =
189 do_actual_raminit(&md, s3resume, cpu_replaced, orig_bootmode);
190
191 /** TODO: report_memory_config **/
192
Angel Pons322b1c32022-05-06 22:18:21 +0200193 if (intel_early_me_uma_size() > 0) {
Angel Pons1c9a8d82022-05-07 00:26:10 +0200194 /*
195 * The 'other' success value is to report loss of memory
196 * consistency to ME if warm boot was downgraded to cold.
197 */
198 uint8_t me_status;
199 if (BOOTMODE_WARM == orig_bootmode && BOOTMODE_COLD == bootmode)
200 me_status = ME_INIT_STATUS_SUCCESS_OTHER;
201 else
202 me_status = ME_INIT_STATUS_SUCCESS;
203
204 /** TODO: Remove this once raminit is implemented **/
205 me_status = ME_INIT_STATUS_ERROR;
Angel Pons322b1c32022-05-06 22:18:21 +0200206 intel_early_me_init_done(me_status);
207 }
208
209 intel_early_me_status();
210
Angel Pons1c9a8d82022-05-07 00:26:10 +0200211 const bool cbmem_was_initted = !cbmem_recovery(s3resume);
212 if (s3resume && !cbmem_was_initted) {
213 /* Failed S3 resume, reset to come up cleanly */
214 printk(BIOS_CRIT, "Failed to recover CBMEM in S3 resume.\n");
215 system_reset();
216 }
217
218 /* Save training data on non-S3 resumes */
219 if (!s3resume)
220 save_mrc_data(&md);
221
222 /** TODO: setup_sdram_meminfo **/
Angel Pons9fdd5572022-05-06 21:12:14 +0200223}