blob: a80ab48b48c42e3491d48eff68781b989a3f7d86 [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 Banikc6e25522021-09-30 18:14:09 +05303#define __SIMPLE_DEVICE__
4
Subrata Banik05e06cd2017-11-09 15:04:09 +05305#include <assert.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08006#include <commonlib/helpers.h>
7#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02008#include <device/mmio.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08009#include <delay.h>
10#include <device/pci.h>
11#include <device/pci_ids.h>
12#include <device/pci_ops.h>
13#include <intelblocks/cse.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010014#include <limits.h>
15#include <option.h>
Tim Wawrzynczak09635f42021-06-18 10:08:47 -060016#include <security/vboot/misc.h>
17#include <security/vboot/vboot_common.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010018#include <soc/intel/common/reset.h>
Subrata Banik05e06cd2017-11-09 15:04:09 +053019#include <soc/iomap.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080020#include <soc/pci_devs.h>
Sridhar Siricilla8e465452019-09-23 20:59:38 +053021#include <soc/me.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080022#include <string.h>
23#include <timer.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010024#include <types.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080025
Subrata Banik5c08c732017-11-13 14:54:37 +053026#define MAX_HECI_MESSAGE_RETRY_COUNT 5
27
Andrey Petrov04a72c42017-03-01 15:51:57 -080028/* Wait up to 15 sec for HECI to get ready */
Subrata Banik03aef282021-09-28 18:10:24 +053029#define HECI_DELAY_READY_MS (15 * 1000)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010030/* Wait up to 100 usec between circular buffer polls */
Subrata Banik03aef282021-09-28 18:10:24 +053031#define HECI_DELAY_US 100
Andrey Petrov04a72c42017-03-01 15:51:57 -080032/* Wait up to 5 sec for CSE to chew something we sent */
Subrata Banik03aef282021-09-28 18:10:24 +053033#define HECI_SEND_TIMEOUT_MS (5 * 1000)
Andrey Petrov04a72c42017-03-01 15:51:57 -080034/* Wait up to 5 sec for CSE to blurp a reply */
Subrata Banik03aef282021-09-28 18:10:24 +053035#define HECI_READ_TIMEOUT_MS (5 * 1000)
Subrata Banika219edb2021-09-25 15:02:37 +053036/* Wait up to 1 ms for CSE CIP */
Subrata Banik03aef282021-09-28 18:10:24 +053037#define HECI_CIP_TIMEOUT_US 1000
Subrata Banikf5765812021-09-30 13:37:10 +053038/* Wait up to 5 seconds for CSE to boot from RO(BP1) */
39#define CSE_DELAY_BOOT_TO_RO_MS (5 * 1000)
Andrey Petrov04a72c42017-03-01 15:51:57 -080040
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
Subrata Banika219edb2021-09-25 15:02:37 +053047#define MMIO_CSE_DEVIDLE 0x800
48#define CSE_DEV_IDLE (1 << 2)
49#define CSE_DEV_CIP (1 << 0)
Andrey Petrov04a72c42017-03-01 15:51:57 -080050
51#define CSR_IE (1 << 0)
52#define CSR_IS (1 << 1)
53#define CSR_IG (1 << 2)
54#define CSR_READY (1 << 3)
55#define CSR_RESET (1 << 4)
56#define CSR_RP_START 8
57#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
58#define CSR_WP_START 16
59#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
60#define CSR_CBD_START 24
61#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
62
63#define MEI_HDR_IS_COMPLETE (1 << 31)
64#define MEI_HDR_LENGTH_START 16
65#define MEI_HDR_LENGTH_SIZE 9
66#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
67 << MEI_HDR_LENGTH_START)
68#define MEI_HDR_HOST_ADDR_START 8
69#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
70#define MEI_HDR_CSE_ADDR_START 0
71#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
72
Subrata Banik38abbda2021-09-30 13:15:50 +053073/* Get HECI BAR 0 from PCI configuration space */
Subrata Banikc6e25522021-09-30 18:14:09 +053074static uintptr_t get_cse_bar(pci_devfn_t dev)
Subrata Banik38abbda2021-09-30 13:15:50 +053075{
76 uintptr_t bar;
77
Subrata Banikc6e25522021-09-30 18:14:09 +053078 bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
Subrata Banik38abbda2021-09-30 13:15:50 +053079 assert(bar != 0);
80 /*
81 * Bits 31-12 are the base address as per EDS for SPI,
82 * Don't care about 0-11 bit
83 */
84 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
85}
Andrey Petrov04a72c42017-03-01 15:51:57 -080086
87/*
88 * Initialize the device with provided temporary BAR. If BAR is 0 use a
89 * default. This is intended for pre-mem usage only where BARs haven't been
90 * assigned yet and devices are not enabled.
91 */
92void heci_init(uintptr_t tempbar)
93{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +020094 pci_devfn_t dev = PCH_DEV_CSE;
Subrata Banikc6e25522021-09-30 18:14:09 +053095
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020096 u16 pcireg;
Andrey Petrov04a72c42017-03-01 15:51:57 -080097
98 /* Assume it is already initialized, nothing else to do */
Subrata Banikc6e25522021-09-30 18:14:09 +053099 if (get_cse_bar(dev))
Andrey Petrov04a72c42017-03-01 15:51:57 -0800100 return;
101
102 /* Use default pre-ram bar */
103 if (!tempbar)
104 tempbar = HECI1_BASE_ADDRESS;
105
106 /* Assign Resources to HECI1 */
107 /* Clear BIT 1-2 of Command Register */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200108 pcireg = pci_read_config16(dev, PCI_COMMAND);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800109 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200110 pci_write_config16(dev, PCI_COMMAND, pcireg);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800111
112 /* Program Temporary BAR for HECI1 */
113 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
114 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
115
116 /* Enable Bus Master and MMIO Space */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200117 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Sridhar Siricillacb2fd202021-06-09 19:27:06 +0530118
119 /* Trigger HECI Reset and make Host ready for communication with CSE */
120 heci_reset();
Subrata Banik05e06cd2017-11-09 15:04:09 +0530121}
122
Subrata Banikc6e25522021-09-30 18:14:09 +0530123static uint32_t read_bar(pci_devfn_t dev, uint32_t offset)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800124{
Subrata Banikc6e25522021-09-30 18:14:09 +0530125 return read32p(get_cse_bar(dev) + offset);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800126}
127
Subrata Banikc6e25522021-09-30 18:14:09 +0530128static void write_bar(pci_devfn_t dev, uint32_t offset, uint32_t val)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800129{
Subrata Banikc6e25522021-09-30 18:14:09 +0530130 return write32p(get_cse_bar(dev) + offset, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800131}
132
133static uint32_t read_cse_csr(void)
134{
Subrata Banikc6e25522021-09-30 18:14:09 +0530135 return read_bar(PCH_DEV_CSE, MMIO_CSE_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800136}
137
138static uint32_t read_host_csr(void)
139{
Subrata Banikc6e25522021-09-30 18:14:09 +0530140 return read_bar(PCH_DEV_CSE, MMIO_HOST_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800141}
142
143static void write_host_csr(uint32_t data)
144{
Subrata Banikc6e25522021-09-30 18:14:09 +0530145 write_bar(PCH_DEV_CSE, MMIO_HOST_CSR, data);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800146}
147
148static size_t filled_slots(uint32_t data)
149{
150 uint8_t wp, rp;
151 rp = data >> CSR_RP_START;
152 wp = data >> CSR_WP_START;
153 return (uint8_t) (wp - rp);
154}
155
156static size_t cse_filled_slots(void)
157{
158 return filled_slots(read_cse_csr());
159}
160
161static size_t host_empty_slots(void)
162{
163 uint32_t csr;
164 csr = read_host_csr();
165
166 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
167}
168
169static void clear_int(void)
170{
171 uint32_t csr;
172 csr = read_host_csr();
173 csr |= CSR_IS;
174 write_host_csr(csr);
175}
176
177static uint32_t read_slot(void)
178{
Subrata Banikc6e25522021-09-30 18:14:09 +0530179 return read_bar(PCH_DEV_CSE, MMIO_CSE_CB_RW);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800180}
181
182static void write_slot(uint32_t val)
183{
Subrata Banikc6e25522021-09-30 18:14:09 +0530184 write_bar(PCH_DEV_CSE, MMIO_CSE_CB_WW, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800185}
186
187static int wait_write_slots(size_t cnt)
188{
189 struct stopwatch sw;
190
Subrata Banik03aef282021-09-28 18:10:24 +0530191 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800192 while (host_empty_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530193 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800194 if (stopwatch_expired(&sw)) {
195 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
196 return 0;
197 }
198 }
199 return 1;
200}
201
202static int wait_read_slots(size_t cnt)
203{
204 struct stopwatch sw;
205
Subrata Banik03aef282021-09-28 18:10:24 +0530206 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800207 while (cse_filled_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530208 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800209 if (stopwatch_expired(&sw)) {
210 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
211 return 0;
212 }
213 }
214 return 1;
215}
216
217/* get number of full 4-byte slots */
218static size_t bytes_to_slots(size_t bytes)
219{
220 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
221}
222
223static int cse_ready(void)
224{
225 uint32_t csr;
226 csr = read_cse_csr();
227 return csr & CSR_READY;
228}
229
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530230static bool cse_check_hfs1_com(int mode)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530231{
232 union me_hfsts1 hfs1;
233 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530234 return hfs1.fields.operation_mode == mode;
235}
236
237bool cse_is_hfs1_cws_normal(void)
238{
239 union me_hfsts1 hfs1;
240 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
241 if (hfs1.fields.working_state == ME_HFS1_CWS_NORMAL)
242 return true;
243 return false;
244}
245
246bool cse_is_hfs1_com_normal(void)
247{
248 return cse_check_hfs1_com(ME_HFS1_COM_NORMAL);
249}
250
251bool cse_is_hfs1_com_secover_mei_msg(void)
252{
253 return cse_check_hfs1_com(ME_HFS1_COM_SECOVER_MEI_MSG);
254}
255
256bool cse_is_hfs1_com_soft_temp_disable(void)
257{
258 return cse_check_hfs1_com(ME_HFS1_COM_SOFT_TEMP_DISABLE);
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530259}
260
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530261bool cse_is_hfs3_fw_sku_lite(void)
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530262{
263 union me_hfsts3 hfs3;
264 hfs3.data = me_read_config32(PCI_ME_HFSTS3);
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530265 return hfs3.fields.fw_sku == ME_HFS3_FW_SKU_LITE;
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530266}
267
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530268/* Makes the host ready to communicate with CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530269void cse_set_host_ready(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530270{
271 uint32_t csr;
272 csr = read_host_csr();
273 csr &= ~CSR_RESET;
274 csr |= (CSR_IG | CSR_READY);
275 write_host_csr(csr);
276}
277
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530278/* Polls for ME mode ME_HFS1_COM_SECOVER_MEI_MSG for 15 seconds */
279uint8_t cse_wait_sec_override_mode(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530280{
281 struct stopwatch sw;
Subrata Banik03aef282021-09-28 18:10:24 +0530282 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530283 while (!cse_is_hfs1_com_secover_mei_msg()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530284 udelay(HECI_DELAY_US);
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530285 if (stopwatch_expired(&sw)) {
286 printk(BIOS_ERR, "HECI: Timed out waiting for SEC_OVERRIDE mode!\n");
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530287 return 0;
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530288 }
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530289 }
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530290 printk(BIOS_DEBUG, "HECI: CSE took %lu ms to enter security override mode\n",
291 stopwatch_duration_msecs(&sw));
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530292 return 1;
293}
294
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530295/*
296 * Polls for CSE's current operation mode 'Soft Temporary Disable'.
297 * The CSE enters the current operation mode when it boots from RO(BP1).
298 */
299uint8_t cse_wait_com_soft_temp_disable(void)
300{
301 struct stopwatch sw;
Subrata Banikf5765812021-09-30 13:37:10 +0530302 stopwatch_init_msecs_expire(&sw, CSE_DELAY_BOOT_TO_RO_MS);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530303 while (!cse_is_hfs1_com_soft_temp_disable()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530304 udelay(HECI_DELAY_US);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530305 if (stopwatch_expired(&sw)) {
306 printk(BIOS_ERR, "HECI: Timed out waiting for CSE to boot from RO!\n");
307 return 0;
308 }
309 }
310 printk(BIOS_SPEW, "HECI: CSE took %lu ms to boot from RO\n",
311 stopwatch_duration_msecs(&sw));
312 return 1;
313}
314
Andrey Petrov04a72c42017-03-01 15:51:57 -0800315static int wait_heci_ready(void)
316{
317 struct stopwatch sw;
318
Subrata Banik03aef282021-09-28 18:10:24 +0530319 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800320 while (!cse_ready()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530321 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800322 if (stopwatch_expired(&sw))
323 return 0;
324 }
325
326 return 1;
327}
328
329static void host_gen_interrupt(void)
330{
331 uint32_t csr;
332 csr = read_host_csr();
333 csr |= CSR_IG;
334 write_host_csr(csr);
335}
336
337static size_t hdr_get_length(uint32_t hdr)
338{
339 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
340}
341
342static int
343send_one_message(uint32_t hdr, const void *buff)
344{
345 size_t pend_len, pend_slots, remainder, i;
346 uint32_t tmp;
347 const uint32_t *p = buff;
348
349 /* Get space for the header */
350 if (!wait_write_slots(1))
351 return 0;
352
353 /* First, write header */
354 write_slot(hdr);
355
356 pend_len = hdr_get_length(hdr);
357 pend_slots = bytes_to_slots(pend_len);
358
359 if (!wait_write_slots(pend_slots))
360 return 0;
361
362 /* Write the body in whole slots */
363 i = 0;
364 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
365 write_slot(*p++);
366 i += SLOT_SIZE;
367 }
368
369 remainder = pend_len % SLOT_SIZE;
370 /* Pad to 4 bytes not touching caller's buffer */
371 if (remainder) {
372 memcpy(&tmp, p, remainder);
373 write_slot(tmp);
374 }
375
376 host_gen_interrupt();
377
378 /* Make sure nothing bad happened during transmission */
379 if (!cse_ready())
380 return 0;
381
382 return pend_len;
383}
384
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530385/*
386 * Send message msg of size len to host from host_addr to cse_addr.
387 * Returns 1 on success and 0 otherwise.
388 * In case of error heci_reset() may be required.
389 */
390static int
Andrey Petrov04a72c42017-03-01 15:51:57 -0800391heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
392{
Subrata Banik5c08c732017-11-13 14:54:37 +0530393 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800394 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530395 size_t sent, remaining, cb_size, max_length;
396 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800397
398 if (!msg || !len)
399 return 0;
400
401 clear_int();
402
Subrata Banik5c08c732017-11-13 14:54:37 +0530403 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
404 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800405
Subrata Banik5c08c732017-11-13 14:54:37 +0530406 if (!wait_heci_ready()) {
407 printk(BIOS_ERR, "HECI: not ready\n");
408 continue;
409 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800410
Subrata Banik4a722f52017-11-13 14:56:42 +0530411 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530412 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
413 /*
414 * Reserve one slot for the header. Limit max message
415 * length by 9 bits that are available in the header.
416 */
417 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
418 - SLOT_SIZE;
419 remaining = len;
420
421 /*
422 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100423 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530424 */
425 do {
426 hdr = MIN(max_length, remaining)
427 << MEI_HDR_LENGTH_START;
428 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
429 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
430 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800431 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530432 sent = send_one_message(hdr, p);
433 p += sent;
434 remaining -= sent;
435 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800436
Subrata Banik5c08c732017-11-13 14:54:37 +0530437 if (!remaining)
438 return 1;
439 }
440 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800441}
442
443static size_t
444recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
445{
446 uint32_t reg, *p = buff;
447 size_t recv_slots, recv_len, remainder, i;
448
449 /* first get the header */
450 if (!wait_read_slots(1))
451 return 0;
452
453 *hdr = read_slot();
454 recv_len = hdr_get_length(*hdr);
455
456 if (!recv_len)
457 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
458
459 recv_slots = bytes_to_slots(recv_len);
460
461 i = 0;
462 if (recv_len > maxlen) {
463 printk(BIOS_ERR, "HECI: response is too big\n");
464 return 0;
465 }
466
467 /* wait for the rest of messages to arrive */
468 wait_read_slots(recv_slots);
469
470 /* fetch whole slots first */
471 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
472 *p++ = read_slot();
473 i += SLOT_SIZE;
474 }
475
Subrata Banik5c08c732017-11-13 14:54:37 +0530476 /*
477 * If ME is not ready, something went wrong and
478 * we received junk
479 */
480 if (!cse_ready())
481 return 0;
482
Andrey Petrov04a72c42017-03-01 15:51:57 -0800483 remainder = recv_len % SLOT_SIZE;
484
485 if (remainder) {
486 reg = read_slot();
487 memcpy(p, &reg, remainder);
488 }
489
490 return recv_len;
491}
492
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530493/*
494 * Receive message into buff not exceeding maxlen. Message is considered
495 * successfully received if a 'complete' indication is read from ME side
496 * and there was enough space in the buffer to fit that message. maxlen
497 * is updated with size of message that was received. Returns 0 on failure
498 * and 1 on success.
499 * In case of error heci_reset() may be required.
500 */
501static int heci_receive(void *buff, size_t *maxlen)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800502{
Subrata Banik5c08c732017-11-13 14:54:37 +0530503 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800504 size_t left, received;
505 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530506 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800507
508 if (!buff || !maxlen || !*maxlen)
509 return 0;
510
Andrey Petrov04a72c42017-03-01 15:51:57 -0800511 clear_int();
512
Subrata Banik5c08c732017-11-13 14:54:37 +0530513 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
514 p = buff;
515 left = *maxlen;
516
517 if (!wait_heci_ready()) {
518 printk(BIOS_ERR, "HECI: not ready\n");
519 continue;
520 }
521
522 /*
523 * Receive multiple packets until we meet one marked
524 * complete or we run out of space in caller-provided buffer.
525 */
526 do {
527 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800528 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200529 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800530 return 0;
531 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530532 left -= received;
533 p += received;
534 /* If we read out everything ping to send more */
535 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
536 host_gen_interrupt();
537 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
538
539 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
540 *maxlen = p - (uint8_t *) buff;
541 return 1;
542 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800543 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530544 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800545}
546
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530547int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz,
548 uint8_t cse_addr)
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530549{
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530550 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, cse_addr)) {
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530551 printk(BIOS_ERR, "HECI: send Failed\n");
552 return 0;
553 }
554
555 if (rcv_msg != NULL) {
556 if (!heci_receive(rcv_msg, rcv_sz)) {
557 printk(BIOS_ERR, "HECI: receive Failed\n");
558 return 0;
559 }
560 }
561 return 1;
562}
563
Andrey Petrov04a72c42017-03-01 15:51:57 -0800564/*
565 * Attempt to reset the device. This is useful when host and ME are out
566 * of sync during transmission or ME didn't understand the message.
567 */
568int heci_reset(void)
569{
570 uint32_t csr;
571
Duncan Laurie15ca9032020-11-05 10:09:07 -0800572 /* Clear post code to prevent eventlog entry from unknown code. */
573 post_code(0);
574
Andrey Petrov04a72c42017-03-01 15:51:57 -0800575 /* Send reset request */
576 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530577 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800578 write_host_csr(csr);
579
580 if (wait_heci_ready()) {
581 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530582 cse_set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800583 return 1;
584 }
585
586 printk(BIOS_CRIT, "HECI: reset failed\n");
587
588 return 0;
589}
590
Subrata Banik3710e992021-09-30 16:59:09 +0530591bool is_cse_devfn_visible(unsigned int devfn)
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530592{
Subrata Banik3710e992021-09-30 16:59:09 +0530593 int slot = PCI_SLOT(devfn);
594 int func = PCI_FUNC(devfn);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530595
Subrata Banik3710e992021-09-30 16:59:09 +0530596 if (!is_devfn_enabled(devfn)) {
597 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is disabled\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530598 return false;
599 }
600
Subrata Banik3710e992021-09-30 16:59:09 +0530601 if (pci_read_config16(PCI_DEV(0, slot, func), PCI_VENDOR_ID) == 0xFFFF) {
602 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is hidden\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530603 return false;
604 }
605
606 return true;
607}
608
Subrata Banik3710e992021-09-30 16:59:09 +0530609bool is_cse_enabled(void)
610{
611 return is_cse_devfn_visible(PCH_DEVFN_CSE);
612}
613
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530614uint32_t me_read_config32(int offset)
615{
616 return pci_read_config32(PCH_DEV_CSE, offset);
617}
618
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530619static bool cse_is_global_reset_allowed(void)
620{
621 /*
622 * Allow sending GLOBAL_RESET command only if:
623 * - CSE's current working state is Normal and current operation mode is Normal.
624 * - (or) CSE's current working state is normal and current operation mode can
625 * be Soft Temp Disable or Security Override Mode if CSE's Firmware SKU is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530626 * Lite.
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530627 */
628 if (!cse_is_hfs1_cws_normal())
629 return false;
630
631 if (cse_is_hfs1_com_normal())
632 return true;
633
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530634 if (cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530635 if (cse_is_hfs1_com_soft_temp_disable() || cse_is_hfs1_com_secover_mei_msg())
636 return true;
637 }
638 return false;
639}
640
Sridhar Siricillad415c202019-08-31 14:54:57 +0530641/*
Subrata Banikf463dc02020-09-14 19:04:03 +0530642 * Sends GLOBAL_RESET_REQ cmd to CSE with reset type GLOBAL_RESET.
643 * Returns 0 on failure and 1 on success.
Sridhar Siricillad415c202019-08-31 14:54:57 +0530644 */
Subrata Banikf463dc02020-09-14 19:04:03 +0530645static int cse_request_reset(enum rst_req_type rst_type)
Sridhar Siricillad415c202019-08-31 14:54:57 +0530646{
647 int status;
648 struct mkhi_hdr reply;
649 struct reset_message {
650 struct mkhi_hdr hdr;
651 uint8_t req_origin;
652 uint8_t reset_type;
653 } __packed;
654 struct reset_message msg = {
655 .hdr = {
656 .group_id = MKHI_GROUP_ID_CBM,
Sridhar Siricillae202e672020-01-07 23:36:40 +0530657 .command = MKHI_CBM_GLOBAL_RESET_REQ,
Sridhar Siricillad415c202019-08-31 14:54:57 +0530658 },
659 .req_origin = GR_ORIGIN_BIOS_POST,
660 .reset_type = rst_type
661 };
662 size_t reply_size;
663
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530664 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530665
Sridhar Siricillac2a2d2b2020-02-27 17:16:13 +0530666 if (!(rst_type == GLOBAL_RESET || rst_type == CSE_RESET_ONLY)) {
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530667 printk(BIOS_ERR, "HECI: Unsupported reset type is requested\n");
668 return 0;
669 }
Sridhar Siricillad415c202019-08-31 14:54:57 +0530670
Subrata Banikf463dc02020-09-14 19:04:03 +0530671 if (!cse_is_global_reset_allowed() || !is_cse_enabled()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530672 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
673 return 0;
674 }
675
Sridhar Siricillad415c202019-08-31 14:54:57 +0530676 heci_reset();
677
678 reply_size = sizeof(reply);
679 memset(&reply, 0, reply_size);
680
Sridhar Siricillad415c202019-08-31 14:54:57 +0530681 if (rst_type == CSE_RESET_ONLY)
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530682 status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530683 else
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530684 status = heci_send_receive(&msg, sizeof(msg), &reply, &reply_size,
685 HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530686
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530687 printk(BIOS_DEBUG, "HECI: Global Reset %s!\n", status ? "success" : "failure");
688 return status;
Sridhar Siricillad415c202019-08-31 14:54:57 +0530689}
690
Subrata Banikf463dc02020-09-14 19:04:03 +0530691int cse_request_global_reset(void)
692{
693 return cse_request_reset(GLOBAL_RESET);
694}
695
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530696static bool cse_is_hmrfpo_enable_allowed(void)
697{
698 /*
699 * Allow sending HMRFPO ENABLE command only if:
700 * - CSE's current working state is Normal and current operation mode is Normal
701 * - (or) cse's current working state is normal and current operation mode is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530702 * Soft Temp Disable if CSE's Firmware SKU is Lite
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530703 */
704 if (!cse_is_hfs1_cws_normal())
705 return false;
706
707 if (cse_is_hfs1_com_normal())
708 return true;
709
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530710 if (cse_is_hfs3_fw_sku_lite() && cse_is_hfs1_com_soft_temp_disable())
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530711 return true;
712
713 return false;
714}
715
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530716/* Sends HMRFPO Enable command to CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530717int cse_hmrfpo_enable(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530718{
719 struct hmrfpo_enable_msg {
720 struct mkhi_hdr hdr;
721 uint32_t nonce[2];
722 } __packed;
723
724 /* HMRFPO Enable message */
725 struct hmrfpo_enable_msg msg = {
726 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530727 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530728 .command = MKHI_HMRFPO_ENABLE,
729 },
730 .nonce = {0},
731 };
732
733 /* HMRFPO Enable response */
734 struct hmrfpo_enable_resp {
735 struct mkhi_hdr hdr;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530736 /* Base addr for factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530737 uint32_t fct_base;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530738 /* Length of factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530739 uint32_t fct_limit;
740 uint8_t status;
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530741 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530742 } __packed;
743
744 struct hmrfpo_enable_resp resp;
745 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530746
Sridhar Siricilla49c25f22021-11-27 19:56:47 +0530747 if (cse_is_hfs1_com_secover_mei_msg()) {
748 printk(BIOS_DEBUG, "HECI: CSE is already in security override mode, "
749 "skip sending HMRFPO_ENABLE command to CSE\n");
750 return 1;
751 }
752
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530753 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530754
755 if (!cse_is_hmrfpo_enable_allowed()) {
756 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
757 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530758 }
759
760 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530761 &resp, &resp_size, HECI_MKHI_ADDR))
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530762 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530763
764 if (resp.hdr.result) {
765 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530766 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530767 }
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530768
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530769 if (resp.status) {
770 printk(BIOS_ERR, "HECI: HMRFPO_Enable Failed (resp status: %d)\n", resp.status);
771 return 0;
772 }
773
774 return 1;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530775}
776
777/*
778 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530779 * The status can be DISABLED/LOCKED/ENABLED
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530780 */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530781int cse_hmrfpo_get_status(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530782{
783 struct hmrfpo_get_status_msg {
784 struct mkhi_hdr hdr;
785 } __packed;
786
787 struct hmrfpo_get_status_resp {
788 struct mkhi_hdr hdr;
789 uint8_t status;
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530790 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530791 } __packed;
792
793 struct hmrfpo_get_status_msg msg = {
794 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530795 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530796 .command = MKHI_HMRFPO_GET_STATUS,
797 },
798 };
799 struct hmrfpo_get_status_resp resp;
800 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
801
802 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
803
Sridhar Siricilla206905c2020-02-06 18:48:22 +0530804 if (!cse_is_hfs1_cws_normal()) {
805 printk(BIOS_ERR, "HECI: CSE's current working state is not Normal\n");
806 return -1;
807 }
808
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530809 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530810 &resp, &resp_size, HECI_MKHI_ADDR)) {
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530811 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
812 return -1;
813 }
814
815 if (resp.hdr.result) {
816 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
817 resp.hdr.result);
818 return -1;
819 }
820
821 return resp.status;
822}
823
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530824void print_me_fw_version(void *unused)
825{
Johnny Lin72e76672021-10-09 12:35:35 +0800826 struct me_fw_ver_resp resp = {0};
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530827
828 /* Ignore if UART debugging is disabled */
829 if (!CONFIG(CONSOLE_SERIAL))
830 return;
831
Johnny Lin72e76672021-10-09 12:35:35 +0800832 if (get_me_fw_version(&resp) == CB_SUCCESS) {
833 printk(BIOS_DEBUG, "ME: Version: %d.%d.%d.%d\n", resp.code.major,
834 resp.code.minor, resp.code.hotfix, resp.code.build);
835 return;
836 }
837 printk(BIOS_DEBUG, "ME: Version: Unavailable\n");
838}
839
840enum cb_err get_me_fw_version(struct me_fw_ver_resp *resp)
841{
842 const struct mkhi_hdr fw_ver_msg = {
843 .group_id = MKHI_GROUP_ID_GEN,
844 .command = MKHI_GEN_GET_FW_VERSION,
845 };
846
847 if (resp == NULL) {
848 printk(BIOS_ERR, "%s failed, null pointer parameter\n", __func__);
849 return CB_ERR;
850 }
851 size_t resp_size = sizeof(*resp);
852
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200853 /* Ignore if CSE is disabled */
854 if (!is_cse_enabled())
Johnny Lin72e76672021-10-09 12:35:35 +0800855 return CB_ERR;
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200856
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530857 /*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530858 * Ignore if ME Firmware SKU type is Lite since
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530859 * print_boot_partition_info() logs RO(BP1) and RW(BP2) versions.
860 */
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530861 if (cse_is_hfs3_fw_sku_lite())
Johnny Lin72e76672021-10-09 12:35:35 +0800862 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530863
864 /*
865 * Prerequisites:
866 * 1) HFSTS1 Current Working State is Normal
867 * 2) HFSTS1 Current Operation Mode is Normal
868 * 3) It's after DRAM INIT DONE message (taken care of by calling it
869 * during ramstage
870 */
871 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal())
Johnny Lin72e76672021-10-09 12:35:35 +0800872 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530873
874 heci_reset();
875
Johnny Lin72e76672021-10-09 12:35:35 +0800876 if (!heci_send_receive(&fw_ver_msg, sizeof(fw_ver_msg), resp, &resp_size,
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530877 HECI_MKHI_ADDR))
Johnny Lin72e76672021-10-09 12:35:35 +0800878 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530879
Johnny Lin72e76672021-10-09 12:35:35 +0800880 if (resp->hdr.result)
881 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530882
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530883
Johnny Lin72e76672021-10-09 12:35:35 +0800884 return CB_SUCCESS;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530885}
886
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600887void cse_trigger_vboot_recovery(enum csme_failure_reason reason)
888{
889 printk(BIOS_DEBUG, "cse: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
890 "HFSTS3: 0x%x\n", me_read_config32(PCI_ME_HFSTS1),
891 me_read_config32(PCI_ME_HFSTS2), me_read_config32(PCI_ME_HFSTS3));
892
893 if (CONFIG(VBOOT)) {
894 struct vb2_context *ctx = vboot_get_context();
895 if (ctx == NULL)
896 goto failure;
897 vb2api_fail(ctx, VB2_RECOVERY_INTEL_CSE_LITE_SKU, reason);
898 vboot_save_data(ctx);
899 vboot_reboot();
900 }
901failure:
902 die("cse: Failed to trigger recovery mode(recovery subcode:%d)\n", reason);
903}
904
Subrata Banikc6e25522021-09-30 18:14:09 +0530905static bool disable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530906{
907 struct stopwatch sw;
Subrata Banikc6e25522021-09-30 18:14:09 +0530908 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530909 dev_idle_ctrl &= ~CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530910 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530911
Subrata Banik03aef282021-09-28 18:10:24 +0530912 stopwatch_init_usecs_expire(&sw, HECI_CIP_TIMEOUT_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530913 do {
Subrata Banikc6e25522021-09-30 18:14:09 +0530914 dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530915 if ((dev_idle_ctrl & CSE_DEV_CIP) == CSE_DEV_CIP)
916 return true;
Subrata Banik03aef282021-09-28 18:10:24 +0530917 udelay(HECI_DELAY_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530918 } while (!stopwatch_expired(&sw));
919
920 return false;
921}
922
Subrata Banikc6e25522021-09-30 18:14:09 +0530923static void enable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530924{
Subrata Banikc6e25522021-09-30 18:14:09 +0530925 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530926 dev_idle_ctrl |= CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530927 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530928}
929
Subrata Banikc6e25522021-09-30 18:14:09 +0530930enum cse_device_state get_cse_device_state(unsigned int devfn)
Subrata Banika219edb2021-09-25 15:02:37 +0530931{
Subrata Banikc6e25522021-09-30 18:14:09 +0530932 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
933 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530934 if ((dev_idle_ctrl & CSE_DEV_IDLE) == CSE_DEV_IDLE)
935 return DEV_IDLE;
936
937 return DEV_ACTIVE;
938}
939
Subrata Banikc6e25522021-09-30 18:14:09 +0530940static enum cse_device_state ensure_cse_active(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530941{
Subrata Banikc6e25522021-09-30 18:14:09 +0530942 if (!disable_cse_idle(dev))
Subrata Banika219edb2021-09-25 15:02:37 +0530943 return DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530944 pci_or_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
Subrata Banika219edb2021-09-25 15:02:37 +0530945
946 return DEV_ACTIVE;
947}
948
Subrata Banikc6e25522021-09-30 18:14:09 +0530949static void ensure_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530950{
Subrata Banikc6e25522021-09-30 18:14:09 +0530951 enable_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +0530952
Subrata Banikc6e25522021-09-30 18:14:09 +0530953 pci_and_config32(dev, PCI_COMMAND, ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
Subrata Banika219edb2021-09-25 15:02:37 +0530954}
955
Subrata Banikc6e25522021-09-30 18:14:09 +0530956bool set_cse_device_state(unsigned int devfn, enum cse_device_state requested_state)
Subrata Banika219edb2021-09-25 15:02:37 +0530957{
Subrata Banikc6e25522021-09-30 18:14:09 +0530958 enum cse_device_state current_state = get_cse_device_state(devfn);
959 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
Subrata Banika219edb2021-09-25 15:02:37 +0530960
961 if (current_state == requested_state)
962 return true;
963
964 if (requested_state == DEV_ACTIVE)
Subrata Banikc6e25522021-09-30 18:14:09 +0530965 return ensure_cse_active(dev) == requested_state;
Subrata Banika219edb2021-09-25 15:02:37 +0530966 else
Subrata Banikc6e25522021-09-30 18:14:09 +0530967 ensure_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +0530968
969 return true;
970}
971
Andrey Petrov04a72c42017-03-01 15:51:57 -0800972#if ENV_RAMSTAGE
973
Sean Rhodes69ed3ed2021-04-30 16:38:17 +0100974/*
975 * Disable the Intel (CS)Management Engine via HECI based on a cmos value
976 * of `me_state`. A value of `0` will result in a (CS)ME state of `0` (working)
977 * and value of `1` will result in a (CS)ME state of `3` (disabled).
978 *
979 * It isn't advised to use this in combination with me_cleaner.
980 *
981 * It is advisable to have a second cmos option called `me_state_counter`.
982 * Whilst not essential, it avoid reboots loops if the (CS)ME fails to
983 * change states after 3 attempts. Some versions of the (CS)ME need to be
984 * reset 3 times.
985 *
986 * Ideal cmos values would be:
987 *
988 * # coreboot config options: cpu
989 * 432 1 e 5 me_state
990 * 440 4 h 0 me_state_counter
991 *
992 * #ID value text
993 * 5 0 Enable
994 * 5 1 Disable
995 */
996
997static void me_reset_with_count(void)
998{
999 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter", UINT_MAX);
1000
1001 if (cmos_me_state_counter != UINT_MAX) {
1002 printk(BIOS_DEBUG, "CMOS: me_state_counter = %u\n", cmos_me_state_counter);
1003 /* Avoid boot loops by only trying a state change 3 times */
1004 if (cmos_me_state_counter < ME_DISABLE_ATTEMPTS) {
1005 cmos_me_state_counter++;
1006 set_uint_option("me_state_counter", cmos_me_state_counter);
1007 printk(BIOS_DEBUG, "ME: Reset attempt %u/%u.\n", cmos_me_state_counter,
1008 ME_DISABLE_ATTEMPTS);
1009 do_global_reset();
1010 } else {
1011 /*
1012 * If the (CS)ME fails to change states after 3 attempts, it will
1013 * likely need a cold boot, or recovering.
1014 */
1015 printk(BIOS_ERR, "Error: Failed to change ME state in %u attempts!\n",
1016 ME_DISABLE_ATTEMPTS);
1017
1018 }
1019 } else {
1020 printk(BIOS_DEBUG, "ME: Resetting");
1021 do_global_reset();
1022 }
1023}
1024
1025static void cse_set_state(struct device *dev)
1026{
1027
1028 /* (CS)ME Disable Command */
1029 struct me_disable_command {
1030 struct mkhi_hdr hdr;
1031 uint32_t rule_id;
1032 uint8_t rule_len;
1033 uint32_t rule_data;
1034 } __packed me_disable = {
1035 .hdr = {
1036 .group_id = MKHI_GROUP_ID_FWCAPS,
1037 .command = MKHI_SET_ME_DISABLE,
1038 },
1039 .rule_id = ME_DISABLE_RULE_ID,
1040 .rule_len = ME_DISABLE_RULE_LENGTH,
1041 .rule_data = ME_DISABLE_COMMAND,
1042 };
1043
1044 struct me_disable_reply {
1045 struct mkhi_hdr hdr;
1046 uint32_t rule_id;
1047 } __packed;
1048
1049 struct me_disable_reply disable_reply;
1050
1051 size_t disable_reply_size;
1052
1053 /* (CS)ME Enable Command */
1054 struct me_enable_command {
1055 struct mkhi_hdr hdr;
1056 } me_enable = {
1057 .hdr = {
1058 .group_id = MKHI_GROUP_ID_BUP_COMMON,
1059 .command = MKHI_SET_ME_ENABLE,
1060 },
1061 };
1062
1063 struct me_enable_reply {
1064 struct mkhi_hdr hdr;
1065 } __packed;
1066
1067 struct me_enable_reply enable_reply;
1068
1069 size_t enable_reply_size;
1070
1071 /* Function Start */
1072
1073 int send;
1074 int result;
1075 /*
1076 * Check if the CMOS value "me_state" exists, if it doesn't, then
1077 * don't do anything.
1078 */
1079 const unsigned int cmos_me_state = get_uint_option("me_state", UINT_MAX);
1080
1081 if (cmos_me_state == UINT_MAX)
1082 return;
1083
1084 printk(BIOS_DEBUG, "CMOS: me_state = %u\n", cmos_me_state);
1085
1086 /*
1087 * We only take action if the me_state doesn't match the CS(ME) working state
1088 */
1089
1090 const unsigned int soft_temp_disable = cse_is_hfs1_com_soft_temp_disable();
1091
1092 if (cmos_me_state && !soft_temp_disable) {
1093 /* me_state should be disabled, but it's enabled */
1094 printk(BIOS_DEBUG, "ME needs to be disabled.\n");
1095 send = heci_send_receive(&me_disable, sizeof(me_disable),
1096 &disable_reply, &disable_reply_size, HECI_MKHI_ADDR);
1097 result = disable_reply.hdr.result;
1098 } else if (!cmos_me_state && soft_temp_disable) {
1099 /* me_state should be enabled, but it's disabled */
1100 printk(BIOS_DEBUG, "ME needs to be enabled.\n");
1101 send = heci_send_receive(&me_enable, sizeof(me_enable),
1102 &enable_reply, &enable_reply_size, HECI_MKHI_ADDR);
1103 result = enable_reply.hdr.result;
1104 } else {
1105 printk(BIOS_DEBUG, "ME is %s.\n", cmos_me_state ? "disabled" : "enabled");
1106 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter",
1107 UINT_MAX);
1108 /* set me_state_counter to 0 */
1109 if ((cmos_me_state_counter != UINT_MAX && cmos_me_state_counter != 0))
1110 set_uint_option("me_state_counter", 0);
1111 return;
1112 }
1113
1114 printk(BIOS_DEBUG, "HECI: ME state change send %s!\n",
1115 send ? "success" : "failure");
1116 printk(BIOS_DEBUG, "HECI: ME state change result %s!\n",
1117 result ? "success" : "failure");
1118
1119 /*
1120 * Reset if the result was successful, or if the send failed as some older
1121 * version of the Intel (CS)ME won't successfully receive the message unless reset
1122 * twice.
1123 */
1124 if (send || !result)
1125 me_reset_with_count();
1126}
1127
Andrey Petrov04a72c42017-03-01 15:51:57 -08001128static struct device_operations cse_ops = {
Subrata Banik38abbda2021-09-30 13:15:50 +05301129 .set_resources = pci_dev_set_resources,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001130 .read_resources = pci_dev_read_resources,
1131 .enable_resources = pci_dev_enable_resources,
1132 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +05301133 .ops_pci = &pci_dev_ops_pci,
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001134 .enable = cse_set_state,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001135};
1136
Hannah Williams63142152017-06-12 14:03:18 -07001137static const unsigned short pci_device_ids[] = {
1138 PCI_DEVICE_ID_INTEL_APL_CSE0,
1139 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -07001140 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Subrata Banikd0586d22017-11-27 13:28:41 +05301141 PCI_DEVICE_ID_INTEL_SKL_CSE0,
Maxim Polyakov571d07d2019-08-22 13:11:32 +03001142 PCI_DEVICE_ID_INTEL_LWB_CSE0,
1143 PCI_DEVICE_ID_INTEL_LWB_CSE0_SUPER,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +08001144 PCI_DEVICE_ID_INTEL_CNP_H_CSE0,
Aamir Bohra9eac0392018-06-30 12:07:04 +05301145 PCI_DEVICE_ID_INTEL_ICL_CSE0,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +05301146 PCI_DEVICE_ID_INTEL_CMP_CSE0,
Gaggery Tsai12a651c2019-12-05 11:23:20 -08001147 PCI_DEVICE_ID_INTEL_CMP_H_CSE0,
Ravi Sarawadi6b5bf402019-10-21 22:25:04 -07001148 PCI_DEVICE_ID_INTEL_TGL_CSE0,
Jeremy Soller191a8d72021-08-10 14:06:51 -06001149 PCI_DEVICE_ID_INTEL_TGL_H_CSE0,
Tan, Lean Sheng26136092020-01-20 19:13:56 -08001150 PCI_DEVICE_ID_INTEL_MCC_CSE0,
1151 PCI_DEVICE_ID_INTEL_MCC_CSE1,
1152 PCI_DEVICE_ID_INTEL_MCC_CSE2,
1153 PCI_DEVICE_ID_INTEL_MCC_CSE3,
Meera Ravindranath3f4af0d2020-02-12 16:01:22 +05301154 PCI_DEVICE_ID_INTEL_JSP_CSE0,
1155 PCI_DEVICE_ID_INTEL_JSP_CSE1,
1156 PCI_DEVICE_ID_INTEL_JSP_CSE2,
1157 PCI_DEVICE_ID_INTEL_JSP_CSE3,
Subrata Banikf672f7f2020-08-03 14:29:25 +05301158 PCI_DEVICE_ID_INTEL_ADP_P_CSE0,
1159 PCI_DEVICE_ID_INTEL_ADP_P_CSE1,
1160 PCI_DEVICE_ID_INTEL_ADP_P_CSE2,
1161 PCI_DEVICE_ID_INTEL_ADP_P_CSE3,
1162 PCI_DEVICE_ID_INTEL_ADP_S_CSE0,
1163 PCI_DEVICE_ID_INTEL_ADP_S_CSE1,
1164 PCI_DEVICE_ID_INTEL_ADP_S_CSE2,
1165 PCI_DEVICE_ID_INTEL_ADP_S_CSE3,
Varshit Pandyaf4d98fdd22021-01-17 18:39:29 +05301166 PCI_DEVICE_ID_INTEL_ADP_M_CSE0,
1167 PCI_DEVICE_ID_INTEL_ADP_M_CSE1,
1168 PCI_DEVICE_ID_INTEL_ADP_M_CSE2,
1169 PCI_DEVICE_ID_INTEL_ADP_M_CSE3,
Hannah Williams63142152017-06-12 14:03:18 -07001170 0,
1171};
1172
Andrey Petrov04a72c42017-03-01 15:51:57 -08001173static const struct pci_driver cse_driver __pci_driver = {
1174 .ops = &cse_ops,
1175 .vendor = PCI_VENDOR_ID_INTEL,
1176 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -07001177 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -08001178};
1179
1180#endif