blob: 1e6bdc8a5ab6f959d54b4490a0e8f439fd27595e [file] [log] [blame]
Angel Pons0612b272020-04-05 15:46:56 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Andrey Petrov04a72c42017-03-01 15:51:57 -08002
Subrata Banik05e06cd2017-11-09 15:04:09 +05303#include <assert.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08004#include <commonlib/helpers.h>
5#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02006#include <device/mmio.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08007#include <delay.h>
8#include <device/pci.h>
9#include <device/pci_ids.h>
10#include <device/pci_ops.h>
11#include <intelblocks/cse.h>
Tim Wawrzynczak09635f42021-06-18 10:08:47 -060012#include <security/vboot/misc.h>
13#include <security/vboot/vboot_common.h>
Subrata Banik05e06cd2017-11-09 15:04:09 +053014#include <soc/iomap.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080015#include <soc/pci_devs.h>
Sridhar Siricilla8e465452019-09-23 20:59:38 +053016#include <soc/me.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080017#include <string.h>
18#include <timer.h>
19
Subrata Banik5c08c732017-11-13 14:54:37 +053020#define MAX_HECI_MESSAGE_RETRY_COUNT 5
21
Andrey Petrov04a72c42017-03-01 15:51:57 -080022/* Wait up to 15 sec for HECI to get ready */
23#define HECI_DELAY_READY (15 * 1000)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010024/* Wait up to 100 usec between circular buffer polls */
Andrey Petrov04a72c42017-03-01 15:51:57 -080025#define HECI_DELAY 100
26/* Wait up to 5 sec for CSE to chew something we sent */
27#define HECI_SEND_TIMEOUT (5 * 1000)
28/* Wait up to 5 sec for CSE to blurp a reply */
29#define HECI_READ_TIMEOUT (5 * 1000)
30
31#define SLOT_SIZE sizeof(uint32_t)
32
33#define MMIO_CSE_CB_WW 0x00
34#define MMIO_HOST_CSR 0x04
35#define MMIO_CSE_CB_RW 0x08
36#define MMIO_CSE_CSR 0x0c
37
38#define CSR_IE (1 << 0)
39#define CSR_IS (1 << 1)
40#define CSR_IG (1 << 2)
41#define CSR_READY (1 << 3)
42#define CSR_RESET (1 << 4)
43#define CSR_RP_START 8
44#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
45#define CSR_WP_START 16
46#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
47#define CSR_CBD_START 24
48#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
49
50#define MEI_HDR_IS_COMPLETE (1 << 31)
51#define MEI_HDR_LENGTH_START 16
52#define MEI_HDR_LENGTH_SIZE 9
53#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
54 << MEI_HDR_LENGTH_START)
55#define MEI_HDR_HOST_ADDR_START 8
56#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
57#define MEI_HDR_CSE_ADDR_START 0
58#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
59
Sridhar Siricilla09ea3712019-11-12 23:35:50 +053060/* Wait up to 5 seconds for CSE to boot from RO(BP1) */
61#define CSE_DELAY_BOOT_TO_RO (5 * 1000)
62
Arthur Heymans3d6ccd02019-05-27 17:25:23 +020063static struct cse_device {
Andrey Petrov04a72c42017-03-01 15:51:57 -080064 uintptr_t sec_bar;
Patrick Georgic9b13592019-11-29 11:47:47 +010065} cse;
Andrey Petrov04a72c42017-03-01 15:51:57 -080066
67/*
68 * Initialize the device with provided temporary BAR. If BAR is 0 use a
69 * default. This is intended for pre-mem usage only where BARs haven't been
70 * assigned yet and devices are not enabled.
71 */
72void heci_init(uintptr_t tempbar)
73{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +020074#if defined(__SIMPLE_DEVICE__)
75 pci_devfn_t dev = PCH_DEV_CSE;
76#else
77 struct device *dev = PCH_DEV_CSE;
78#endif
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020079 u16 pcireg;
Andrey Petrov04a72c42017-03-01 15:51:57 -080080
81 /* Assume it is already initialized, nothing else to do */
Patrick Georgic9b13592019-11-29 11:47:47 +010082 if (cse.sec_bar)
Andrey Petrov04a72c42017-03-01 15:51:57 -080083 return;
84
85 /* Use default pre-ram bar */
86 if (!tempbar)
87 tempbar = HECI1_BASE_ADDRESS;
88
89 /* Assign Resources to HECI1 */
90 /* Clear BIT 1-2 of Command Register */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020091 pcireg = pci_read_config16(dev, PCI_COMMAND);
Andrey Petrov04a72c42017-03-01 15:51:57 -080092 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020093 pci_write_config16(dev, PCI_COMMAND, pcireg);
Andrey Petrov04a72c42017-03-01 15:51:57 -080094
95 /* Program Temporary BAR for HECI1 */
96 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
97 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
98
99 /* Enable Bus Master and MMIO Space */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200100 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800101
Patrick Georgic9b13592019-11-29 11:47:47 +0100102 cse.sec_bar = tempbar;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800103}
104
Subrata Banik05e06cd2017-11-09 15:04:09 +0530105/* Get HECI BAR 0 from PCI configuration space */
106static uint32_t get_cse_bar(void)
107{
108 uintptr_t bar;
109
110 bar = pci_read_config32(PCH_DEV_CSE, PCI_BASE_ADDRESS_0);
111 assert(bar != 0);
112 /*
113 * Bits 31-12 are the base address as per EDS for SPI,
114 * Don't care about 0-11 bit
115 */
116 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
117}
118
Andrey Petrov04a72c42017-03-01 15:51:57 -0800119static uint32_t read_bar(uint32_t offset)
120{
Patrick Georgi08c8cf92019-12-02 11:43:20 +0100121 /* Load and cache BAR */
Patrick Georgic9b13592019-11-29 11:47:47 +0100122 if (!cse.sec_bar)
123 cse.sec_bar = get_cse_bar();
124 return read32((void *)(cse.sec_bar + offset));
Andrey Petrov04a72c42017-03-01 15:51:57 -0800125}
126
127static void write_bar(uint32_t offset, uint32_t val)
128{
Patrick Georgi08c8cf92019-12-02 11:43:20 +0100129 /* Load and cache BAR */
Patrick Georgic9b13592019-11-29 11:47:47 +0100130 if (!cse.sec_bar)
131 cse.sec_bar = get_cse_bar();
132 return write32((void *)(cse.sec_bar + offset), val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800133}
134
135static uint32_t read_cse_csr(void)
136{
137 return read_bar(MMIO_CSE_CSR);
138}
139
140static uint32_t read_host_csr(void)
141{
142 return read_bar(MMIO_HOST_CSR);
143}
144
145static void write_host_csr(uint32_t data)
146{
147 write_bar(MMIO_HOST_CSR, data);
148}
149
150static size_t filled_slots(uint32_t data)
151{
152 uint8_t wp, rp;
153 rp = data >> CSR_RP_START;
154 wp = data >> CSR_WP_START;
155 return (uint8_t) (wp - rp);
156}
157
158static size_t cse_filled_slots(void)
159{
160 return filled_slots(read_cse_csr());
161}
162
163static size_t host_empty_slots(void)
164{
165 uint32_t csr;
166 csr = read_host_csr();
167
168 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
169}
170
171static void clear_int(void)
172{
173 uint32_t csr;
174 csr = read_host_csr();
175 csr |= CSR_IS;
176 write_host_csr(csr);
177}
178
179static uint32_t read_slot(void)
180{
181 return read_bar(MMIO_CSE_CB_RW);
182}
183
184static void write_slot(uint32_t val)
185{
186 write_bar(MMIO_CSE_CB_WW, val);
187}
188
189static int wait_write_slots(size_t cnt)
190{
191 struct stopwatch sw;
192
193 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
194 while (host_empty_slots() < cnt) {
195 udelay(HECI_DELAY);
196 if (stopwatch_expired(&sw)) {
197 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
198 return 0;
199 }
200 }
201 return 1;
202}
203
204static int wait_read_slots(size_t cnt)
205{
206 struct stopwatch sw;
207
208 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
209 while (cse_filled_slots() < cnt) {
210 udelay(HECI_DELAY);
211 if (stopwatch_expired(&sw)) {
212 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
213 return 0;
214 }
215 }
216 return 1;
217}
218
219/* get number of full 4-byte slots */
220static size_t bytes_to_slots(size_t bytes)
221{
222 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
223}
224
225static int cse_ready(void)
226{
227 uint32_t csr;
228 csr = read_cse_csr();
229 return csr & CSR_READY;
230}
231
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530232static bool cse_check_hfs1_com(int mode)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530233{
234 union me_hfsts1 hfs1;
235 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530236 return hfs1.fields.operation_mode == mode;
237}
238
239bool cse_is_hfs1_cws_normal(void)
240{
241 union me_hfsts1 hfs1;
242 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
243 if (hfs1.fields.working_state == ME_HFS1_CWS_NORMAL)
244 return true;
245 return false;
246}
247
248bool cse_is_hfs1_com_normal(void)
249{
250 return cse_check_hfs1_com(ME_HFS1_COM_NORMAL);
251}
252
253bool cse_is_hfs1_com_secover_mei_msg(void)
254{
255 return cse_check_hfs1_com(ME_HFS1_COM_SECOVER_MEI_MSG);
256}
257
258bool cse_is_hfs1_com_soft_temp_disable(void)
259{
260 return cse_check_hfs1_com(ME_HFS1_COM_SOFT_TEMP_DISABLE);
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530261}
262
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530263bool cse_is_hfs3_fw_sku_lite(void)
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530264{
265 union me_hfsts3 hfs3;
266 hfs3.data = me_read_config32(PCI_ME_HFSTS3);
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530267 return hfs3.fields.fw_sku == ME_HFS3_FW_SKU_LITE;
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530268}
269
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530270/* Makes the host ready to communicate with CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530271void cse_set_host_ready(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530272{
273 uint32_t csr;
274 csr = read_host_csr();
275 csr &= ~CSR_RESET;
276 csr |= (CSR_IG | CSR_READY);
277 write_host_csr(csr);
278}
279
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530280/* Polls for ME mode ME_HFS1_COM_SECOVER_MEI_MSG for 15 seconds */
281uint8_t cse_wait_sec_override_mode(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530282{
283 struct stopwatch sw;
284 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530285 while (!cse_is_hfs1_com_secover_mei_msg()) {
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530286 udelay(HECI_DELAY);
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530287 if (stopwatch_expired(&sw)) {
288 printk(BIOS_ERR, "HECI: Timed out waiting for SEC_OVERRIDE mode!\n");
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530289 return 0;
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530290 }
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530291 }
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530292 printk(BIOS_DEBUG, "HECI: CSE took %lu ms to enter security override mode\n",
293 stopwatch_duration_msecs(&sw));
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530294 return 1;
295}
296
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530297/*
298 * Polls for CSE's current operation mode 'Soft Temporary Disable'.
299 * The CSE enters the current operation mode when it boots from RO(BP1).
300 */
301uint8_t cse_wait_com_soft_temp_disable(void)
302{
303 struct stopwatch sw;
304 stopwatch_init_msecs_expire(&sw, CSE_DELAY_BOOT_TO_RO);
305 while (!cse_is_hfs1_com_soft_temp_disable()) {
306 udelay(HECI_DELAY);
307 if (stopwatch_expired(&sw)) {
308 printk(BIOS_ERR, "HECI: Timed out waiting for CSE to boot from RO!\n");
309 return 0;
310 }
311 }
312 printk(BIOS_SPEW, "HECI: CSE took %lu ms to boot from RO\n",
313 stopwatch_duration_msecs(&sw));
314 return 1;
315}
316
Andrey Petrov04a72c42017-03-01 15:51:57 -0800317static int wait_heci_ready(void)
318{
319 struct stopwatch sw;
320
321 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
322 while (!cse_ready()) {
323 udelay(HECI_DELAY);
324 if (stopwatch_expired(&sw))
325 return 0;
326 }
327
328 return 1;
329}
330
331static void host_gen_interrupt(void)
332{
333 uint32_t csr;
334 csr = read_host_csr();
335 csr |= CSR_IG;
336 write_host_csr(csr);
337}
338
339static size_t hdr_get_length(uint32_t hdr)
340{
341 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
342}
343
344static int
345send_one_message(uint32_t hdr, const void *buff)
346{
347 size_t pend_len, pend_slots, remainder, i;
348 uint32_t tmp;
349 const uint32_t *p = buff;
350
351 /* Get space for the header */
352 if (!wait_write_slots(1))
353 return 0;
354
355 /* First, write header */
356 write_slot(hdr);
357
358 pend_len = hdr_get_length(hdr);
359 pend_slots = bytes_to_slots(pend_len);
360
361 if (!wait_write_slots(pend_slots))
362 return 0;
363
364 /* Write the body in whole slots */
365 i = 0;
366 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
367 write_slot(*p++);
368 i += SLOT_SIZE;
369 }
370
371 remainder = pend_len % SLOT_SIZE;
372 /* Pad to 4 bytes not touching caller's buffer */
373 if (remainder) {
374 memcpy(&tmp, p, remainder);
375 write_slot(tmp);
376 }
377
378 host_gen_interrupt();
379
380 /* Make sure nothing bad happened during transmission */
381 if (!cse_ready())
382 return 0;
383
384 return pend_len;
385}
386
387int
388heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
389{
Subrata Banik5c08c732017-11-13 14:54:37 +0530390 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800391 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530392 size_t sent, remaining, cb_size, max_length;
393 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800394
395 if (!msg || !len)
396 return 0;
397
398 clear_int();
399
Subrata Banik5c08c732017-11-13 14:54:37 +0530400 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
401 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800402
Subrata Banik5c08c732017-11-13 14:54:37 +0530403 if (!wait_heci_ready()) {
404 printk(BIOS_ERR, "HECI: not ready\n");
405 continue;
406 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800407
Subrata Banik4a722f52017-11-13 14:56:42 +0530408 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530409 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
410 /*
411 * Reserve one slot for the header. Limit max message
412 * length by 9 bits that are available in the header.
413 */
414 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
415 - SLOT_SIZE;
416 remaining = len;
417
418 /*
419 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100420 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530421 */
422 do {
423 hdr = MIN(max_length, remaining)
424 << MEI_HDR_LENGTH_START;
425 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
426 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
427 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800428 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530429 sent = send_one_message(hdr, p);
430 p += sent;
431 remaining -= sent;
432 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800433
Subrata Banik5c08c732017-11-13 14:54:37 +0530434 if (!remaining)
435 return 1;
436 }
437 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800438}
439
440static size_t
441recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
442{
443 uint32_t reg, *p = buff;
444 size_t recv_slots, recv_len, remainder, i;
445
446 /* first get the header */
447 if (!wait_read_slots(1))
448 return 0;
449
450 *hdr = read_slot();
451 recv_len = hdr_get_length(*hdr);
452
453 if (!recv_len)
454 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
455
456 recv_slots = bytes_to_slots(recv_len);
457
458 i = 0;
459 if (recv_len > maxlen) {
460 printk(BIOS_ERR, "HECI: response is too big\n");
461 return 0;
462 }
463
464 /* wait for the rest of messages to arrive */
465 wait_read_slots(recv_slots);
466
467 /* fetch whole slots first */
468 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
469 *p++ = read_slot();
470 i += SLOT_SIZE;
471 }
472
Subrata Banik5c08c732017-11-13 14:54:37 +0530473 /*
474 * If ME is not ready, something went wrong and
475 * we received junk
476 */
477 if (!cse_ready())
478 return 0;
479
Andrey Petrov04a72c42017-03-01 15:51:57 -0800480 remainder = recv_len % SLOT_SIZE;
481
482 if (remainder) {
483 reg = read_slot();
484 memcpy(p, &reg, remainder);
485 }
486
487 return recv_len;
488}
489
490int heci_receive(void *buff, size_t *maxlen)
491{
Subrata Banik5c08c732017-11-13 14:54:37 +0530492 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800493 size_t left, received;
494 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530495 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800496
497 if (!buff || !maxlen || !*maxlen)
498 return 0;
499
Andrey Petrov04a72c42017-03-01 15:51:57 -0800500 clear_int();
501
Subrata Banik5c08c732017-11-13 14:54:37 +0530502 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
503 p = buff;
504 left = *maxlen;
505
506 if (!wait_heci_ready()) {
507 printk(BIOS_ERR, "HECI: not ready\n");
508 continue;
509 }
510
511 /*
512 * Receive multiple packets until we meet one marked
513 * complete or we run out of space in caller-provided buffer.
514 */
515 do {
516 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800517 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200518 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800519 return 0;
520 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530521 left -= received;
522 p += received;
523 /* If we read out everything ping to send more */
524 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
525 host_gen_interrupt();
526 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
527
528 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
529 *maxlen = p - (uint8_t *) buff;
530 return 1;
531 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800532 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530533 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800534}
535
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530536int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz)
537{
538 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, HECI_MKHI_ADDR)) {
539 printk(BIOS_ERR, "HECI: send Failed\n");
540 return 0;
541 }
542
543 if (rcv_msg != NULL) {
544 if (!heci_receive(rcv_msg, rcv_sz)) {
545 printk(BIOS_ERR, "HECI: receive Failed\n");
546 return 0;
547 }
548 }
549 return 1;
550}
551
Andrey Petrov04a72c42017-03-01 15:51:57 -0800552/*
553 * Attempt to reset the device. This is useful when host and ME are out
554 * of sync during transmission or ME didn't understand the message.
555 */
556int heci_reset(void)
557{
558 uint32_t csr;
559
Duncan Laurie15ca9032020-11-05 10:09:07 -0800560 /* Clear post code to prevent eventlog entry from unknown code. */
561 post_code(0);
562
Andrey Petrov04a72c42017-03-01 15:51:57 -0800563 /* Send reset request */
564 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530565 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800566 write_host_csr(csr);
567
568 if (wait_heci_ready()) {
569 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530570 cse_set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800571 return 1;
572 }
573
574 printk(BIOS_CRIT, "HECI: reset failed\n");
575
576 return 0;
577}
578
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530579bool is_cse_enabled(void)
580{
581 const struct device *cse_dev = pcidev_path_on_root(PCH_DEVFN_CSE);
582
583 if (!cse_dev || !cse_dev->enabled) {
584 printk(BIOS_WARNING, "HECI: No CSE device\n");
585 return false;
586 }
587
588 if (pci_read_config16(PCH_DEV_CSE, PCI_VENDOR_ID) == 0xFFFF) {
589 printk(BIOS_WARNING, "HECI: CSE device is hidden\n");
590 return false;
591 }
592
593 return true;
594}
595
596uint32_t me_read_config32(int offset)
597{
598 return pci_read_config32(PCH_DEV_CSE, offset);
599}
600
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530601static bool cse_is_global_reset_allowed(void)
602{
603 /*
604 * Allow sending GLOBAL_RESET command only if:
605 * - CSE's current working state is Normal and current operation mode is Normal.
606 * - (or) CSE's current working state is normal and current operation mode can
607 * be Soft Temp Disable or Security Override Mode if CSE's Firmware SKU is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530608 * Lite.
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530609 */
610 if (!cse_is_hfs1_cws_normal())
611 return false;
612
613 if (cse_is_hfs1_com_normal())
614 return true;
615
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530616 if (cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530617 if (cse_is_hfs1_com_soft_temp_disable() || cse_is_hfs1_com_secover_mei_msg())
618 return true;
619 }
620 return false;
621}
622
Sridhar Siricillad415c202019-08-31 14:54:57 +0530623/*
Subrata Banikf463dc02020-09-14 19:04:03 +0530624 * Sends GLOBAL_RESET_REQ cmd to CSE with reset type GLOBAL_RESET.
625 * Returns 0 on failure and 1 on success.
Sridhar Siricillad415c202019-08-31 14:54:57 +0530626 */
Subrata Banikf463dc02020-09-14 19:04:03 +0530627static int cse_request_reset(enum rst_req_type rst_type)
Sridhar Siricillad415c202019-08-31 14:54:57 +0530628{
629 int status;
630 struct mkhi_hdr reply;
631 struct reset_message {
632 struct mkhi_hdr hdr;
633 uint8_t req_origin;
634 uint8_t reset_type;
635 } __packed;
636 struct reset_message msg = {
637 .hdr = {
638 .group_id = MKHI_GROUP_ID_CBM,
Sridhar Siricillae202e672020-01-07 23:36:40 +0530639 .command = MKHI_CBM_GLOBAL_RESET_REQ,
Sridhar Siricillad415c202019-08-31 14:54:57 +0530640 },
641 .req_origin = GR_ORIGIN_BIOS_POST,
642 .reset_type = rst_type
643 };
644 size_t reply_size;
645
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530646 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530647
Sridhar Siricillac2a2d2b2020-02-27 17:16:13 +0530648 if (!(rst_type == GLOBAL_RESET || rst_type == CSE_RESET_ONLY)) {
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530649 printk(BIOS_ERR, "HECI: Unsupported reset type is requested\n");
650 return 0;
651 }
Sridhar Siricillad415c202019-08-31 14:54:57 +0530652
Subrata Banikf463dc02020-09-14 19:04:03 +0530653 if (!cse_is_global_reset_allowed() || !is_cse_enabled()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530654 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
655 return 0;
656 }
657
Sridhar Siricillad415c202019-08-31 14:54:57 +0530658 heci_reset();
659
660 reply_size = sizeof(reply);
661 memset(&reply, 0, reply_size);
662
Sridhar Siricillad415c202019-08-31 14:54:57 +0530663 if (rst_type == CSE_RESET_ONLY)
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530664 status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530665 else
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530666 status = heci_send_receive(&msg, sizeof(msg), &reply, &reply_size);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530667
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530668 printk(BIOS_DEBUG, "HECI: Global Reset %s!\n", status ? "success" : "failure");
669 return status;
Sridhar Siricillad415c202019-08-31 14:54:57 +0530670}
671
Subrata Banikf463dc02020-09-14 19:04:03 +0530672int cse_request_global_reset(void)
673{
674 return cse_request_reset(GLOBAL_RESET);
675}
676
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530677static bool cse_is_hmrfpo_enable_allowed(void)
678{
679 /*
680 * Allow sending HMRFPO ENABLE command only if:
681 * - CSE's current working state is Normal and current operation mode is Normal
682 * - (or) cse's current working state is normal and current operation mode is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530683 * Soft Temp Disable if CSE's Firmware SKU is Lite
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530684 */
685 if (!cse_is_hfs1_cws_normal())
686 return false;
687
688 if (cse_is_hfs1_com_normal())
689 return true;
690
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530691 if (cse_is_hfs3_fw_sku_lite() && cse_is_hfs1_com_soft_temp_disable())
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530692 return true;
693
694 return false;
695}
696
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530697/* Sends HMRFPO Enable command to CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530698int cse_hmrfpo_enable(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530699{
700 struct hmrfpo_enable_msg {
701 struct mkhi_hdr hdr;
702 uint32_t nonce[2];
703 } __packed;
704
705 /* HMRFPO Enable message */
706 struct hmrfpo_enable_msg msg = {
707 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530708 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530709 .command = MKHI_HMRFPO_ENABLE,
710 },
711 .nonce = {0},
712 };
713
714 /* HMRFPO Enable response */
715 struct hmrfpo_enable_resp {
716 struct mkhi_hdr hdr;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530717 /* Base addr for factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530718 uint32_t fct_base;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530719 /* Length of factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530720 uint32_t fct_limit;
721 uint8_t status;
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530722 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530723 } __packed;
724
725 struct hmrfpo_enable_resp resp;
726 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530727
728 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530729
730 if (!cse_is_hmrfpo_enable_allowed()) {
731 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
732 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530733 }
734
735 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
736 &resp, &resp_size))
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530737 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530738
739 if (resp.hdr.result) {
740 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530741 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530742 }
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530743
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530744 if (resp.status) {
745 printk(BIOS_ERR, "HECI: HMRFPO_Enable Failed (resp status: %d)\n", resp.status);
746 return 0;
747 }
748
749 return 1;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530750}
751
752/*
753 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530754 * The status can be DISABLED/LOCKED/ENABLED
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530755 */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530756int cse_hmrfpo_get_status(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530757{
758 struct hmrfpo_get_status_msg {
759 struct mkhi_hdr hdr;
760 } __packed;
761
762 struct hmrfpo_get_status_resp {
763 struct mkhi_hdr hdr;
764 uint8_t status;
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530765 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530766 } __packed;
767
768 struct hmrfpo_get_status_msg msg = {
769 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530770 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530771 .command = MKHI_HMRFPO_GET_STATUS,
772 },
773 };
774 struct hmrfpo_get_status_resp resp;
775 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
776
777 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
778
Sridhar Siricilla206905c2020-02-06 18:48:22 +0530779 if (!cse_is_hfs1_cws_normal()) {
780 printk(BIOS_ERR, "HECI: CSE's current working state is not Normal\n");
781 return -1;
782 }
783
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530784 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
785 &resp, &resp_size)) {
786 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
787 return -1;
788 }
789
790 if (resp.hdr.result) {
791 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
792 resp.hdr.result);
793 return -1;
794 }
795
796 return resp.status;
797}
798
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530799void print_me_fw_version(void *unused)
800{
801 struct version {
802 uint16_t minor;
803 uint16_t major;
804 uint16_t build;
805 uint16_t hotfix;
806 } __packed;
807
808 struct fw_ver_resp {
809 struct mkhi_hdr hdr;
810 struct version code;
811 struct version rec;
812 struct version fitc;
813 } __packed;
814
815 const struct mkhi_hdr fw_ver_msg = {
816 .group_id = MKHI_GROUP_ID_GEN,
817 .command = MKHI_GEN_GET_FW_VERSION,
818 };
819
820 struct fw_ver_resp resp;
821 size_t resp_size = sizeof(resp);
822
823 /* Ignore if UART debugging is disabled */
824 if (!CONFIG(CONSOLE_SERIAL))
825 return;
826
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200827 /* Ignore if CSE is disabled */
828 if (!is_cse_enabled())
829 return;
830
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530831 /*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530832 * Ignore if ME Firmware SKU type is Lite since
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530833 * print_boot_partition_info() logs RO(BP1) and RW(BP2) versions.
834 */
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530835 if (cse_is_hfs3_fw_sku_lite())
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530836 return;
837
838 /*
839 * Prerequisites:
840 * 1) HFSTS1 Current Working State is Normal
841 * 2) HFSTS1 Current Operation Mode is Normal
842 * 3) It's after DRAM INIT DONE message (taken care of by calling it
843 * during ramstage
844 */
845 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal())
846 goto fail;
847
848 heci_reset();
849
850 if (!heci_send_receive(&fw_ver_msg, sizeof(fw_ver_msg), &resp, &resp_size))
851 goto fail;
852
853 if (resp.hdr.result)
854 goto fail;
855
856 printk(BIOS_DEBUG, "ME: Version: %d.%d.%d.%d\n", resp.code.major,
857 resp.code.minor, resp.code.hotfix, resp.code.build);
858 return;
859
860fail:
861 printk(BIOS_DEBUG, "ME: Version: Unavailable\n");
862}
863
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600864void cse_trigger_vboot_recovery(enum csme_failure_reason reason)
865{
866 printk(BIOS_DEBUG, "cse: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
867 "HFSTS3: 0x%x\n", me_read_config32(PCI_ME_HFSTS1),
868 me_read_config32(PCI_ME_HFSTS2), me_read_config32(PCI_ME_HFSTS3));
869
870 if (CONFIG(VBOOT)) {
871 struct vb2_context *ctx = vboot_get_context();
872 if (ctx == NULL)
873 goto failure;
874 vb2api_fail(ctx, VB2_RECOVERY_INTEL_CSE_LITE_SKU, reason);
875 vboot_save_data(ctx);
876 vboot_reboot();
877 }
878failure:
879 die("cse: Failed to trigger recovery mode(recovery subcode:%d)\n", reason);
880}
881
Andrey Petrov04a72c42017-03-01 15:51:57 -0800882#if ENV_RAMSTAGE
883
884static void update_sec_bar(struct device *dev)
885{
Patrick Georgic9b13592019-11-29 11:47:47 +0100886 cse.sec_bar = find_resource(dev, PCI_BASE_ADDRESS_0)->base;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800887}
888
889static void cse_set_resources(struct device *dev)
890{
Subrata Banik2ee54db2017-03-05 12:37:00 +0530891 if (dev->path.pci.devfn == PCH_DEVFN_CSE)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800892 update_sec_bar(dev);
893
894 pci_dev_set_resources(dev);
895}
896
897static struct device_operations cse_ops = {
898 .set_resources = cse_set_resources,
899 .read_resources = pci_dev_read_resources,
900 .enable_resources = pci_dev_enable_resources,
901 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530902 .ops_pci = &pci_dev_ops_pci,
Andrey Petrov04a72c42017-03-01 15:51:57 -0800903};
904
Hannah Williams63142152017-06-12 14:03:18 -0700905static const unsigned short pci_device_ids[] = {
906 PCI_DEVICE_ID_INTEL_APL_CSE0,
907 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -0700908 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Subrata Banikd0586d22017-11-27 13:28:41 +0530909 PCI_DEVICE_ID_INTEL_SKL_CSE0,
Maxim Polyakov571d07d2019-08-22 13:11:32 +0300910 PCI_DEVICE_ID_INTEL_LWB_CSE0,
911 PCI_DEVICE_ID_INTEL_LWB_CSE0_SUPER,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800912 PCI_DEVICE_ID_INTEL_CNP_H_CSE0,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530913 PCI_DEVICE_ID_INTEL_ICL_CSE0,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +0530914 PCI_DEVICE_ID_INTEL_CMP_CSE0,
Gaggery Tsai12a651c2019-12-05 11:23:20 -0800915 PCI_DEVICE_ID_INTEL_CMP_H_CSE0,
Ravi Sarawadi6b5bf402019-10-21 22:25:04 -0700916 PCI_DEVICE_ID_INTEL_TGL_CSE0,
Tan, Lean Sheng26136092020-01-20 19:13:56 -0800917 PCI_DEVICE_ID_INTEL_MCC_CSE0,
918 PCI_DEVICE_ID_INTEL_MCC_CSE1,
919 PCI_DEVICE_ID_INTEL_MCC_CSE2,
920 PCI_DEVICE_ID_INTEL_MCC_CSE3,
Meera Ravindranath3f4af0d2020-02-12 16:01:22 +0530921 PCI_DEVICE_ID_INTEL_JSP_CSE0,
922 PCI_DEVICE_ID_INTEL_JSP_CSE1,
923 PCI_DEVICE_ID_INTEL_JSP_CSE2,
924 PCI_DEVICE_ID_INTEL_JSP_CSE3,
Subrata Banikf672f7f2020-08-03 14:29:25 +0530925 PCI_DEVICE_ID_INTEL_ADP_P_CSE0,
926 PCI_DEVICE_ID_INTEL_ADP_P_CSE1,
927 PCI_DEVICE_ID_INTEL_ADP_P_CSE2,
928 PCI_DEVICE_ID_INTEL_ADP_P_CSE3,
929 PCI_DEVICE_ID_INTEL_ADP_S_CSE0,
930 PCI_DEVICE_ID_INTEL_ADP_S_CSE1,
931 PCI_DEVICE_ID_INTEL_ADP_S_CSE2,
932 PCI_DEVICE_ID_INTEL_ADP_S_CSE3,
Varshit Pandyaf4d98fdd22021-01-17 18:39:29 +0530933 PCI_DEVICE_ID_INTEL_ADP_M_CSE0,
934 PCI_DEVICE_ID_INTEL_ADP_M_CSE1,
935 PCI_DEVICE_ID_INTEL_ADP_M_CSE2,
936 PCI_DEVICE_ID_INTEL_ADP_M_CSE3,
Hannah Williams63142152017-06-12 14:03:18 -0700937 0,
938};
939
Andrey Petrov04a72c42017-03-01 15:51:57 -0800940static const struct pci_driver cse_driver __pci_driver = {
941 .ops = &cse_ops,
942 .vendor = PCI_VENDOR_ID_INTEL,
943 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -0700944 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -0800945};
946
947#endif