blob: 2db3c2d1194824093f1d8ee8e07fd7c0c293cd17 [file] [log] [blame]
Angel Pons2e29c3b2020-08-10 15:47:28 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
Angel Pons2e29c3b2020-08-10 15:47:28 +02003#include <device/mmio.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pci_ops.h>
7#include <console/console.h>
8#include <device/pci_ids.h>
Angel Pons2e29c3b2020-08-10 15:47:28 +02009#include <string.h>
10#include <delay.h>
11#include <halt.h>
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +030012#include <timer.h>
Angel Pons2e29c3b2020-08-10 15:47:28 +020013
14#include "me.h"
15#include "pch.h"
16
Kyösti Mälkki26e0f4c2020-12-19 19:10:45 +020017#include <vendorcode/google/chromeos/chromeos.h>
18
Angel Pons2e29c3b2020-08-10 15:47:28 +020019/* Path that the BIOS should take based on ME state */
Angel Pons4def30d2020-06-02 20:10:36 +020020static const char *const me_bios_path_values[] = {
Angel Pons2e29c3b2020-08-10 15:47:28 +020021 [ME_NORMAL_BIOS_PATH] = "Normal",
22 [ME_S3WAKE_BIOS_PATH] = "S3 Wake",
23 [ME_ERROR_BIOS_PATH] = "Error",
24 [ME_RECOVERY_BIOS_PATH] = "Recovery",
25 [ME_DISABLE_BIOS_PATH] = "Disable",
26 [ME_FIRMWARE_UPDATE_BIOS_PATH] = "Firmware Update",
27};
28
Angel Pons4def30d2020-06-02 20:10:36 +020029const char *const me_get_bios_path_string(int path)
Angel Pons2e29c3b2020-08-10 15:47:28 +020030{
31 return me_bios_path_values[path];
32}
33
34/* MMIO base address for MEI interface */
35static u32 *mei_base_address;
36
37static void mei_dump(void *ptr, int dword, int offset, const char *type)
38{
39 struct mei_csr *csr;
40
41 if (!CONFIG(DEBUG_INTEL_ME))
42 return;
43
44 printk(BIOS_SPEW, "%-9s[%02x] : ", type, offset);
45
46 switch (offset) {
47 case MEI_H_CSR:
48 case MEI_ME_CSR_HA:
49 csr = ptr;
50 if (!csr) {
51 printk(BIOS_SPEW, "ERROR: 0x%08x\n", dword);
52 break;
53 }
54 printk(BIOS_SPEW, "cbd=%u cbrp=%02u cbwp=%02u ready=%u "
55 "reset=%u ig=%u is=%u ie=%u\n", csr->buffer_depth,
56 csr->buffer_read_ptr, csr->buffer_write_ptr,
57 csr->ready, csr->reset, csr->interrupt_generate,
58 csr->interrupt_status, csr->interrupt_enable);
59 break;
60 case MEI_ME_CB_RW:
61 case MEI_H_CB_WW:
62 printk(BIOS_SPEW, "CB: 0x%08x\n", dword);
63 break;
64 default:
65 printk(BIOS_SPEW, "0x%08x\n", offset);
66 break;
67 }
68}
69
70/*
71 * ME/MEI access helpers using memcpy to avoid aliasing.
72 */
73
Angel Pons4def30d2020-06-02 20:10:36 +020074void mei_read_dword_ptr(void *ptr, int offset)
Angel Pons2e29c3b2020-08-10 15:47:28 +020075{
76 u32 dword = read32(mei_base_address + (offset / sizeof(u32)));
77 memcpy(ptr, &dword, sizeof(dword));
78 mei_dump(ptr, dword, offset, "READ");
79}
80
Angel Pons4def30d2020-06-02 20:10:36 +020081void mei_write_dword_ptr(void *ptr, int offset)
Angel Pons2e29c3b2020-08-10 15:47:28 +020082{
83 u32 dword = 0;
84 memcpy(&dword, ptr, sizeof(dword));
85 write32(mei_base_address + (offset / sizeof(u32)), dword);
86 mei_dump(ptr, dword, offset, "WRITE");
87}
88
Angel Pons4def30d2020-06-02 20:10:36 +020089void read_host_csr(struct mei_csr *csr)
Angel Pons2e29c3b2020-08-10 15:47:28 +020090{
91 mei_read_dword_ptr(csr, MEI_H_CSR);
92}
93
Angel Pons4def30d2020-06-02 20:10:36 +020094void write_host_csr(struct mei_csr *csr)
Angel Pons2e29c3b2020-08-10 15:47:28 +020095{
96 mei_write_dword_ptr(csr, MEI_H_CSR);
97}
98
Angel Pons4def30d2020-06-02 20:10:36 +020099void read_me_csr(struct mei_csr *csr)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200100{
101 mei_read_dword_ptr(csr, MEI_ME_CSR_HA);
102}
103
Angel Pons4def30d2020-06-02 20:10:36 +0200104void write_cb(u32 dword)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200105{
106 write32(mei_base_address + (MEI_H_CB_WW / sizeof(u32)), dword);
107 mei_dump(NULL, dword, MEI_H_CB_WW, "WRITE");
108}
109
Angel Pons4def30d2020-06-02 20:10:36 +0200110u32 read_cb(void)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200111{
112 u32 dword = read32(mei_base_address + (MEI_ME_CB_RW / sizeof(u32)));
113 mei_dump(NULL, dword, MEI_ME_CB_RW, "READ");
114 return dword;
115}
116
117/* Wait for ME ready bit to be asserted */
118static int mei_wait_for_me_ready(void)
119{
120 struct mei_csr me;
121 unsigned int try = ME_RETRY;
122
123 while (try--) {
124 read_me_csr(&me);
125 if (me.ready)
126 return 0;
127 udelay(ME_DELAY);
128 }
129
130 printk(BIOS_ERR, "ME: failed to become ready\n");
131 return -1;
132}
133
134static void mei_reset(void)
135{
136 struct mei_csr host;
137
138 if (mei_wait_for_me_ready() < 0)
139 return;
140
141 /* Reset host and ME circular buffers for next message */
142 read_host_csr(&host);
143 host.reset = 1;
144 host.interrupt_generate = 1;
145 write_host_csr(&host);
146
147 if (mei_wait_for_me_ready() < 0)
148 return;
149
150 /* Re-init and indicate host is ready */
151 read_host_csr(&host);
152 host.interrupt_generate = 1;
153 host.ready = 1;
154 host.reset = 0;
155 write_host_csr(&host);
156}
157
158static int mei_send_msg(struct mei_header *mei, struct mkhi_header *mkhi, void *req_data)
159{
160 struct mei_csr host;
161 unsigned int ndata, n;
162 u32 *data;
163
164 /* Number of dwords to write, ignoring MKHI */
165 ndata = mei->length >> 2;
166
167 /* Pad non-dword aligned request message length */
168 if (mei->length & 3)
169 ndata++;
Angel Pons4def30d2020-06-02 20:10:36 +0200170
Angel Pons2e29c3b2020-08-10 15:47:28 +0200171 if (!ndata) {
172 printk(BIOS_DEBUG, "ME: request does not include MKHI\n");
173 return -1;
174 }
175 ndata++; /* Add MEI header */
176
177 /*
178 * Make sure there is still room left in the circular buffer.
179 * Reset the buffer pointers if the requested message will not fit.
180 */
181 read_host_csr(&host);
182 if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
183 printk(BIOS_ERR, "ME: circular buffer full, resetting...\n");
184 mei_reset();
185 read_host_csr(&host);
186 }
187
188 /*
189 * This implementation does not handle splitting large messages
190 * across multiple transactions. Ensure the requested length
191 * will fit in the available circular buffer depth.
192 */
193 if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
194 printk(BIOS_ERR, "ME: message (%u) too large for buffer (%u)\n",
195 ndata + 2, host.buffer_depth);
196 return -1;
197 }
198
199 /* Write MEI header */
200 mei_write_dword_ptr(mei, MEI_H_CB_WW);
201 ndata--;
202
203 /* Write MKHI header */
204 mei_write_dword_ptr(mkhi, MEI_H_CB_WW);
205 ndata--;
206
207 /* Write message data */
208 data = req_data;
209 for (n = 0; n < ndata; ++n)
210 write_cb(*data++);
211
212 /* Generate interrupt to the ME */
213 read_host_csr(&host);
214 host.interrupt_generate = 1;
215 write_host_csr(&host);
216
217 /* Make sure ME is ready after sending request data */
218 return mei_wait_for_me_ready();
219}
220
221static int mei_recv_msg(struct mkhi_header *mkhi, void *rsp_data, int rsp_bytes)
222{
223 struct mei_header mei_rsp;
224 struct mkhi_header mkhi_rsp;
225 struct mei_csr me, host;
226 unsigned int ndata, n;
227 unsigned int expected;
228 u32 *data;
229
230 /* Total number of dwords to read from circular buffer */
231 expected = (rsp_bytes + sizeof(mei_rsp) + sizeof(mkhi_rsp)) >> 2;
232 if (rsp_bytes & 3)
233 expected++;
234
235 /*
236 * The interrupt status bit does not appear to indicate that the
237 * message has actually been received. Instead we wait until the
238 * expected number of dwords are present in the circular buffer.
239 */
240 for (n = ME_RETRY; n; --n) {
241 read_me_csr(&me);
242 if ((me.buffer_write_ptr - me.buffer_read_ptr) >= expected)
243 break;
244 udelay(ME_DELAY);
245 }
Angel Pons4def30d2020-06-02 20:10:36 +0200246
Angel Pons2e29c3b2020-08-10 15:47:28 +0200247 if (!n) {
248 printk(BIOS_ERR, "ME: timeout waiting for data: expected %u, available %u\n",
249 expected, me.buffer_write_ptr - me.buffer_read_ptr);
250 return -1;
251 }
252
253 /* Read and verify MEI response header from the ME */
254 mei_read_dword_ptr(&mei_rsp, MEI_ME_CB_RW);
255 if (!mei_rsp.is_complete) {
256 printk(BIOS_ERR, "ME: response is not complete\n");
257 return -1;
258 }
259
260 /* Handle non-dword responses and expect at least MKHI header */
261 ndata = mei_rsp.length >> 2;
262 if (mei_rsp.length & 3)
263 ndata++;
Angel Pons4def30d2020-06-02 20:10:36 +0200264
Angel Pons2e29c3b2020-08-10 15:47:28 +0200265 if (ndata != (expected - 1)) {
266 printk(BIOS_ERR, "ME: response is missing data %d != %d\n",
267 ndata, (expected - 1));
268 return -1;
269 }
270
271 /* Read and verify MKHI response header from the ME */
272 mei_read_dword_ptr(&mkhi_rsp, MEI_ME_CB_RW);
273 if (!mkhi_rsp.is_response ||
274 mkhi->group_id != mkhi_rsp.group_id ||
275 mkhi->command != mkhi_rsp.command) {
276 printk(BIOS_ERR, "ME: invalid response, group %u ?= %u, "
277 "command %u ?= %u, is_response %u\n", mkhi->group_id,
278 mkhi_rsp.group_id, mkhi->command, mkhi_rsp.command,
279 mkhi_rsp.is_response);
280 return -1;
281 }
282 ndata--; /* MKHI header has been read */
283
284 /* Make sure caller passed a buffer with enough space */
285 if (ndata != (rsp_bytes >> 2)) {
286 printk(BIOS_ERR, "ME: not enough room in response buffer: %u != %u\n",
287 ndata, rsp_bytes >> 2);
288 return -1;
289 }
290
291 /* Read response data from the circular buffer */
292 data = rsp_data;
293 for (n = 0; n < ndata; ++n)
294 *data++ = read_cb();
295
296 /* Tell the ME that we have consumed the response */
297 read_host_csr(&host);
298 host.interrupt_status = 1;
299 host.interrupt_generate = 1;
300 write_host_csr(&host);
301
302 return mei_wait_for_me_ready();
303}
304
Angel Pons4def30d2020-06-02 20:10:36 +0200305int mei_sendrecv(struct mei_header *mei, struct mkhi_header *mkhi,
306 void *req_data, void *rsp_data, int rsp_bytes)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200307{
308 if (mei_send_msg(mei, mkhi, req_data) < 0)
309 return -1;
310 if (mei_recv_msg(mkhi, rsp_data, rsp_bytes) < 0)
311 return -1;
312 return 0;
313}
314
315#ifdef __SIMPLE_DEVICE__
316
Angel Pons4def30d2020-06-02 20:10:36 +0200317void update_mei_base_address(void)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200318{
Patrick Rudolph819c2062019-11-29 19:27:37 +0100319 uint32_t reg32 = pci_read_config32(PCH_ME_DEV, PCI_BASE_ADDRESS_0) & ~0xf;
320 mei_base_address = (u32 *)(uintptr_t)reg32;
Angel Pons2e29c3b2020-08-10 15:47:28 +0200321}
322
Angel Pons4def30d2020-06-02 20:10:36 +0200323bool is_mei_base_address_valid(void)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200324{
325 return mei_base_address && mei_base_address != (u32 *)0xfffffff0;
326}
327
328#else
329
330/* Prepare ME for MEI messages */
Angel Pons4def30d2020-06-02 20:10:36 +0200331int intel_mei_setup(struct device *dev)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200332{
333 struct resource *res;
334 struct mei_csr host;
335
336 /* Find the MMIO base for the ME interface */
Angel Ponsf32ae102021-11-03 13:07:14 +0100337 res = probe_resource(dev, PCI_BASE_ADDRESS_0);
Angel Pons2e29c3b2020-08-10 15:47:28 +0200338 if (!res || res->base == 0 || res->size == 0) {
339 printk(BIOS_DEBUG, "ME: MEI resource not present!\n");
340 return -1;
341 }
342 mei_base_address = (u32 *)(uintptr_t)res->base;
343
344 /* Ensure Memory and Bus Master bits are set */
345 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
346
347 /* Clean up status for next message */
348 read_host_csr(&host);
349 host.interrupt_generate = 1;
350 host.ready = 1;
351 host.reset = 0;
352 write_host_csr(&host);
353
354 return 0;
355}
356
Angel Pons2e29c3b2020-08-10 15:47:28 +0200357/* Read the Extend register hash of ME firmware */
Angel Pons4def30d2020-06-02 20:10:36 +0200358int intel_me_extend_valid(struct device *dev)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200359{
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100360 union me_heres status;
Angel Pons2e29c3b2020-08-10 15:47:28 +0200361 u32 extend[8] = {0};
362 int i, count = 0;
363
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100364 status.raw = pci_read_config32(dev, PCI_ME_HERES);
Angel Pons2e29c3b2020-08-10 15:47:28 +0200365 if (!status.extend_feature_present) {
366 printk(BIOS_ERR, "ME: Extend Feature not present\n");
367 return -1;
368 }
369
370 if (!status.extend_reg_valid) {
371 printk(BIOS_ERR, "ME: Extend Register not valid\n");
372 return -1;
373 }
374
375 switch (status.extend_reg_algorithm) {
376 case PCI_ME_EXT_SHA1:
377 count = 5;
378 printk(BIOS_DEBUG, "ME: Extend SHA-1: ");
379 break;
380 case PCI_ME_EXT_SHA256:
381 count = 8;
382 printk(BIOS_DEBUG, "ME: Extend SHA-256: ");
383 break;
384 default:
385 printk(BIOS_ERR, "ME: Extend Algorithm %d unknown\n",
386 status.extend_reg_algorithm);
387 return -1;
388 }
389
390 for (i = 0; i < count; ++i) {
391 extend[i] = pci_read_config32(dev, PCI_ME_HER(i));
392 printk(BIOS_DEBUG, "%08x", extend[i]);
393 }
394 printk(BIOS_DEBUG, "\n");
395
Angel Pons2e29c3b2020-08-10 15:47:28 +0200396 /* Save hash in NVS for the OS to verify */
Kyösti Mälkki84d10cc2021-02-10 17:53:34 +0200397 if (CONFIG(CHROMEOS_NVS))
Kyösti Mälkki26e0f4c2020-12-19 19:10:45 +0200398 chromeos_set_me_hash(extend, count);
Angel Pons2e29c3b2020-08-10 15:47:28 +0200399
400 return 0;
401}
402
403/* Hide the ME virtual PCI devices */
Angel Pons4def30d2020-06-02 20:10:36 +0200404void intel_me_hide(struct device *dev)
Angel Pons2e29c3b2020-08-10 15:47:28 +0200405{
406 dev->enabled = 0;
407 pch_enable(dev);
408}
409
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300410bool enter_soft_temp_disable(void)
411{
412 /* The binary sequence for the disable command was found by PT in some vendor BIOS */
413 struct me_disable message = {
414 .rule_id = MKHI_DISABLE_RULE_ID,
415 .data = 0x01,
416 };
417 struct mkhi_header mkhi = {
418 .group_id = MKHI_GROUP_ID_FWCAPS,
419 .command = MKHI_FWCAPS_SET_RULE,
420 };
421 struct mei_header mei = {
422 .is_complete = 1,
423 .length = sizeof(mkhi) + sizeof(message),
424 .host_address = MEI_HOST_ADDRESS,
425 .client_address = MEI_ADDRESS_MKHI,
426 };
427 u32 resp;
428
429 if (mei_sendrecv(&mei, &mkhi, &message, &resp, sizeof(resp)) < 0
430 || resp != MKHI_DISABLE_RULE_ID) {
431 printk(BIOS_WARNING, "ME: disable command failed\n");
432 return false;
433 }
434
435 return true;
436}
437
438void enter_soft_temp_disable_wait(void)
439{
440 /*
441 * TODO: Find smarter way to determine when we're ready to reboot.
442 *
443 * There has to be some bit in some register, or something, that indicates that ME has
444 * finished doing its thing and we're ready to reboot.
445 *
446 * It was not found yet, though, and waiting for a response after the disable command is
447 * not enough. If we reboot too early, ME will not be disabled on next boot. For now,
448 * let's just wait for 1 second here.
449 */
450 mdelay(1000);
451}
452
453void exit_soft_temp_disable(struct device *dev)
454{
455 /* To bring ME out of Soft Temporary Disable Mode, host writes 0x20000000 to H_GS */
456 pci_write_config32(dev, PCI_ME_H_GS, 0x2 << 28);
457}
458
459void exit_soft_temp_disable_wait(struct device *dev)
460{
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100461 union me_hfs hfs;
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300462 struct stopwatch sw;
463
464 stopwatch_init_msecs_expire(&sw, ME_ENABLE_TIMEOUT);
465
466 /**
467 * Wait for fw_init_complete. Check every 50 ms, give up after 20 sec.
468 * This is what vendor BIOS does. Usually it takes 1.5 seconds or so.
469 */
470 do {
471 mdelay(50);
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100472 hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300473 if (hfs.fw_init_complete)
474 break;
475 } while (!stopwatch_expired(&sw));
476
477 if (!hfs.fw_init_complete)
478 printk(BIOS_ERR, "ME: giving up on waiting for fw_init_complete\n");
479 else
Rob Barnesd522f382022-09-12 06:31:47 -0600480 printk(BIOS_NOTICE, "ME: took %lldms to complete initialization\n",
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300481 stopwatch_duration_msecs(&sw));
482}
483
Angel Pons2e29c3b2020-08-10 15:47:28 +0200484#endif