blob: fd6cb45dbb4d1378f8f9b1b0de5ffb4fa10c0864 [file] [log] [blame]
Angel Pons0612b272020-04-05 15:46:56 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Andrey Petrov04a72c42017-03-01 15:51:57 -08003
Subrata Banik05e06cd2017-11-09 15:04:09 +05304#include <assert.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08005#include <commonlib/helpers.h>
6#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08008#include <delay.h>
9#include <device/pci.h>
10#include <device/pci_ids.h>
11#include <device/pci_ops.h>
12#include <intelblocks/cse.h>
Subrata Banik05e06cd2017-11-09 15:04:09 +053013#include <soc/iomap.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080014#include <soc/pci_devs.h>
Sridhar Siricilla8e465452019-09-23 20:59:38 +053015#include <soc/me.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080016#include <string.h>
17#include <timer.h>
18
Subrata Banik5c08c732017-11-13 14:54:37 +053019#define MAX_HECI_MESSAGE_RETRY_COUNT 5
20
Andrey Petrov04a72c42017-03-01 15:51:57 -080021/* Wait up to 15 sec for HECI to get ready */
22#define HECI_DELAY_READY (15 * 1000)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010023/* Wait up to 100 usec between circular buffer polls */
Andrey Petrov04a72c42017-03-01 15:51:57 -080024#define HECI_DELAY 100
25/* Wait up to 5 sec for CSE to chew something we sent */
26#define HECI_SEND_TIMEOUT (5 * 1000)
27/* Wait up to 5 sec for CSE to blurp a reply */
28#define HECI_READ_TIMEOUT (5 * 1000)
29
30#define SLOT_SIZE sizeof(uint32_t)
31
32#define MMIO_CSE_CB_WW 0x00
33#define MMIO_HOST_CSR 0x04
34#define MMIO_CSE_CB_RW 0x08
35#define MMIO_CSE_CSR 0x0c
36
37#define CSR_IE (1 << 0)
38#define CSR_IS (1 << 1)
39#define CSR_IG (1 << 2)
40#define CSR_READY (1 << 3)
41#define CSR_RESET (1 << 4)
42#define CSR_RP_START 8
43#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
44#define CSR_WP_START 16
45#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
46#define CSR_CBD_START 24
47#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
48
49#define MEI_HDR_IS_COMPLETE (1 << 31)
50#define MEI_HDR_LENGTH_START 16
51#define MEI_HDR_LENGTH_SIZE 9
52#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
53 << MEI_HDR_LENGTH_START)
54#define MEI_HDR_HOST_ADDR_START 8
55#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
56#define MEI_HDR_CSE_ADDR_START 0
57#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
58
Sridhar Siricilla09ea3712019-11-12 23:35:50 +053059/* Wait up to 5 seconds for CSE to boot from RO(BP1) */
60#define CSE_DELAY_BOOT_TO_RO (5 * 1000)
61
Arthur Heymans3d6ccd02019-05-27 17:25:23 +020062static struct cse_device {
Andrey Petrov04a72c42017-03-01 15:51:57 -080063 uintptr_t sec_bar;
Patrick Georgic9b13592019-11-29 11:47:47 +010064} cse;
Andrey Petrov04a72c42017-03-01 15:51:57 -080065
66/*
67 * Initialize the device with provided temporary BAR. If BAR is 0 use a
68 * default. This is intended for pre-mem usage only where BARs haven't been
69 * assigned yet and devices are not enabled.
70 */
71void heci_init(uintptr_t tempbar)
72{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +020073#if defined(__SIMPLE_DEVICE__)
74 pci_devfn_t dev = PCH_DEV_CSE;
75#else
76 struct device *dev = PCH_DEV_CSE;
77#endif
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020078 u16 pcireg;
Andrey Petrov04a72c42017-03-01 15:51:57 -080079
80 /* Assume it is already initialized, nothing else to do */
Patrick Georgic9b13592019-11-29 11:47:47 +010081 if (cse.sec_bar)
Andrey Petrov04a72c42017-03-01 15:51:57 -080082 return;
83
84 /* Use default pre-ram bar */
85 if (!tempbar)
86 tempbar = HECI1_BASE_ADDRESS;
87
88 /* Assign Resources to HECI1 */
89 /* Clear BIT 1-2 of Command Register */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020090 pcireg = pci_read_config16(dev, PCI_COMMAND);
Andrey Petrov04a72c42017-03-01 15:51:57 -080091 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020092 pci_write_config16(dev, PCI_COMMAND, pcireg);
Andrey Petrov04a72c42017-03-01 15:51:57 -080093
94 /* Program Temporary BAR for HECI1 */
95 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
96 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
97
98 /* Enable Bus Master and MMIO Space */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020099 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800100
Patrick Georgic9b13592019-11-29 11:47:47 +0100101 cse.sec_bar = tempbar;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800102}
103
Subrata Banik05e06cd2017-11-09 15:04:09 +0530104/* Get HECI BAR 0 from PCI configuration space */
105static uint32_t get_cse_bar(void)
106{
107 uintptr_t bar;
108
109 bar = pci_read_config32(PCH_DEV_CSE, PCI_BASE_ADDRESS_0);
110 assert(bar != 0);
111 /*
112 * Bits 31-12 are the base address as per EDS for SPI,
113 * Don't care about 0-11 bit
114 */
115 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
116}
117
Andrey Petrov04a72c42017-03-01 15:51:57 -0800118static uint32_t read_bar(uint32_t offset)
119{
Patrick Georgi08c8cf92019-12-02 11:43:20 +0100120 /* Load and cache BAR */
Patrick Georgic9b13592019-11-29 11:47:47 +0100121 if (!cse.sec_bar)
122 cse.sec_bar = get_cse_bar();
123 return read32((void *)(cse.sec_bar + offset));
Andrey Petrov04a72c42017-03-01 15:51:57 -0800124}
125
126static void write_bar(uint32_t offset, uint32_t val)
127{
Patrick Georgi08c8cf92019-12-02 11:43:20 +0100128 /* Load and cache BAR */
Patrick Georgic9b13592019-11-29 11:47:47 +0100129 if (!cse.sec_bar)
130 cse.sec_bar = get_cse_bar();
131 return write32((void *)(cse.sec_bar + offset), val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800132}
133
134static uint32_t read_cse_csr(void)
135{
136 return read_bar(MMIO_CSE_CSR);
137}
138
139static uint32_t read_host_csr(void)
140{
141 return read_bar(MMIO_HOST_CSR);
142}
143
144static void write_host_csr(uint32_t data)
145{
146 write_bar(MMIO_HOST_CSR, data);
147}
148
149static size_t filled_slots(uint32_t data)
150{
151 uint8_t wp, rp;
152 rp = data >> CSR_RP_START;
153 wp = data >> CSR_WP_START;
154 return (uint8_t) (wp - rp);
155}
156
157static size_t cse_filled_slots(void)
158{
159 return filled_slots(read_cse_csr());
160}
161
162static size_t host_empty_slots(void)
163{
164 uint32_t csr;
165 csr = read_host_csr();
166
167 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
168}
169
170static void clear_int(void)
171{
172 uint32_t csr;
173 csr = read_host_csr();
174 csr |= CSR_IS;
175 write_host_csr(csr);
176}
177
178static uint32_t read_slot(void)
179{
180 return read_bar(MMIO_CSE_CB_RW);
181}
182
183static void write_slot(uint32_t val)
184{
185 write_bar(MMIO_CSE_CB_WW, val);
186}
187
188static int wait_write_slots(size_t cnt)
189{
190 struct stopwatch sw;
191
192 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
193 while (host_empty_slots() < cnt) {
194 udelay(HECI_DELAY);
195 if (stopwatch_expired(&sw)) {
196 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
197 return 0;
198 }
199 }
200 return 1;
201}
202
203static int wait_read_slots(size_t cnt)
204{
205 struct stopwatch sw;
206
207 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
208 while (cse_filled_slots() < cnt) {
209 udelay(HECI_DELAY);
210 if (stopwatch_expired(&sw)) {
211 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
212 return 0;
213 }
214 }
215 return 1;
216}
217
218/* get number of full 4-byte slots */
219static size_t bytes_to_slots(size_t bytes)
220{
221 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
222}
223
224static int cse_ready(void)
225{
226 uint32_t csr;
227 csr = read_cse_csr();
228 return csr & CSR_READY;
229}
230
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530231static bool cse_check_hfs1_com(int mode)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530232{
233 union me_hfsts1 hfs1;
234 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530235 return hfs1.fields.operation_mode == mode;
236}
237
238bool cse_is_hfs1_cws_normal(void)
239{
240 union me_hfsts1 hfs1;
241 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
242 if (hfs1.fields.working_state == ME_HFS1_CWS_NORMAL)
243 return true;
244 return false;
245}
246
247bool cse_is_hfs1_com_normal(void)
248{
249 return cse_check_hfs1_com(ME_HFS1_COM_NORMAL);
250}
251
252bool cse_is_hfs1_com_secover_mei_msg(void)
253{
254 return cse_check_hfs1_com(ME_HFS1_COM_SECOVER_MEI_MSG);
255}
256
257bool cse_is_hfs1_com_soft_temp_disable(void)
258{
259 return cse_check_hfs1_com(ME_HFS1_COM_SOFT_TEMP_DISABLE);
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530260}
261
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530262bool cse_is_hfs3_fw_sku_custom(void)
263{
264 union me_hfsts3 hfs3;
265 hfs3.data = me_read_config32(PCI_ME_HFSTS3);
266 return hfs3.fields.fw_sku == ME_HFS3_FW_SKU_CUSTOM;
267}
268
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530269/* Makes the host ready to communicate with CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530270void cse_set_host_ready(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530271{
272 uint32_t csr;
273 csr = read_host_csr();
274 csr &= ~CSR_RESET;
275 csr |= (CSR_IG | CSR_READY);
276 write_host_csr(csr);
277}
278
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530279/* Polls for ME mode ME_HFS1_COM_SECOVER_MEI_MSG for 15 seconds */
280uint8_t cse_wait_sec_override_mode(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530281{
282 struct stopwatch sw;
283 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530284 while (!cse_is_hfs1_com_secover_mei_msg()) {
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530285 udelay(HECI_DELAY);
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530286 if (stopwatch_expired(&sw)) {
287 printk(BIOS_ERR, "HECI: Timed out waiting for SEC_OVERRIDE mode!\n");
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530288 return 0;
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530289 }
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530290 }
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530291 printk(BIOS_DEBUG, "HECI: CSE took %lu ms to enter security override mode\n",
292 stopwatch_duration_msecs(&sw));
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530293 return 1;
294}
295
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530296/*
297 * Polls for CSE's current operation mode 'Soft Temporary Disable'.
298 * The CSE enters the current operation mode when it boots from RO(BP1).
299 */
300uint8_t cse_wait_com_soft_temp_disable(void)
301{
302 struct stopwatch sw;
303 stopwatch_init_msecs_expire(&sw, CSE_DELAY_BOOT_TO_RO);
304 while (!cse_is_hfs1_com_soft_temp_disable()) {
305 udelay(HECI_DELAY);
306 if (stopwatch_expired(&sw)) {
307 printk(BIOS_ERR, "HECI: Timed out waiting for CSE to boot from RO!\n");
308 return 0;
309 }
310 }
311 printk(BIOS_SPEW, "HECI: CSE took %lu ms to boot from RO\n",
312 stopwatch_duration_msecs(&sw));
313 return 1;
314}
315
Andrey Petrov04a72c42017-03-01 15:51:57 -0800316static int wait_heci_ready(void)
317{
318 struct stopwatch sw;
319
320 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
321 while (!cse_ready()) {
322 udelay(HECI_DELAY);
323 if (stopwatch_expired(&sw))
324 return 0;
325 }
326
327 return 1;
328}
329
330static void host_gen_interrupt(void)
331{
332 uint32_t csr;
333 csr = read_host_csr();
334 csr |= CSR_IG;
335 write_host_csr(csr);
336}
337
338static size_t hdr_get_length(uint32_t hdr)
339{
340 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
341}
342
343static int
344send_one_message(uint32_t hdr, const void *buff)
345{
346 size_t pend_len, pend_slots, remainder, i;
347 uint32_t tmp;
348 const uint32_t *p = buff;
349
350 /* Get space for the header */
351 if (!wait_write_slots(1))
352 return 0;
353
354 /* First, write header */
355 write_slot(hdr);
356
357 pend_len = hdr_get_length(hdr);
358 pend_slots = bytes_to_slots(pend_len);
359
360 if (!wait_write_slots(pend_slots))
361 return 0;
362
363 /* Write the body in whole slots */
364 i = 0;
365 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
366 write_slot(*p++);
367 i += SLOT_SIZE;
368 }
369
370 remainder = pend_len % SLOT_SIZE;
371 /* Pad to 4 bytes not touching caller's buffer */
372 if (remainder) {
373 memcpy(&tmp, p, remainder);
374 write_slot(tmp);
375 }
376
377 host_gen_interrupt();
378
379 /* Make sure nothing bad happened during transmission */
380 if (!cse_ready())
381 return 0;
382
383 return pend_len;
384}
385
386int
387heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
388{
Subrata Banik5c08c732017-11-13 14:54:37 +0530389 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800390 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530391 size_t sent, remaining, cb_size, max_length;
392 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800393
394 if (!msg || !len)
395 return 0;
396
397 clear_int();
398
Subrata Banik5c08c732017-11-13 14:54:37 +0530399 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
400 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800401
Subrata Banik5c08c732017-11-13 14:54:37 +0530402 if (!wait_heci_ready()) {
403 printk(BIOS_ERR, "HECI: not ready\n");
404 continue;
405 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800406
Subrata Banik4a722f52017-11-13 14:56:42 +0530407 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530408 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
409 /*
410 * Reserve one slot for the header. Limit max message
411 * length by 9 bits that are available in the header.
412 */
413 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
414 - SLOT_SIZE;
415 remaining = len;
416
417 /*
418 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100419 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530420 */
421 do {
422 hdr = MIN(max_length, remaining)
423 << MEI_HDR_LENGTH_START;
424 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
425 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
426 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800427 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530428 sent = send_one_message(hdr, p);
429 p += sent;
430 remaining -= sent;
431 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800432
Subrata Banik5c08c732017-11-13 14:54:37 +0530433 if (!remaining)
434 return 1;
435 }
436 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800437}
438
439static size_t
440recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
441{
442 uint32_t reg, *p = buff;
443 size_t recv_slots, recv_len, remainder, i;
444
445 /* first get the header */
446 if (!wait_read_slots(1))
447 return 0;
448
449 *hdr = read_slot();
450 recv_len = hdr_get_length(*hdr);
451
452 if (!recv_len)
453 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
454
455 recv_slots = bytes_to_slots(recv_len);
456
457 i = 0;
458 if (recv_len > maxlen) {
459 printk(BIOS_ERR, "HECI: response is too big\n");
460 return 0;
461 }
462
463 /* wait for the rest of messages to arrive */
464 wait_read_slots(recv_slots);
465
466 /* fetch whole slots first */
467 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
468 *p++ = read_slot();
469 i += SLOT_SIZE;
470 }
471
Subrata Banik5c08c732017-11-13 14:54:37 +0530472 /*
473 * If ME is not ready, something went wrong and
474 * we received junk
475 */
476 if (!cse_ready())
477 return 0;
478
Andrey Petrov04a72c42017-03-01 15:51:57 -0800479 remainder = recv_len % SLOT_SIZE;
480
481 if (remainder) {
482 reg = read_slot();
483 memcpy(p, &reg, remainder);
484 }
485
486 return recv_len;
487}
488
489int heci_receive(void *buff, size_t *maxlen)
490{
Subrata Banik5c08c732017-11-13 14:54:37 +0530491 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800492 size_t left, received;
493 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530494 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800495
496 if (!buff || !maxlen || !*maxlen)
497 return 0;
498
Andrey Petrov04a72c42017-03-01 15:51:57 -0800499 clear_int();
500
Subrata Banik5c08c732017-11-13 14:54:37 +0530501 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
502 p = buff;
503 left = *maxlen;
504
505 if (!wait_heci_ready()) {
506 printk(BIOS_ERR, "HECI: not ready\n");
507 continue;
508 }
509
510 /*
511 * Receive multiple packets until we meet one marked
512 * complete or we run out of space in caller-provided buffer.
513 */
514 do {
515 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800516 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200517 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800518 return 0;
519 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530520 left -= received;
521 p += received;
522 /* If we read out everything ping to send more */
523 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
524 host_gen_interrupt();
525 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
526
527 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
528 *maxlen = p - (uint8_t *) buff;
529 return 1;
530 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800531 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530532 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800533}
534
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530535int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz)
536{
537 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, HECI_MKHI_ADDR)) {
538 printk(BIOS_ERR, "HECI: send Failed\n");
539 return 0;
540 }
541
542 if (rcv_msg != NULL) {
543 if (!heci_receive(rcv_msg, rcv_sz)) {
544 printk(BIOS_ERR, "HECI: receive Failed\n");
545 return 0;
546 }
547 }
548 return 1;
549}
550
Andrey Petrov04a72c42017-03-01 15:51:57 -0800551/*
552 * Attempt to reset the device. This is useful when host and ME are out
553 * of sync during transmission or ME didn't understand the message.
554 */
555int heci_reset(void)
556{
557 uint32_t csr;
558
559 /* Send reset request */
560 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530561 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800562 write_host_csr(csr);
563
564 if (wait_heci_ready()) {
565 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530566 cse_set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800567 return 1;
568 }
569
570 printk(BIOS_CRIT, "HECI: reset failed\n");
571
572 return 0;
573}
574
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530575bool is_cse_enabled(void)
576{
577 const struct device *cse_dev = pcidev_path_on_root(PCH_DEVFN_CSE);
578
579 if (!cse_dev || !cse_dev->enabled) {
580 printk(BIOS_WARNING, "HECI: No CSE device\n");
581 return false;
582 }
583
584 if (pci_read_config16(PCH_DEV_CSE, PCI_VENDOR_ID) == 0xFFFF) {
585 printk(BIOS_WARNING, "HECI: CSE device is hidden\n");
586 return false;
587 }
588
589 return true;
590}
591
592uint32_t me_read_config32(int offset)
593{
594 return pci_read_config32(PCH_DEV_CSE, offset);
595}
596
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530597static bool cse_is_global_reset_allowed(void)
598{
599 /*
600 * Allow sending GLOBAL_RESET command only if:
601 * - CSE's current working state is Normal and current operation mode is Normal.
602 * - (or) CSE's current working state is normal and current operation mode can
603 * be Soft Temp Disable or Security Override Mode if CSE's Firmware SKU is
604 * Custom.
605 */
606 if (!cse_is_hfs1_cws_normal())
607 return false;
608
609 if (cse_is_hfs1_com_normal())
610 return true;
611
612 if (cse_is_hfs3_fw_sku_custom()) {
613 if (cse_is_hfs1_com_soft_temp_disable() || cse_is_hfs1_com_secover_mei_msg())
614 return true;
615 }
616 return false;
617}
618
Sridhar Siricillad415c202019-08-31 14:54:57 +0530619/*
Sridhar Siricillac2a2d2b2020-02-27 17:16:13 +0530620 * Sends GLOBAL_RESET_REQ cmd to CSE.The reset type can be GLOBAL_RESET/CSE_RESET_ONLY.
Sridhar Siricillad415c202019-08-31 14:54:57 +0530621 */
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530622int cse_request_global_reset(enum rst_req_type rst_type)
Sridhar Siricillad415c202019-08-31 14:54:57 +0530623{
624 int status;
625 struct mkhi_hdr reply;
626 struct reset_message {
627 struct mkhi_hdr hdr;
628 uint8_t req_origin;
629 uint8_t reset_type;
630 } __packed;
631 struct reset_message msg = {
632 .hdr = {
633 .group_id = MKHI_GROUP_ID_CBM,
Sridhar Siricillae202e672020-01-07 23:36:40 +0530634 .command = MKHI_CBM_GLOBAL_RESET_REQ,
Sridhar Siricillad415c202019-08-31 14:54:57 +0530635 },
636 .req_origin = GR_ORIGIN_BIOS_POST,
637 .reset_type = rst_type
638 };
639 size_t reply_size;
640
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530641 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530642
Sridhar Siricillac2a2d2b2020-02-27 17:16:13 +0530643 if (!(rst_type == GLOBAL_RESET || rst_type == CSE_RESET_ONLY)) {
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530644 printk(BIOS_ERR, "HECI: Unsupported reset type is requested\n");
645 return 0;
646 }
Sridhar Siricillad415c202019-08-31 14:54:57 +0530647
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530648 if (!cse_is_global_reset_allowed()) {
649 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
650 return 0;
651 }
652
Sridhar Siricillad415c202019-08-31 14:54:57 +0530653 heci_reset();
654
655 reply_size = sizeof(reply);
656 memset(&reply, 0, reply_size);
657
Sridhar Siricillad415c202019-08-31 14:54:57 +0530658 if (rst_type == CSE_RESET_ONLY)
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530659 status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530660 else
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530661 status = heci_send_receive(&msg, sizeof(msg), &reply, &reply_size);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530662
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530663 printk(BIOS_DEBUG, "HECI: Global Reset %s!\n", status ? "success" : "failure");
664 return status;
Sridhar Siricillad415c202019-08-31 14:54:57 +0530665}
666
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530667static bool cse_is_hmrfpo_enable_allowed(void)
668{
669 /*
670 * Allow sending HMRFPO ENABLE command only if:
671 * - CSE's current working state is Normal and current operation mode is Normal
672 * - (or) cse's current working state is normal and current operation mode is
673 * Soft Temp Disable if CSE's Firmware SKU is Custom
674 */
675 if (!cse_is_hfs1_cws_normal())
676 return false;
677
678 if (cse_is_hfs1_com_normal())
679 return true;
680
681 if (cse_is_hfs3_fw_sku_custom() && cse_is_hfs1_com_soft_temp_disable())
682 return true;
683
684 return false;
685}
686
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530687/* Sends HMRFPO Enable command to CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530688int cse_hmrfpo_enable(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530689{
690 struct hmrfpo_enable_msg {
691 struct mkhi_hdr hdr;
692 uint32_t nonce[2];
693 } __packed;
694
695 /* HMRFPO Enable message */
696 struct hmrfpo_enable_msg msg = {
697 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530698 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530699 .command = MKHI_HMRFPO_ENABLE,
700 },
701 .nonce = {0},
702 };
703
704 /* HMRFPO Enable response */
705 struct hmrfpo_enable_resp {
706 struct mkhi_hdr hdr;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530707 /* Base addr for factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530708 uint32_t fct_base;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530709 /* Length of factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530710 uint32_t fct_limit;
711 uint8_t status;
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530712 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530713 } __packed;
714
715 struct hmrfpo_enable_resp resp;
716 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530717
718 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530719
720 if (!cse_is_hmrfpo_enable_allowed()) {
721 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
722 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530723 }
724
725 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
726 &resp, &resp_size))
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530727 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530728
729 if (resp.hdr.result) {
730 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530731 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530732 }
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530733
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530734 if (resp.status) {
735 printk(BIOS_ERR, "HECI: HMRFPO_Enable Failed (resp status: %d)\n", resp.status);
736 return 0;
737 }
738
739 return 1;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530740}
741
742/*
743 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530744 * The status can be DISABLED/LOCKED/ENABLED
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530745 */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530746int cse_hmrfpo_get_status(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530747{
748 struct hmrfpo_get_status_msg {
749 struct mkhi_hdr hdr;
750 } __packed;
751
752 struct hmrfpo_get_status_resp {
753 struct mkhi_hdr hdr;
754 uint8_t status;
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530755 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530756 } __packed;
757
758 struct hmrfpo_get_status_msg msg = {
759 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530760 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530761 .command = MKHI_HMRFPO_GET_STATUS,
762 },
763 };
764 struct hmrfpo_get_status_resp resp;
765 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
766
767 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
768
Sridhar Siricilla206905c2020-02-06 18:48:22 +0530769 if (!cse_is_hfs1_cws_normal()) {
770 printk(BIOS_ERR, "HECI: CSE's current working state is not Normal\n");
771 return -1;
772 }
773
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530774 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
775 &resp, &resp_size)) {
776 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
777 return -1;
778 }
779
780 if (resp.hdr.result) {
781 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
782 resp.hdr.result);
783 return -1;
784 }
785
786 return resp.status;
787}
788
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530789void print_me_fw_version(void *unused)
790{
791 struct version {
792 uint16_t minor;
793 uint16_t major;
794 uint16_t build;
795 uint16_t hotfix;
796 } __packed;
797
798 struct fw_ver_resp {
799 struct mkhi_hdr hdr;
800 struct version code;
801 struct version rec;
802 struct version fitc;
803 } __packed;
804
805 const struct mkhi_hdr fw_ver_msg = {
806 .group_id = MKHI_GROUP_ID_GEN,
807 .command = MKHI_GEN_GET_FW_VERSION,
808 };
809
810 struct fw_ver_resp resp;
811 size_t resp_size = sizeof(resp);
812
813 /* Ignore if UART debugging is disabled */
814 if (!CONFIG(CONSOLE_SERIAL))
815 return;
816
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200817 /* Ignore if CSE is disabled */
818 if (!is_cse_enabled())
819 return;
820
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530821 /*
822 * Ignore if ME Firmware SKU type is custom since
823 * print_boot_partition_info() logs RO(BP1) and RW(BP2) versions.
824 */
825 if (cse_is_hfs3_fw_sku_custom())
826 return;
827
828 /*
829 * Prerequisites:
830 * 1) HFSTS1 Current Working State is Normal
831 * 2) HFSTS1 Current Operation Mode is Normal
832 * 3) It's after DRAM INIT DONE message (taken care of by calling it
833 * during ramstage
834 */
835 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal())
836 goto fail;
837
838 heci_reset();
839
840 if (!heci_send_receive(&fw_ver_msg, sizeof(fw_ver_msg), &resp, &resp_size))
841 goto fail;
842
843 if (resp.hdr.result)
844 goto fail;
845
846 printk(BIOS_DEBUG, "ME: Version: %d.%d.%d.%d\n", resp.code.major,
847 resp.code.minor, resp.code.hotfix, resp.code.build);
848 return;
849
850fail:
851 printk(BIOS_DEBUG, "ME: Version: Unavailable\n");
852}
853
Andrey Petrov04a72c42017-03-01 15:51:57 -0800854#if ENV_RAMSTAGE
855
856static void update_sec_bar(struct device *dev)
857{
Patrick Georgic9b13592019-11-29 11:47:47 +0100858 cse.sec_bar = find_resource(dev, PCI_BASE_ADDRESS_0)->base;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800859}
860
861static void cse_set_resources(struct device *dev)
862{
Subrata Banik2ee54db2017-03-05 12:37:00 +0530863 if (dev->path.pci.devfn == PCH_DEVFN_CSE)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800864 update_sec_bar(dev);
865
866 pci_dev_set_resources(dev);
867}
868
869static struct device_operations cse_ops = {
870 .set_resources = cse_set_resources,
871 .read_resources = pci_dev_read_resources,
872 .enable_resources = pci_dev_enable_resources,
873 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530874 .ops_pci = &pci_dev_ops_pci,
Andrey Petrov04a72c42017-03-01 15:51:57 -0800875};
876
Hannah Williams63142152017-06-12 14:03:18 -0700877static const unsigned short pci_device_ids[] = {
878 PCI_DEVICE_ID_INTEL_APL_CSE0,
879 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -0700880 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Subrata Banikd0586d22017-11-27 13:28:41 +0530881 PCI_DEVICE_ID_INTEL_SKL_CSE0,
Maxim Polyakov571d07d2019-08-22 13:11:32 +0300882 PCI_DEVICE_ID_INTEL_LWB_CSE0,
883 PCI_DEVICE_ID_INTEL_LWB_CSE0_SUPER,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800884 PCI_DEVICE_ID_INTEL_CNP_H_CSE0,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530885 PCI_DEVICE_ID_INTEL_ICL_CSE0,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +0530886 PCI_DEVICE_ID_INTEL_CMP_CSE0,
Gaggery Tsai12a651c2019-12-05 11:23:20 -0800887 PCI_DEVICE_ID_INTEL_CMP_H_CSE0,
Ravi Sarawadi6b5bf402019-10-21 22:25:04 -0700888 PCI_DEVICE_ID_INTEL_TGL_CSE0,
Tan, Lean Sheng26136092020-01-20 19:13:56 -0800889 PCI_DEVICE_ID_INTEL_MCC_CSE0,
890 PCI_DEVICE_ID_INTEL_MCC_CSE1,
891 PCI_DEVICE_ID_INTEL_MCC_CSE2,
892 PCI_DEVICE_ID_INTEL_MCC_CSE3,
Meera Ravindranath3f4af0d2020-02-12 16:01:22 +0530893 PCI_DEVICE_ID_INTEL_JSP_CSE0,
894 PCI_DEVICE_ID_INTEL_JSP_CSE1,
895 PCI_DEVICE_ID_INTEL_JSP_CSE2,
896 PCI_DEVICE_ID_INTEL_JSP_CSE3,
Hannah Williams63142152017-06-12 14:03:18 -0700897 0,
898};
899
Andrey Petrov04a72c42017-03-01 15:51:57 -0800900static const struct pci_driver cse_driver __pci_driver = {
901 .ops = &cse_ops,
902 .vendor = PCI_VENDOR_ID_INTEL,
903 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -0700904 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -0800905};
906
907#endif