blob: debbf1fbf47a4853218b48b1457c22ace5030aae [file] [log] [blame]
Andrey Petrov04a72c42017-03-01 15:51:57 -08001/*
2 * This file is part of the coreboot project.
3 *
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +08004 * Copyright 2017-2018 Intel Inc.
Andrey Petrov04a72c42017-03-01 15:51:57 -08005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
Subrata Banik05e06cd2017-11-09 15:04:09 +053016#include <assert.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080017#include <commonlib/helpers.h>
18#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020019#include <device/mmio.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080020#include <delay.h>
21#include <device/pci.h>
22#include <device/pci_ids.h>
23#include <device/pci_ops.h>
24#include <intelblocks/cse.h>
Subrata Banik05e06cd2017-11-09 15:04:09 +053025#include <soc/iomap.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080026#include <soc/pci_devs.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080027#include <string.h>
28#include <timer.h>
29
Subrata Banik5c08c732017-11-13 14:54:37 +053030#define MAX_HECI_MESSAGE_RETRY_COUNT 5
31
Andrey Petrov04a72c42017-03-01 15:51:57 -080032/* Wait up to 15 sec for HECI to get ready */
33#define HECI_DELAY_READY (15 * 1000)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010034/* Wait up to 100 usec between circular buffer polls */
Andrey Petrov04a72c42017-03-01 15:51:57 -080035#define HECI_DELAY 100
36/* Wait up to 5 sec for CSE to chew something we sent */
37#define HECI_SEND_TIMEOUT (5 * 1000)
38/* Wait up to 5 sec for CSE to blurp a reply */
39#define HECI_READ_TIMEOUT (5 * 1000)
40
41#define SLOT_SIZE sizeof(uint32_t)
42
43#define MMIO_CSE_CB_WW 0x00
44#define MMIO_HOST_CSR 0x04
45#define MMIO_CSE_CB_RW 0x08
46#define MMIO_CSE_CSR 0x0c
47
48#define CSR_IE (1 << 0)
49#define CSR_IS (1 << 1)
50#define CSR_IG (1 << 2)
51#define CSR_READY (1 << 3)
52#define CSR_RESET (1 << 4)
53#define CSR_RP_START 8
54#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
55#define CSR_WP_START 16
56#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
57#define CSR_CBD_START 24
58#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
59
60#define MEI_HDR_IS_COMPLETE (1 << 31)
61#define MEI_HDR_LENGTH_START 16
62#define MEI_HDR_LENGTH_SIZE 9
63#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
64 << MEI_HDR_LENGTH_START)
65#define MEI_HDR_HOST_ADDR_START 8
66#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
67#define MEI_HDR_CSE_ADDR_START 0
68#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
69
Sridhar Siricillab9d075b2019-08-31 11:38:33 +053070#define HECI_OP_MODE_SEC_OVERRIDE 5
Andrey Petrov04a72c42017-03-01 15:51:57 -080071
Sridhar Siricillad415c202019-08-31 14:54:57 +053072/* Global Reset Command ID */
73#define MKHI_GLOBAL_RESET_REQ 0xb
74#define MKHI_GROUP_ID_CBM 0
75
76/* RST Origin */
77#define GR_ORIGIN_BIOS_POST 2
78
Sridhar Siricillae30a0e62019-08-31 16:12:21 +053079#define MKHI_HMRFPO_GROUP_ID 5
80
81/* HMRFPO Command Ids */
82#define MKHI_HMRFPO_ENABLE 1
83#define MKHI_HMRFPO_GET_STATUS 3
84
85#define ME_HFS_CWS_NORMAL 5
86#define ME_HFS_MODE_NORMAL 0
87#define ME_HFS_TEMP_DISABLE 3
88
Arthur Heymans3d6ccd02019-05-27 17:25:23 +020089static struct cse_device {
Andrey Petrov04a72c42017-03-01 15:51:57 -080090 uintptr_t sec_bar;
Arthur Heymansa5eed802019-05-25 10:28:11 +020091} g_cse;
Andrey Petrov04a72c42017-03-01 15:51:57 -080092
Sridhar Siricillad415c202019-08-31 14:54:57 +053093/* HECI Message Header */
94struct mkhi_hdr {
95 uint8_t group_id;
96 uint8_t command:7;
97 uint8_t is_resp:1;
98 uint8_t rsvd;
99 uint8_t result;
100} __packed;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800101/*
102 * Initialize the device with provided temporary BAR. If BAR is 0 use a
103 * default. This is intended for pre-mem usage only where BARs haven't been
104 * assigned yet and devices are not enabled.
105 */
106void heci_init(uintptr_t tempbar)
107{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +0200108#if defined(__SIMPLE_DEVICE__)
109 pci_devfn_t dev = PCH_DEV_CSE;
110#else
111 struct device *dev = PCH_DEV_CSE;
112#endif
Andrey Petrov04a72c42017-03-01 15:51:57 -0800113 u8 pcireg;
114
115 /* Assume it is already initialized, nothing else to do */
Arthur Heymansa5eed802019-05-25 10:28:11 +0200116 if (g_cse.sec_bar)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800117 return;
118
119 /* Use default pre-ram bar */
120 if (!tempbar)
121 tempbar = HECI1_BASE_ADDRESS;
122
123 /* Assign Resources to HECI1 */
124 /* Clear BIT 1-2 of Command Register */
125 pcireg = pci_read_config8(dev, PCI_COMMAND);
126 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
127 pci_write_config8(dev, PCI_COMMAND, pcireg);
128
129 /* Program Temporary BAR for HECI1 */
130 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
131 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
132
133 /* Enable Bus Master and MMIO Space */
134 pcireg = pci_read_config8(dev, PCI_COMMAND);
135 pcireg |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
136 pci_write_config8(dev, PCI_COMMAND, pcireg);
137
Arthur Heymansa5eed802019-05-25 10:28:11 +0200138 g_cse.sec_bar = tempbar;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800139}
140
Subrata Banik05e06cd2017-11-09 15:04:09 +0530141/* Get HECI BAR 0 from PCI configuration space */
142static uint32_t get_cse_bar(void)
143{
144 uintptr_t bar;
145
146 bar = pci_read_config32(PCH_DEV_CSE, PCI_BASE_ADDRESS_0);
147 assert(bar != 0);
148 /*
149 * Bits 31-12 are the base address as per EDS for SPI,
150 * Don't care about 0-11 bit
151 */
152 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
153}
154
Andrey Petrov04a72c42017-03-01 15:51:57 -0800155static uint32_t read_bar(uint32_t offset)
156{
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100157 /* Reach PCI config space to get BAR in case CAR global not available */
Arthur Heymansa5eed802019-05-25 10:28:11 +0200158 if (!g_cse.sec_bar)
159 g_cse.sec_bar = get_cse_bar();
160 return read32((void *)(g_cse.sec_bar + offset));
Andrey Petrov04a72c42017-03-01 15:51:57 -0800161}
162
163static void write_bar(uint32_t offset, uint32_t val)
164{
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100165 /* Reach PCI config space to get BAR in case CAR global not available */
Arthur Heymansa5eed802019-05-25 10:28:11 +0200166 if (!g_cse.sec_bar)
167 g_cse.sec_bar = get_cse_bar();
168 return write32((void *)(g_cse.sec_bar + offset), val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800169}
170
171static uint32_t read_cse_csr(void)
172{
173 return read_bar(MMIO_CSE_CSR);
174}
175
176static uint32_t read_host_csr(void)
177{
178 return read_bar(MMIO_HOST_CSR);
179}
180
181static void write_host_csr(uint32_t data)
182{
183 write_bar(MMIO_HOST_CSR, data);
184}
185
186static size_t filled_slots(uint32_t data)
187{
188 uint8_t wp, rp;
189 rp = data >> CSR_RP_START;
190 wp = data >> CSR_WP_START;
191 return (uint8_t) (wp - rp);
192}
193
194static size_t cse_filled_slots(void)
195{
196 return filled_slots(read_cse_csr());
197}
198
199static size_t host_empty_slots(void)
200{
201 uint32_t csr;
202 csr = read_host_csr();
203
204 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
205}
206
207static void clear_int(void)
208{
209 uint32_t csr;
210 csr = read_host_csr();
211 csr |= CSR_IS;
212 write_host_csr(csr);
213}
214
215static uint32_t read_slot(void)
216{
217 return read_bar(MMIO_CSE_CB_RW);
218}
219
220static void write_slot(uint32_t val)
221{
222 write_bar(MMIO_CSE_CB_WW, val);
223}
224
225static int wait_write_slots(size_t cnt)
226{
227 struct stopwatch sw;
228
229 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
230 while (host_empty_slots() < cnt) {
231 udelay(HECI_DELAY);
232 if (stopwatch_expired(&sw)) {
233 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
234 return 0;
235 }
236 }
237 return 1;
238}
239
240static int wait_read_slots(size_t cnt)
241{
242 struct stopwatch sw;
243
244 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
245 while (cse_filled_slots() < cnt) {
246 udelay(HECI_DELAY);
247 if (stopwatch_expired(&sw)) {
248 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
249 return 0;
250 }
251 }
252 return 1;
253}
254
255/* get number of full 4-byte slots */
256static size_t bytes_to_slots(size_t bytes)
257{
258 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
259}
260
261static int cse_ready(void)
262{
263 uint32_t csr;
264 csr = read_cse_csr();
265 return csr & CSR_READY;
266}
267
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530268/*
269 * Checks if CSE is in SEC_OVERRIDE operation mode. This is the mode where
270 * CSE will allow reflashing of CSE region.
271 */
272static uint8_t check_cse_sec_override_mode(void)
273{
274 union me_hfsts1 hfs1;
275 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
276 if (hfs1.fields.operation_mode == HECI_OP_MODE_SEC_OVERRIDE)
277 return 1;
278 return 0;
279}
280
281/* Makes the host ready to communicate with CSE */
282void set_host_ready(void)
283{
284 uint32_t csr;
285 csr = read_host_csr();
286 csr &= ~CSR_RESET;
287 csr |= (CSR_IG | CSR_READY);
288 write_host_csr(csr);
289}
290
291/* Polls for ME state 'HECI_OP_MODE_SEC_OVERRIDE' for 15 seconds */
292uint8_t wait_cse_sec_override_mode(void)
293{
294 struct stopwatch sw;
295 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
296 while (!check_cse_sec_override_mode()) {
297 udelay(HECI_DELAY);
298 if (stopwatch_expired(&sw))
299 return 0;
300 }
301
302 return 1;
303}
304
Andrey Petrov04a72c42017-03-01 15:51:57 -0800305static int wait_heci_ready(void)
306{
307 struct stopwatch sw;
308
309 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
310 while (!cse_ready()) {
311 udelay(HECI_DELAY);
312 if (stopwatch_expired(&sw))
313 return 0;
314 }
315
316 return 1;
317}
318
319static void host_gen_interrupt(void)
320{
321 uint32_t csr;
322 csr = read_host_csr();
323 csr |= CSR_IG;
324 write_host_csr(csr);
325}
326
327static size_t hdr_get_length(uint32_t hdr)
328{
329 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
330}
331
332static int
333send_one_message(uint32_t hdr, const void *buff)
334{
335 size_t pend_len, pend_slots, remainder, i;
336 uint32_t tmp;
337 const uint32_t *p = buff;
338
339 /* Get space for the header */
340 if (!wait_write_slots(1))
341 return 0;
342
343 /* First, write header */
344 write_slot(hdr);
345
346 pend_len = hdr_get_length(hdr);
347 pend_slots = bytes_to_slots(pend_len);
348
349 if (!wait_write_slots(pend_slots))
350 return 0;
351
352 /* Write the body in whole slots */
353 i = 0;
354 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
355 write_slot(*p++);
356 i += SLOT_SIZE;
357 }
358
359 remainder = pend_len % SLOT_SIZE;
360 /* Pad to 4 bytes not touching caller's buffer */
361 if (remainder) {
362 memcpy(&tmp, p, remainder);
363 write_slot(tmp);
364 }
365
366 host_gen_interrupt();
367
368 /* Make sure nothing bad happened during transmission */
369 if (!cse_ready())
370 return 0;
371
372 return pend_len;
373}
374
375int
376heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
377{
Subrata Banik5c08c732017-11-13 14:54:37 +0530378 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800379 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530380 size_t sent, remaining, cb_size, max_length;
381 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800382
383 if (!msg || !len)
384 return 0;
385
386 clear_int();
387
Subrata Banik5c08c732017-11-13 14:54:37 +0530388 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
389 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800390
Subrata Banik5c08c732017-11-13 14:54:37 +0530391 if (!wait_heci_ready()) {
392 printk(BIOS_ERR, "HECI: not ready\n");
393 continue;
394 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800395
Subrata Banik4a722f52017-11-13 14:56:42 +0530396 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530397 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
398 /*
399 * Reserve one slot for the header. Limit max message
400 * length by 9 bits that are available in the header.
401 */
402 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
403 - SLOT_SIZE;
404 remaining = len;
405
406 /*
407 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100408 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530409 */
410 do {
411 hdr = MIN(max_length, remaining)
412 << MEI_HDR_LENGTH_START;
413 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
414 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
415 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800416 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530417 sent = send_one_message(hdr, p);
418 p += sent;
419 remaining -= sent;
420 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800421
Subrata Banik5c08c732017-11-13 14:54:37 +0530422 if (!remaining)
423 return 1;
424 }
425 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800426}
427
428static size_t
429recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
430{
431 uint32_t reg, *p = buff;
432 size_t recv_slots, recv_len, remainder, i;
433
434 /* first get the header */
435 if (!wait_read_slots(1))
436 return 0;
437
438 *hdr = read_slot();
439 recv_len = hdr_get_length(*hdr);
440
441 if (!recv_len)
442 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
443
444 recv_slots = bytes_to_slots(recv_len);
445
446 i = 0;
447 if (recv_len > maxlen) {
448 printk(BIOS_ERR, "HECI: response is too big\n");
449 return 0;
450 }
451
452 /* wait for the rest of messages to arrive */
453 wait_read_slots(recv_slots);
454
455 /* fetch whole slots first */
456 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
457 *p++ = read_slot();
458 i += SLOT_SIZE;
459 }
460
Subrata Banik5c08c732017-11-13 14:54:37 +0530461 /*
462 * If ME is not ready, something went wrong and
463 * we received junk
464 */
465 if (!cse_ready())
466 return 0;
467
Andrey Petrov04a72c42017-03-01 15:51:57 -0800468 remainder = recv_len % SLOT_SIZE;
469
470 if (remainder) {
471 reg = read_slot();
472 memcpy(p, &reg, remainder);
473 }
474
475 return recv_len;
476}
477
478int heci_receive(void *buff, size_t *maxlen)
479{
Subrata Banik5c08c732017-11-13 14:54:37 +0530480 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800481 size_t left, received;
482 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530483 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800484
485 if (!buff || !maxlen || !*maxlen)
486 return 0;
487
Andrey Petrov04a72c42017-03-01 15:51:57 -0800488 clear_int();
489
Subrata Banik5c08c732017-11-13 14:54:37 +0530490 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
491 p = buff;
492 left = *maxlen;
493
494 if (!wait_heci_ready()) {
495 printk(BIOS_ERR, "HECI: not ready\n");
496 continue;
497 }
498
499 /*
500 * Receive multiple packets until we meet one marked
501 * complete or we run out of space in caller-provided buffer.
502 */
503 do {
504 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800505 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200506 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800507 return 0;
508 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530509 left -= received;
510 p += received;
511 /* If we read out everything ping to send more */
512 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
513 host_gen_interrupt();
514 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
515
516 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
517 *maxlen = p - (uint8_t *) buff;
518 return 1;
519 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800520 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530521 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800522}
523
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530524int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz)
525{
526 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, HECI_MKHI_ADDR)) {
527 printk(BIOS_ERR, "HECI: send Failed\n");
528 return 0;
529 }
530
531 if (rcv_msg != NULL) {
532 if (!heci_receive(rcv_msg, rcv_sz)) {
533 printk(BIOS_ERR, "HECI: receive Failed\n");
534 return 0;
535 }
536 }
537 return 1;
538}
539
Andrey Petrov04a72c42017-03-01 15:51:57 -0800540/*
541 * Attempt to reset the device. This is useful when host and ME are out
542 * of sync during transmission or ME didn't understand the message.
543 */
544int heci_reset(void)
545{
546 uint32_t csr;
547
548 /* Send reset request */
549 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530550 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800551 write_host_csr(csr);
552
553 if (wait_heci_ready()) {
554 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530555 set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800556 return 1;
557 }
558
559 printk(BIOS_CRIT, "HECI: reset failed\n");
560
561 return 0;
562}
563
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530564bool is_cse_enabled(void)
565{
566 const struct device *cse_dev = pcidev_path_on_root(PCH_DEVFN_CSE);
567
568 if (!cse_dev || !cse_dev->enabled) {
569 printk(BIOS_WARNING, "HECI: No CSE device\n");
570 return false;
571 }
572
573 if (pci_read_config16(PCH_DEV_CSE, PCI_VENDOR_ID) == 0xFFFF) {
574 printk(BIOS_WARNING, "HECI: CSE device is hidden\n");
575 return false;
576 }
577
578 return true;
579}
580
581uint32_t me_read_config32(int offset)
582{
583 return pci_read_config32(PCH_DEV_CSE, offset);
584}
585
Sridhar Siricillad415c202019-08-31 14:54:57 +0530586/*
587 * Sends GLOBAL_RESET_REQ cmd to CSE.The reset type can be GLOBAL_RESET/
588 * HOST_RESET_ONLY/CSE_RESET_ONLY.
589 */
590int send_heci_reset_req_message(uint8_t rst_type)
591{
592 int status;
593 struct mkhi_hdr reply;
594 struct reset_message {
595 struct mkhi_hdr hdr;
596 uint8_t req_origin;
597 uint8_t reset_type;
598 } __packed;
599 struct reset_message msg = {
600 .hdr = {
601 .group_id = MKHI_GROUP_ID_CBM,
602 .command = MKHI_GLOBAL_RESET_REQ,
603 },
604 .req_origin = GR_ORIGIN_BIOS_POST,
605 .reset_type = rst_type
606 };
607 size_t reply_size;
608
609 if (!((rst_type == GLOBAL_RESET) ||
610 (rst_type == HOST_RESET_ONLY) || (rst_type == CSE_RESET_ONLY)))
611 return -1;
612
613 heci_reset();
614
615 reply_size = sizeof(reply);
616 memset(&reply, 0, reply_size);
617
618 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
619 if (rst_type == CSE_RESET_ONLY)
620 status = heci_send_receive(&msg, sizeof(msg), NULL, 0);
621 else
622 status = heci_send_receive(&msg, sizeof(msg), &reply,
623 &reply_size);
624
625 if (status != 1)
626 return -1;
627
628 printk(BIOS_DEBUG, "HECI: Global Reset success!\n");
629 return 0;
630}
631
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530632/* Sends HMRFPO Enable command to CSE */
633int send_hmrfpo_enable_msg(void)
634{
635 struct hmrfpo_enable_msg {
636 struct mkhi_hdr hdr;
637 uint32_t nonce[2];
638 } __packed;
639
640 /* HMRFPO Enable message */
641 struct hmrfpo_enable_msg msg = {
642 .hdr = {
643 .group_id = MKHI_HMRFPO_GROUP_ID,
644 .command = MKHI_HMRFPO_ENABLE,
645 },
646 .nonce = {0},
647 };
648
649 /* HMRFPO Enable response */
650 struct hmrfpo_enable_resp {
651 struct mkhi_hdr hdr;
652 uint32_t fct_base;
653 uint32_t fct_limit;
654 uint8_t status;
655 uint8_t padding[3];
656 } __packed;
657
658 struct hmrfpo_enable_resp resp;
659 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
660 union me_hfsts1 hfs1;
661
662 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
663 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
664 /*
665 * This command can be run only if:
666 * - Working state is normal and
667 * - Operation mode is normal or temporary disable mode.
668 */
669 if (hfs1.fields.working_state != ME_HFS_CWS_NORMAL ||
670 (hfs1.fields.operation_mode != ME_HFS_MODE_NORMAL &&
671 hfs1.fields.operation_mode != ME_HFS_TEMP_DISABLE)) {
672 printk(BIOS_ERR, "HECI: ME not in required Mode\n");
673 goto failed;
674 }
675
676 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
677 &resp, &resp_size))
678 goto failed;
679
680 if (resp.hdr.result) {
681 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
682 goto failed;
683 }
684 return 1;
685
686failed:
687 return 0;
688}
689
690/*
691 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
692 * The status can be DISABLES/LOCKED/ENABLED
693 */
694int send_hmrfpo_get_status_msg(void)
695{
696 struct hmrfpo_get_status_msg {
697 struct mkhi_hdr hdr;
698 } __packed;
699
700 struct hmrfpo_get_status_resp {
701 struct mkhi_hdr hdr;
702 uint8_t status;
703 uint8_t padding[3];
704 } __packed;
705
706 struct hmrfpo_get_status_msg msg = {
707 .hdr = {
708 .group_id = MKHI_HMRFPO_GROUP_ID,
709 .command = MKHI_HMRFPO_GET_STATUS,
710 },
711 };
712 struct hmrfpo_get_status_resp resp;
713 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
714
715 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
716
717 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
718 &resp, &resp_size)) {
719 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
720 return -1;
721 }
722
723 if (resp.hdr.result) {
724 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
725 resp.hdr.result);
726 return -1;
727 }
728
729 return resp.status;
730}
731
Andrey Petrov04a72c42017-03-01 15:51:57 -0800732#if ENV_RAMSTAGE
733
734static void update_sec_bar(struct device *dev)
735{
736 g_cse.sec_bar = find_resource(dev, PCI_BASE_ADDRESS_0)->base;
737}
738
739static void cse_set_resources(struct device *dev)
740{
Subrata Banik2ee54db2017-03-05 12:37:00 +0530741 if (dev->path.pci.devfn == PCH_DEVFN_CSE)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800742 update_sec_bar(dev);
743
744 pci_dev_set_resources(dev);
745}
746
747static struct device_operations cse_ops = {
748 .set_resources = cse_set_resources,
749 .read_resources = pci_dev_read_resources,
750 .enable_resources = pci_dev_enable_resources,
751 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530752 .ops_pci = &pci_dev_ops_pci,
Andrey Petrov04a72c42017-03-01 15:51:57 -0800753};
754
Hannah Williams63142152017-06-12 14:03:18 -0700755static const unsigned short pci_device_ids[] = {
756 PCI_DEVICE_ID_INTEL_APL_CSE0,
757 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -0700758 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Subrata Banikd0586d22017-11-27 13:28:41 +0530759 PCI_DEVICE_ID_INTEL_SKL_CSE0,
Maxim Polyakov571d07d2019-08-22 13:11:32 +0300760 PCI_DEVICE_ID_INTEL_LWB_CSE0,
761 PCI_DEVICE_ID_INTEL_LWB_CSE0_SUPER,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800762 PCI_DEVICE_ID_INTEL_CNP_H_CSE0,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530763 PCI_DEVICE_ID_INTEL_ICL_CSE0,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +0530764 PCI_DEVICE_ID_INTEL_CMP_CSE0,
Hannah Williams63142152017-06-12 14:03:18 -0700765 0,
766};
767
Andrey Petrov04a72c42017-03-01 15:51:57 -0800768static const struct pci_driver cse_driver __pci_driver = {
769 .ops = &cse_ops,
770 .vendor = PCI_VENDOR_ID_INTEL,
771 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -0700772 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -0800773};
774
775#endif