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