blob: c82f3bdc7aaa826615fb601932f62cac90645d26 [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>
Sridhar Siricilla8e465452019-09-23 20:59:38 +053027#include <soc/me.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080028#include <string.h>
29#include <timer.h>
30
Subrata Banik5c08c732017-11-13 14:54:37 +053031#define MAX_HECI_MESSAGE_RETRY_COUNT 5
32
Andrey Petrov04a72c42017-03-01 15:51:57 -080033/* Wait up to 15 sec for HECI to get ready */
34#define HECI_DELAY_READY (15 * 1000)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010035/* Wait up to 100 usec between circular buffer polls */
Andrey Petrov04a72c42017-03-01 15:51:57 -080036#define HECI_DELAY 100
37/* Wait up to 5 sec for CSE to chew something we sent */
38#define HECI_SEND_TIMEOUT (5 * 1000)
39/* Wait up to 5 sec for CSE to blurp a reply */
40#define HECI_READ_TIMEOUT (5 * 1000)
41
42#define SLOT_SIZE sizeof(uint32_t)
43
44#define MMIO_CSE_CB_WW 0x00
45#define MMIO_HOST_CSR 0x04
46#define MMIO_CSE_CB_RW 0x08
47#define MMIO_CSE_CSR 0x0c
48
49#define CSR_IE (1 << 0)
50#define CSR_IS (1 << 1)
51#define CSR_IG (1 << 2)
52#define CSR_READY (1 << 3)
53#define CSR_RESET (1 << 4)
54#define CSR_RP_START 8
55#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
56#define CSR_WP_START 16
57#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
58#define CSR_CBD_START 24
59#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
60
61#define MEI_HDR_IS_COMPLETE (1 << 31)
62#define MEI_HDR_LENGTH_START 16
63#define MEI_HDR_LENGTH_SIZE 9
64#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
65 << MEI_HDR_LENGTH_START)
66#define MEI_HDR_HOST_ADDR_START 8
67#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
68#define MEI_HDR_CSE_ADDR_START 0
69#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
70
Arthur Heymans3d6ccd02019-05-27 17:25:23 +020071static struct cse_device {
Andrey Petrov04a72c42017-03-01 15:51:57 -080072 uintptr_t sec_bar;
Patrick Georgic9b13592019-11-29 11:47:47 +010073} cse;
Andrey Petrov04a72c42017-03-01 15:51:57 -080074
75/*
76 * Initialize the device with provided temporary BAR. If BAR is 0 use a
77 * default. This is intended for pre-mem usage only where BARs haven't been
78 * assigned yet and devices are not enabled.
79 */
80void heci_init(uintptr_t tempbar)
81{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +020082#if defined(__SIMPLE_DEVICE__)
83 pci_devfn_t dev = PCH_DEV_CSE;
84#else
85 struct device *dev = PCH_DEV_CSE;
86#endif
Andrey Petrov04a72c42017-03-01 15:51:57 -080087 u8 pcireg;
88
89 /* Assume it is already initialized, nothing else to do */
Patrick Georgic9b13592019-11-29 11:47:47 +010090 if (cse.sec_bar)
Andrey Petrov04a72c42017-03-01 15:51:57 -080091 return;
92
93 /* Use default pre-ram bar */
94 if (!tempbar)
95 tempbar = HECI1_BASE_ADDRESS;
96
97 /* Assign Resources to HECI1 */
98 /* Clear BIT 1-2 of Command Register */
99 pcireg = pci_read_config8(dev, PCI_COMMAND);
100 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
101 pci_write_config8(dev, PCI_COMMAND, pcireg);
102
103 /* Program Temporary BAR for HECI1 */
104 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
105 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
106
107 /* Enable Bus Master and MMIO Space */
108 pcireg = pci_read_config8(dev, PCI_COMMAND);
109 pcireg |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
110 pci_write_config8(dev, PCI_COMMAND, pcireg);
111
Patrick Georgic9b13592019-11-29 11:47:47 +0100112 cse.sec_bar = tempbar;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800113}
114
Subrata Banik05e06cd2017-11-09 15:04:09 +0530115/* Get HECI BAR 0 from PCI configuration space */
116static uint32_t get_cse_bar(void)
117{
118 uintptr_t bar;
119
120 bar = pci_read_config32(PCH_DEV_CSE, PCI_BASE_ADDRESS_0);
121 assert(bar != 0);
122 /*
123 * Bits 31-12 are the base address as per EDS for SPI,
124 * Don't care about 0-11 bit
125 */
126 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
127}
128
Andrey Petrov04a72c42017-03-01 15:51:57 -0800129static uint32_t read_bar(uint32_t offset)
130{
Patrick Georgi08c8cf92019-12-02 11:43:20 +0100131 /* Load and cache BAR */
Patrick Georgic9b13592019-11-29 11:47:47 +0100132 if (!cse.sec_bar)
133 cse.sec_bar = get_cse_bar();
134 return read32((void *)(cse.sec_bar + offset));
Andrey Petrov04a72c42017-03-01 15:51:57 -0800135}
136
137static void write_bar(uint32_t offset, uint32_t val)
138{
Patrick Georgi08c8cf92019-12-02 11:43:20 +0100139 /* Load and cache BAR */
Patrick Georgic9b13592019-11-29 11:47:47 +0100140 if (!cse.sec_bar)
141 cse.sec_bar = get_cse_bar();
142 return write32((void *)(cse.sec_bar + offset), val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800143}
144
145static uint32_t read_cse_csr(void)
146{
147 return read_bar(MMIO_CSE_CSR);
148}
149
150static uint32_t read_host_csr(void)
151{
152 return read_bar(MMIO_HOST_CSR);
153}
154
155static void write_host_csr(uint32_t data)
156{
157 write_bar(MMIO_HOST_CSR, data);
158}
159
160static size_t filled_slots(uint32_t data)
161{
162 uint8_t wp, rp;
163 rp = data >> CSR_RP_START;
164 wp = data >> CSR_WP_START;
165 return (uint8_t) (wp - rp);
166}
167
168static size_t cse_filled_slots(void)
169{
170 return filled_slots(read_cse_csr());
171}
172
173static size_t host_empty_slots(void)
174{
175 uint32_t csr;
176 csr = read_host_csr();
177
178 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
179}
180
181static void clear_int(void)
182{
183 uint32_t csr;
184 csr = read_host_csr();
185 csr |= CSR_IS;
186 write_host_csr(csr);
187}
188
189static uint32_t read_slot(void)
190{
191 return read_bar(MMIO_CSE_CB_RW);
192}
193
194static void write_slot(uint32_t val)
195{
196 write_bar(MMIO_CSE_CB_WW, val);
197}
198
199static int wait_write_slots(size_t cnt)
200{
201 struct stopwatch sw;
202
203 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT);
204 while (host_empty_slots() < cnt) {
205 udelay(HECI_DELAY);
206 if (stopwatch_expired(&sw)) {
207 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
208 return 0;
209 }
210 }
211 return 1;
212}
213
214static int wait_read_slots(size_t cnt)
215{
216 struct stopwatch sw;
217
218 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT);
219 while (cse_filled_slots() < cnt) {
220 udelay(HECI_DELAY);
221 if (stopwatch_expired(&sw)) {
222 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
223 return 0;
224 }
225 }
226 return 1;
227}
228
229/* get number of full 4-byte slots */
230static size_t bytes_to_slots(size_t bytes)
231{
232 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
233}
234
235static int cse_ready(void)
236{
237 uint32_t csr;
238 csr = read_cse_csr();
239 return csr & CSR_READY;
240}
241
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530242static bool cse_check_hfs1_com(int mode)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530243{
244 union me_hfsts1 hfs1;
245 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530246 return hfs1.fields.operation_mode == mode;
247}
248
249bool cse_is_hfs1_cws_normal(void)
250{
251 union me_hfsts1 hfs1;
252 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
253 if (hfs1.fields.working_state == ME_HFS1_CWS_NORMAL)
254 return true;
255 return false;
256}
257
258bool cse_is_hfs1_com_normal(void)
259{
260 return cse_check_hfs1_com(ME_HFS1_COM_NORMAL);
261}
262
263bool cse_is_hfs1_com_secover_mei_msg(void)
264{
265 return cse_check_hfs1_com(ME_HFS1_COM_SECOVER_MEI_MSG);
266}
267
268bool cse_is_hfs1_com_soft_temp_disable(void)
269{
270 return cse_check_hfs1_com(ME_HFS1_COM_SOFT_TEMP_DISABLE);
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530271}
272
273/* Makes the host ready to communicate with CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530274void cse_set_host_ready(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530275{
276 uint32_t csr;
277 csr = read_host_csr();
278 csr &= ~CSR_RESET;
279 csr |= (CSR_IG | CSR_READY);
280 write_host_csr(csr);
281}
282
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530283/* Polls for ME mode ME_HFS1_COM_SECOVER_MEI_MSG for 15 seconds */
284uint8_t cse_wait_sec_override_mode(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530285{
286 struct stopwatch sw;
287 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530288 while (!cse_is_hfs1_com_secover_mei_msg()) {
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530289 udelay(HECI_DELAY);
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530290 if (stopwatch_expired(&sw)) {
291 printk(BIOS_ERR, "HECI: Timed out waiting for SEC_OVERRIDE mode!\n");
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530292 return 0;
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530293 }
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530294 }
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530295 printk(BIOS_DEBUG, "HECI: CSE took %lu ms to enter security override mode\n",
296 stopwatch_duration_msecs(&sw));
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530297 return 1;
298}
299
Andrey Petrov04a72c42017-03-01 15:51:57 -0800300static int wait_heci_ready(void)
301{
302 struct stopwatch sw;
303
304 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY);
305 while (!cse_ready()) {
306 udelay(HECI_DELAY);
307 if (stopwatch_expired(&sw))
308 return 0;
309 }
310
311 return 1;
312}
313
314static void host_gen_interrupt(void)
315{
316 uint32_t csr;
317 csr = read_host_csr();
318 csr |= CSR_IG;
319 write_host_csr(csr);
320}
321
322static size_t hdr_get_length(uint32_t hdr)
323{
324 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
325}
326
327static int
328send_one_message(uint32_t hdr, const void *buff)
329{
330 size_t pend_len, pend_slots, remainder, i;
331 uint32_t tmp;
332 const uint32_t *p = buff;
333
334 /* Get space for the header */
335 if (!wait_write_slots(1))
336 return 0;
337
338 /* First, write header */
339 write_slot(hdr);
340
341 pend_len = hdr_get_length(hdr);
342 pend_slots = bytes_to_slots(pend_len);
343
344 if (!wait_write_slots(pend_slots))
345 return 0;
346
347 /* Write the body in whole slots */
348 i = 0;
349 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
350 write_slot(*p++);
351 i += SLOT_SIZE;
352 }
353
354 remainder = pend_len % SLOT_SIZE;
355 /* Pad to 4 bytes not touching caller's buffer */
356 if (remainder) {
357 memcpy(&tmp, p, remainder);
358 write_slot(tmp);
359 }
360
361 host_gen_interrupt();
362
363 /* Make sure nothing bad happened during transmission */
364 if (!cse_ready())
365 return 0;
366
367 return pend_len;
368}
369
370int
371heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
372{
Subrata Banik5c08c732017-11-13 14:54:37 +0530373 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800374 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530375 size_t sent, remaining, cb_size, max_length;
376 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800377
378 if (!msg || !len)
379 return 0;
380
381 clear_int();
382
Subrata Banik5c08c732017-11-13 14:54:37 +0530383 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
384 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800385
Subrata Banik5c08c732017-11-13 14:54:37 +0530386 if (!wait_heci_ready()) {
387 printk(BIOS_ERR, "HECI: not ready\n");
388 continue;
389 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800390
Subrata Banik4a722f52017-11-13 14:56:42 +0530391 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530392 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
393 /*
394 * Reserve one slot for the header. Limit max message
395 * length by 9 bits that are available in the header.
396 */
397 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
398 - SLOT_SIZE;
399 remaining = len;
400
401 /*
402 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100403 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530404 */
405 do {
406 hdr = MIN(max_length, remaining)
407 << MEI_HDR_LENGTH_START;
408 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
409 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
410 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800411 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530412 sent = send_one_message(hdr, p);
413 p += sent;
414 remaining -= sent;
415 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800416
Subrata Banik5c08c732017-11-13 14:54:37 +0530417 if (!remaining)
418 return 1;
419 }
420 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800421}
422
423static size_t
424recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
425{
426 uint32_t reg, *p = buff;
427 size_t recv_slots, recv_len, remainder, i;
428
429 /* first get the header */
430 if (!wait_read_slots(1))
431 return 0;
432
433 *hdr = read_slot();
434 recv_len = hdr_get_length(*hdr);
435
436 if (!recv_len)
437 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
438
439 recv_slots = bytes_to_slots(recv_len);
440
441 i = 0;
442 if (recv_len > maxlen) {
443 printk(BIOS_ERR, "HECI: response is too big\n");
444 return 0;
445 }
446
447 /* wait for the rest of messages to arrive */
448 wait_read_slots(recv_slots);
449
450 /* fetch whole slots first */
451 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
452 *p++ = read_slot();
453 i += SLOT_SIZE;
454 }
455
Subrata Banik5c08c732017-11-13 14:54:37 +0530456 /*
457 * If ME is not ready, something went wrong and
458 * we received junk
459 */
460 if (!cse_ready())
461 return 0;
462
Andrey Petrov04a72c42017-03-01 15:51:57 -0800463 remainder = recv_len % SLOT_SIZE;
464
465 if (remainder) {
466 reg = read_slot();
467 memcpy(p, &reg, remainder);
468 }
469
470 return recv_len;
471}
472
473int heci_receive(void *buff, size_t *maxlen)
474{
Subrata Banik5c08c732017-11-13 14:54:37 +0530475 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800476 size_t left, received;
477 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530478 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800479
480 if (!buff || !maxlen || !*maxlen)
481 return 0;
482
Andrey Petrov04a72c42017-03-01 15:51:57 -0800483 clear_int();
484
Subrata Banik5c08c732017-11-13 14:54:37 +0530485 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
486 p = buff;
487 left = *maxlen;
488
489 if (!wait_heci_ready()) {
490 printk(BIOS_ERR, "HECI: not ready\n");
491 continue;
492 }
493
494 /*
495 * Receive multiple packets until we meet one marked
496 * complete or we run out of space in caller-provided buffer.
497 */
498 do {
499 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800500 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200501 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800502 return 0;
503 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530504 left -= received;
505 p += received;
506 /* If we read out everything ping to send more */
507 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
508 host_gen_interrupt();
509 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
510
511 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
512 *maxlen = p - (uint8_t *) buff;
513 return 1;
514 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800515 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530516 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800517}
518
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530519int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz)
520{
521 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, HECI_MKHI_ADDR)) {
522 printk(BIOS_ERR, "HECI: send Failed\n");
523 return 0;
524 }
525
526 if (rcv_msg != NULL) {
527 if (!heci_receive(rcv_msg, rcv_sz)) {
528 printk(BIOS_ERR, "HECI: receive Failed\n");
529 return 0;
530 }
531 }
532 return 1;
533}
534
Andrey Petrov04a72c42017-03-01 15:51:57 -0800535/*
536 * Attempt to reset the device. This is useful when host and ME are out
537 * of sync during transmission or ME didn't understand the message.
538 */
539int heci_reset(void)
540{
541 uint32_t csr;
542
543 /* Send reset request */
544 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530545 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800546 write_host_csr(csr);
547
548 if (wait_heci_ready()) {
549 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530550 cse_set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800551 return 1;
552 }
553
554 printk(BIOS_CRIT, "HECI: reset failed\n");
555
556 return 0;
557}
558
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530559bool is_cse_enabled(void)
560{
561 const struct device *cse_dev = pcidev_path_on_root(PCH_DEVFN_CSE);
562
563 if (!cse_dev || !cse_dev->enabled) {
564 printk(BIOS_WARNING, "HECI: No CSE device\n");
565 return false;
566 }
567
568 if (pci_read_config16(PCH_DEV_CSE, PCI_VENDOR_ID) == 0xFFFF) {
569 printk(BIOS_WARNING, "HECI: CSE device is hidden\n");
570 return false;
571 }
572
573 return true;
574}
575
576uint32_t me_read_config32(int offset)
577{
578 return pci_read_config32(PCH_DEV_CSE, offset);
579}
580
Sridhar Siricillad415c202019-08-31 14:54:57 +0530581/*
582 * Sends GLOBAL_RESET_REQ cmd to CSE.The reset type can be GLOBAL_RESET/
583 * HOST_RESET_ONLY/CSE_RESET_ONLY.
584 */
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530585int cse_request_global_reset(enum rst_req_type rst_type)
Sridhar Siricillad415c202019-08-31 14:54:57 +0530586{
587 int status;
588 struct mkhi_hdr reply;
589 struct reset_message {
590 struct mkhi_hdr hdr;
591 uint8_t req_origin;
592 uint8_t reset_type;
593 } __packed;
594 struct reset_message msg = {
595 .hdr = {
596 .group_id = MKHI_GROUP_ID_CBM,
Sridhar Siricillae202e672020-01-07 23:36:40 +0530597 .command = MKHI_CBM_GLOBAL_RESET_REQ,
Sridhar Siricillad415c202019-08-31 14:54:57 +0530598 },
599 .req_origin = GR_ORIGIN_BIOS_POST,
600 .reset_type = rst_type
601 };
602 size_t reply_size;
603
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530604 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530605 if (!((rst_type == GLOBAL_RESET) ||
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530606 (rst_type == HOST_RESET_ONLY) || (rst_type == CSE_RESET_ONLY))) {
607 printk(BIOS_ERR, "HECI: Unsupported reset type is requested\n");
608 return 0;
609 }
Sridhar Siricillad415c202019-08-31 14:54:57 +0530610
611 heci_reset();
612
613 reply_size = sizeof(reply);
614 memset(&reply, 0, reply_size);
615
Sridhar Siricillad415c202019-08-31 14:54:57 +0530616 if (rst_type == CSE_RESET_ONLY)
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530617 status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530618 else
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530619 status = heci_send_receive(&msg, sizeof(msg), &reply, &reply_size);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530620
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530621 printk(BIOS_DEBUG, "HECI: Global Reset %s!\n", status ? "success" : "failure");
622 return status;
Sridhar Siricillad415c202019-08-31 14:54:57 +0530623}
624
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530625/* Sends HMRFPO Enable command to CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530626int cse_hmrfpo_enable(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530627{
628 struct hmrfpo_enable_msg {
629 struct mkhi_hdr hdr;
630 uint32_t nonce[2];
631 } __packed;
632
633 /* HMRFPO Enable message */
634 struct hmrfpo_enable_msg msg = {
635 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530636 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530637 .command = MKHI_HMRFPO_ENABLE,
638 },
639 .nonce = {0},
640 };
641
642 /* HMRFPO Enable response */
643 struct hmrfpo_enable_resp {
644 struct mkhi_hdr hdr;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530645 /* Base addr for factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530646 uint32_t fct_base;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530647 /* Length of factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530648 uint32_t fct_limit;
649 uint8_t status;
650 uint8_t padding[3];
651 } __packed;
652
653 struct hmrfpo_enable_resp resp;
654 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530655
656 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530657 /*
658 * This command can be run only if:
659 * - Working state is normal and
660 * - Operation mode is normal or temporary disable mode.
661 */
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530662 if (!cse_is_hfs1_cws_normal() ||
663 (!cse_is_hfs1_com_normal() && !cse_is_hfs1_com_soft_temp_disable())) {
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530664 printk(BIOS_ERR, "HECI: ME not in required Mode\n");
665 goto failed;
666 }
667
668 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
669 &resp, &resp_size))
670 goto failed;
671
672 if (resp.hdr.result) {
673 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
674 goto failed;
675 }
676 return 1;
677
678failed:
679 return 0;
680}
681
682/*
683 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530684 * The status can be DISABLED/LOCKED/ENABLED
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530685 */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530686int cse_hmrfpo_get_status(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530687{
688 struct hmrfpo_get_status_msg {
689 struct mkhi_hdr hdr;
690 } __packed;
691
692 struct hmrfpo_get_status_resp {
693 struct mkhi_hdr hdr;
694 uint8_t status;
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530695 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530696 } __packed;
697
698 struct hmrfpo_get_status_msg msg = {
699 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530700 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530701 .command = MKHI_HMRFPO_GET_STATUS,
702 },
703 };
704 struct hmrfpo_get_status_resp resp;
705 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
706
707 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
708
709 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
710 &resp, &resp_size)) {
711 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
712 return -1;
713 }
714
715 if (resp.hdr.result) {
716 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
717 resp.hdr.result);
718 return -1;
719 }
720
721 return resp.status;
722}
723
Andrey Petrov04a72c42017-03-01 15:51:57 -0800724#if ENV_RAMSTAGE
725
726static void update_sec_bar(struct device *dev)
727{
Patrick Georgic9b13592019-11-29 11:47:47 +0100728 cse.sec_bar = find_resource(dev, PCI_BASE_ADDRESS_0)->base;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800729}
730
731static void cse_set_resources(struct device *dev)
732{
Subrata Banik2ee54db2017-03-05 12:37:00 +0530733 if (dev->path.pci.devfn == PCH_DEVFN_CSE)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800734 update_sec_bar(dev);
735
736 pci_dev_set_resources(dev);
737}
738
739static struct device_operations cse_ops = {
740 .set_resources = cse_set_resources,
741 .read_resources = pci_dev_read_resources,
742 .enable_resources = pci_dev_enable_resources,
743 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530744 .ops_pci = &pci_dev_ops_pci,
Andrey Petrov04a72c42017-03-01 15:51:57 -0800745};
746
Hannah Williams63142152017-06-12 14:03:18 -0700747static const unsigned short pci_device_ids[] = {
748 PCI_DEVICE_ID_INTEL_APL_CSE0,
749 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -0700750 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Subrata Banikd0586d22017-11-27 13:28:41 +0530751 PCI_DEVICE_ID_INTEL_SKL_CSE0,
Maxim Polyakov571d07d2019-08-22 13:11:32 +0300752 PCI_DEVICE_ID_INTEL_LWB_CSE0,
753 PCI_DEVICE_ID_INTEL_LWB_CSE0_SUPER,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800754 PCI_DEVICE_ID_INTEL_CNP_H_CSE0,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530755 PCI_DEVICE_ID_INTEL_ICL_CSE0,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +0530756 PCI_DEVICE_ID_INTEL_CMP_CSE0,
Gaggery Tsai12a651c2019-12-05 11:23:20 -0800757 PCI_DEVICE_ID_INTEL_CMP_H_CSE0,
Ravi Sarawadi6b5bf402019-10-21 22:25:04 -0700758 PCI_DEVICE_ID_INTEL_TGL_CSE0,
rkanabar263f1292019-11-28 10:41:45 +0530759 PCI_DEVICE_ID_INTEL_JSP_PRE_PROD_CSE0,
Tan, Lean Sheng26136092020-01-20 19:13:56 -0800760 PCI_DEVICE_ID_INTEL_MCC_CSE0,
761 PCI_DEVICE_ID_INTEL_MCC_CSE1,
762 PCI_DEVICE_ID_INTEL_MCC_CSE2,
763 PCI_DEVICE_ID_INTEL_MCC_CSE3,
Hannah Williams63142152017-06-12 14:03:18 -0700764 0,
765};
766
Andrey Petrov04a72c42017-03-01 15:51:57 -0800767static const struct pci_driver cse_driver __pci_driver = {
768 .ops = &cse_ops,
769 .vendor = PCI_VENDOR_ID_INTEL,
770 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -0700771 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -0800772};
773
774#endif