blob: 07013c55397902dee158db545791011898b8d0a2 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin76c37002012-10-30 09:03:43 -05002
Aaron Durbin76c37002012-10-30 09:03:43 -05003#include <arch/io.h>
Angel Pons322b1c32022-05-06 22:18:21 +02004#include <cf9_reset.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02005#include <device/pci_ops.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05006#include <console/console.h>
7#include <delay.h>
Patrick Georgibd79c5e2014-11-28 22:35:36 +01008#include <halt.h>
Angel Pons322b1c32022-05-06 22:18:21 +02009#include <timer.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050010#include "me.h"
11#include "pch.h"
12
13static const char *me_ack_values[] = {
14 [ME_HFS_ACK_NO_DID] = "No DID Ack received",
15 [ME_HFS_ACK_RESET] = "Non-power cycle reset",
16 [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset",
17 [ME_HFS_ACK_S3] = "Go to S3",
18 [ME_HFS_ACK_S4] = "Go to S4",
19 [ME_HFS_ACK_S5] = "Go to S5",
20 [ME_HFS_ACK_GBL_RESET] = "Global Reset",
21 [ME_HFS_ACK_CONTINUE] = "Continue to boot"
22};
23
Aaron Durbin76c37002012-10-30 09:03:43 -050024void intel_early_me_status(void)
25{
Angel Pons032255c2021-11-24 14:12:38 +010026 union me_hfs hfs = { .raw = pci_read_config32(PCH_ME_DEV, PCI_ME_HFS) };
27 union me_hfs2 hfs2 = { .raw = pci_read_config32(PCH_ME_DEV, PCI_ME_HFS2) };
Aaron Durbin76c37002012-10-30 09:03:43 -050028
Angel Pons55405a32021-11-24 15:04:05 +010029 intel_me_status(hfs, hfs2);
Aaron Durbin76c37002012-10-30 09:03:43 -050030}
31
32int intel_early_me_init(void)
33{
34 int count;
Angel Pons032255c2021-11-24 14:12:38 +010035 union me_uma uma;
36 union me_hfs hfs;
Aaron Durbin76c37002012-10-30 09:03:43 -050037
38 printk(BIOS_INFO, "Intel ME early init\n");
39
40 /* Wait for ME UMA SIZE VALID bit to be set */
Aaron Durbin9aa031e2012-11-02 09:16:46 -050041 /* FIXME: ME9 BGW indicates a 5 sec poll timeout. */
Aaron Durbin76c37002012-10-30 09:03:43 -050042 for (count = ME_RETRY; count > 0; --count) {
Angel Pons032255c2021-11-24 14:12:38 +010043 uma.raw = pci_read_config32(PCH_ME_DEV, PCI_ME_UMA);
Aaron Durbin76c37002012-10-30 09:03:43 -050044 if (uma.valid)
45 break;
46 udelay(ME_DELAY);
47 }
48 if (!count) {
Julius Wernere9665952022-01-21 17:06:20 -080049 printk(BIOS_ERR, "ME is not ready!\n");
Aaron Durbin76c37002012-10-30 09:03:43 -050050 return -1;
51 }
52
53 /* Check for valid firmware */
Angel Pons032255c2021-11-24 14:12:38 +010054 hfs.raw = pci_read_config32(PCH_ME_DEV, PCI_ME_HFS);
Aaron Durbin76c37002012-10-30 09:03:43 -050055 if (hfs.fpt_bad) {
Julius Wernere9665952022-01-21 17:06:20 -080056 printk(BIOS_WARNING, "ME has bad firmware\n");
Aaron Durbin76c37002012-10-30 09:03:43 -050057 return -1;
58 }
59
60 printk(BIOS_INFO, "Intel ME firmware is ready\n");
61 return 0;
62}
63
Angel Pons322b1c32022-05-06 22:18:21 +020064bool intel_early_me_cpu_replacement_check(void)
65{
66 printk(BIOS_DEBUG, "ME: Checking whether CPU was replaced... ");
67
68 struct stopwatch timer;
69 stopwatch_init_msecs_expire(&timer, 50);
70
71 union me_hfs2 hfs2;
72 do {
73 hfs2.raw = pci_read_config32(PCH_ME_DEV, PCI_ME_HFS2);
74 if (stopwatch_expired(&timer)) {
75 /* Assume CPU was replaced just in case */
76 printk(BIOS_DEBUG, "timed out, assuming CPU was replaced\n");
77 return true;
78 }
79 udelay(ME_DELAY);
80 } while (!hfs2.cpu_replaced_valid);
81
82 if (hfs2.warm_reset_request) {
83 printk(BIOS_DEBUG, "warm reset needed for dynamic fusing\n");
84 system_reset();
85 }
86
87 printk(BIOS_DEBUG, "%sreplaced\n", hfs2.cpu_replaced_sts ? "" : "not ");
88 return hfs2.cpu_replaced_sts;
89}
90
Aaron Durbin76c37002012-10-30 09:03:43 -050091int intel_early_me_uma_size(void)
92{
Angel Pons032255c2021-11-24 14:12:38 +010093 union me_uma uma = { .raw = pci_read_config32(PCH_ME_DEV, PCI_ME_UMA) };
Aaron Durbin76c37002012-10-30 09:03:43 -050094
Aaron Durbin76c37002012-10-30 09:03:43 -050095 if (uma.valid) {
96 printk(BIOS_DEBUG, "ME: Requested %uMB UMA\n", uma.size);
97 return uma.size;
98 }
99
100 printk(BIOS_DEBUG, "ME: Invalid UMA size\n");
101 return 0;
102}
103
104static inline void set_global_reset(int enable)
105{
Aaron Durbinb9ea8b32012-11-02 09:10:30 -0500106 u32 pmir = pci_read_config32(PCH_LPC_DEV, PMIR);
Aaron Durbin76c37002012-10-30 09:03:43 -0500107
108 /* CF9GR indicates a Global Reset */
109 if (enable)
Aaron Durbinb9ea8b32012-11-02 09:10:30 -0500110 pmir |= PMIR_CF9GR;
Aaron Durbin76c37002012-10-30 09:03:43 -0500111 else
Aaron Durbinb9ea8b32012-11-02 09:10:30 -0500112 pmir &= ~PMIR_CF9GR;
Aaron Durbin76c37002012-10-30 09:03:43 -0500113
Aaron Durbinb9ea8b32012-11-02 09:10:30 -0500114 pci_write_config32(PCH_LPC_DEV, PMIR, pmir);
Aaron Durbin76c37002012-10-30 09:03:43 -0500115}
116
117int intel_early_me_init_done(u8 status)
118{
119 u8 reset;
120 int count;
121 u32 mebase_l, mebase_h;
Angel Pons032255c2021-11-24 14:12:38 +0100122 union me_hfs hfs;
123 union me_did did = {
Aaron Durbin76c37002012-10-30 09:03:43 -0500124 .init_done = ME_INIT_DONE,
125 .status = status
126 };
127
128 /* MEBASE from MESEG_BASE[35:20] */
129 mebase_l = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_L);
130 mebase_h = pci_read_config32(PCI_CPU_DEVICE, PCI_CPU_MEBASE_H) & 0xf;
131 did.uma_base = (mebase_l >> 20) | (mebase_h << 12);
132
133 /* Send message to ME */
134 printk(BIOS_DEBUG, "ME: Sending Init Done with status: %d, "
135 "UMA base: 0x%04x\n", status, did.uma_base);
136
Angel Pons032255c2021-11-24 14:12:38 +0100137 pci_write_config32(PCH_ME_DEV, PCI_ME_H_GS, did.raw);
Aaron Durbin76c37002012-10-30 09:03:43 -0500138
Aaron Durbin9aa031e2012-11-02 09:16:46 -0500139 /*
140 * The ME firmware does not respond with an ACK when NOMEM or ERROR
141 * are sent.
142 */
143 if (status == ME_INIT_STATUS_NOMEM || status == ME_INIT_STATUS_ERROR)
144 return 0;
145
Aaron Durbin76c37002012-10-30 09:03:43 -0500146 /* Must wait for ME acknowledgement */
147 for (count = ME_RETRY; count > 0; --count) {
Angel Pons032255c2021-11-24 14:12:38 +0100148 hfs.raw = pci_read_config32(PCH_ME_DEV, PCI_ME_HFS);
Aaron Durbin76c37002012-10-30 09:03:43 -0500149 if (hfs.bios_msg_ack)
150 break;
151 udelay(ME_DELAY);
152 }
153 if (!count) {
Julius Wernere9665952022-01-21 17:06:20 -0800154 printk(BIOS_ERR, "ME failed to respond\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500155 return -1;
156 }
157
158 /* Return the requested BIOS action */
159 printk(BIOS_NOTICE, "ME: Requested BIOS Action: %s\n",
160 me_ack_values[hfs.ack_data]);
161
162 /* Check status after acknowledgement */
163 intel_early_me_status();
164
165 reset = 0;
166 switch (hfs.ack_data) {
167 case ME_HFS_ACK_CONTINUE:
168 /* Continue to boot */
169 return 0;
170 case ME_HFS_ACK_RESET:
171 /* Non-power cycle reset */
172 set_global_reset(0);
173 reset = 0x06;
174 break;
175 case ME_HFS_ACK_PWR_CYCLE:
176 /* Power cycle reset */
177 set_global_reset(0);
178 reset = 0x0e;
179 break;
180 case ME_HFS_ACK_GBL_RESET:
181 /* Global reset */
182 set_global_reset(1);
183 reset = 0x0e;
184 break;
185 case ME_HFS_ACK_S3:
186 case ME_HFS_ACK_S4:
187 case ME_HFS_ACK_S5:
188 break;
189 }
190
191 /* Perform the requested reset */
192 if (reset) {
193 outb(reset, 0xcf9);
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100194 halt();
Aaron Durbin76c37002012-10-30 09:03:43 -0500195 }
196 return -1;
197}