blob: 25a04ed30459787b39dbb57052bd4e717b68f3be [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>
Dinesh Gehlot7e396162023-02-20 06:26:17 +000014#include <intelblocks/me.h>
Subrata Banik80c92892022-02-01 00:26:55 +053015#include <intelblocks/pmclib.h>
Martin Roth8c974502022-11-20 17:56:44 -070016#include <intelblocks/post_codes.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010017#include <option.h>
Tim Wawrzynczak09635f42021-06-18 10:08:47 -060018#include <security/vboot/misc.h>
19#include <security/vboot/vboot_common.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010020#include <soc/intel/common/reset.h>
Subrata Banik05e06cd2017-11-09 15:04:09 +053021#include <soc/iomap.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080022#include <soc/pci_devs.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080023#include <string.h>
24#include <timer.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010025#include <types.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080026
Subrata Banik801dbf42022-06-01 07:56:40 +000027#define HECI_BASE_SIZE (4 * KiB)
28
Subrata Banik5c08c732017-11-13 14:54:37 +053029#define MAX_HECI_MESSAGE_RETRY_COUNT 5
30
Andrey Petrov04a72c42017-03-01 15:51:57 -080031/* Wait up to 15 sec for HECI to get ready */
Subrata Banik03aef282021-09-28 18:10:24 +053032#define HECI_DELAY_READY_MS (15 * 1000)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010033/* Wait up to 100 usec between circular buffer polls */
Subrata Banik03aef282021-09-28 18:10:24 +053034#define HECI_DELAY_US 100
Andrey Petrov04a72c42017-03-01 15:51:57 -080035/* Wait up to 5 sec for CSE to chew something we sent */
Subrata Banik03aef282021-09-28 18:10:24 +053036#define HECI_SEND_TIMEOUT_MS (5 * 1000)
Andrey Petrov04a72c42017-03-01 15:51:57 -080037/* Wait up to 5 sec for CSE to blurp a reply */
Subrata Banik03aef282021-09-28 18:10:24 +053038#define HECI_READ_TIMEOUT_MS (5 * 1000)
Subrata Banika219edb2021-09-25 15:02:37 +053039/* Wait up to 1 ms for CSE CIP */
Subrata Banik03aef282021-09-28 18:10:24 +053040#define HECI_CIP_TIMEOUT_US 1000
Subrata Banikf5765812021-09-30 13:37:10 +053041/* Wait up to 5 seconds for CSE to boot from RO(BP1) */
42#define CSE_DELAY_BOOT_TO_RO_MS (5 * 1000)
Andrey Petrov04a72c42017-03-01 15:51:57 -080043
44#define SLOT_SIZE sizeof(uint32_t)
45
46#define MMIO_CSE_CB_WW 0x00
47#define MMIO_HOST_CSR 0x04
48#define MMIO_CSE_CB_RW 0x08
49#define MMIO_CSE_CSR 0x0c
Subrata Banika219edb2021-09-25 15:02:37 +053050#define MMIO_CSE_DEVIDLE 0x800
51#define CSE_DEV_IDLE (1 << 2)
52#define CSE_DEV_CIP (1 << 0)
Andrey Petrov04a72c42017-03-01 15:51:57 -080053
54#define CSR_IE (1 << 0)
55#define CSR_IS (1 << 1)
56#define CSR_IG (1 << 2)
57#define CSR_READY (1 << 3)
58#define CSR_RESET (1 << 4)
59#define CSR_RP_START 8
60#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
61#define CSR_WP_START 16
62#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
63#define CSR_CBD_START 24
64#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
65
66#define MEI_HDR_IS_COMPLETE (1 << 31)
67#define MEI_HDR_LENGTH_START 16
68#define MEI_HDR_LENGTH_SIZE 9
69#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
70 << MEI_HDR_LENGTH_START)
71#define MEI_HDR_HOST_ADDR_START 8
72#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
73#define MEI_HDR_CSE_ADDR_START 0
74#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
75
Subrata Banik38abbda2021-09-30 13:15:50 +053076/* Get HECI BAR 0 from PCI configuration space */
Subrata Banikc6e25522021-09-30 18:14:09 +053077static uintptr_t get_cse_bar(pci_devfn_t dev)
Subrata Banik38abbda2021-09-30 13:15:50 +053078{
79 uintptr_t bar;
80
Subrata Banikc6e25522021-09-30 18:14:09 +053081 bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
Subrata Banik38abbda2021-09-30 13:15:50 +053082 assert(bar != 0);
83 /*
84 * Bits 31-12 are the base address as per EDS for SPI,
85 * Don't care about 0-11 bit
86 */
87 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
88}
Andrey Petrov04a72c42017-03-01 15:51:57 -080089
Subrata Banik801dbf42022-06-01 07:56:40 +000090static void heci_assign_resource(pci_devfn_t dev, uintptr_t tempbar)
91{
92 u16 pcireg;
93
94 /* Assign Resources */
95 /* Clear BIT 1-2 of Command Register */
96 pcireg = pci_read_config16(dev, PCI_COMMAND);
97 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
98 pci_write_config16(dev, PCI_COMMAND, pcireg);
99
100 /* Program Temporary BAR for HECI device */
101 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
102 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
103
104 /* Enable Bus Master and MMIO Space */
105 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
106}
107
Andrey Petrov04a72c42017-03-01 15:51:57 -0800108/*
Subrata Banik0b92aa62022-06-01 06:54:44 +0000109 * Initialize the CSE device with provided temporary BAR. If BAR is 0 use a
Andrey Petrov04a72c42017-03-01 15:51:57 -0800110 * default. This is intended for pre-mem usage only where BARs haven't been
111 * assigned yet and devices are not enabled.
112 */
Subrata Banik0b92aa62022-06-01 06:54:44 +0000113void cse_init(uintptr_t tempbar)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800114{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +0200115 pci_devfn_t dev = PCH_DEV_CSE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530116
Matt DeVillierf711bf02022-01-25 19:48:38 -0600117 /* Check if device enabled */
118 if (!is_cse_enabled())
119 return;
120
Andrey Petrov04a72c42017-03-01 15:51:57 -0800121 /* Assume it is already initialized, nothing else to do */
Subrata Banikc6e25522021-09-30 18:14:09 +0530122 if (get_cse_bar(dev))
Andrey Petrov04a72c42017-03-01 15:51:57 -0800123 return;
124
125 /* Use default pre-ram bar */
126 if (!tempbar)
127 tempbar = HECI1_BASE_ADDRESS;
128
Subrata Banik801dbf42022-06-01 07:56:40 +0000129 /* Assign HECI resource and enable the resource */
130 heci_assign_resource(dev, tempbar);
Sridhar Siricillacb2fd202021-06-09 19:27:06 +0530131
132 /* Trigger HECI Reset and make Host ready for communication with CSE */
133 heci_reset();
Subrata Banik05e06cd2017-11-09 15:04:09 +0530134}
135
Subrata Banikc6e25522021-09-30 18:14:09 +0530136static uint32_t read_bar(pci_devfn_t dev, uint32_t offset)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800137{
Subrata Banikc6e25522021-09-30 18:14:09 +0530138 return read32p(get_cse_bar(dev) + offset);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800139}
140
Subrata Banikc6e25522021-09-30 18:14:09 +0530141static void write_bar(pci_devfn_t dev, uint32_t offset, uint32_t val)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800142{
Subrata Banikc6e25522021-09-30 18:14:09 +0530143 return write32p(get_cse_bar(dev) + offset, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800144}
145
146static uint32_t read_cse_csr(void)
147{
Subrata Banikc6e25522021-09-30 18:14:09 +0530148 return read_bar(PCH_DEV_CSE, MMIO_CSE_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800149}
150
151static uint32_t read_host_csr(void)
152{
Subrata Banikc6e25522021-09-30 18:14:09 +0530153 return read_bar(PCH_DEV_CSE, MMIO_HOST_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800154}
155
156static void write_host_csr(uint32_t data)
157{
Subrata Banikc6e25522021-09-30 18:14:09 +0530158 write_bar(PCH_DEV_CSE, MMIO_HOST_CSR, data);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800159}
160
161static size_t filled_slots(uint32_t data)
162{
163 uint8_t wp, rp;
164 rp = data >> CSR_RP_START;
165 wp = data >> CSR_WP_START;
Elyes Haouas9018dee2022-11-18 15:07:33 +0100166 return (uint8_t)(wp - rp);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800167}
168
169static size_t cse_filled_slots(void)
170{
171 return filled_slots(read_cse_csr());
172}
173
174static size_t host_empty_slots(void)
175{
176 uint32_t csr;
177 csr = read_host_csr();
178
179 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
180}
181
182static void clear_int(void)
183{
184 uint32_t csr;
185 csr = read_host_csr();
186 csr |= CSR_IS;
187 write_host_csr(csr);
188}
189
190static uint32_t read_slot(void)
191{
Subrata Banikc6e25522021-09-30 18:14:09 +0530192 return read_bar(PCH_DEV_CSE, MMIO_CSE_CB_RW);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800193}
194
195static void write_slot(uint32_t val)
196{
Subrata Banikc6e25522021-09-30 18:14:09 +0530197 write_bar(PCH_DEV_CSE, MMIO_CSE_CB_WW, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800198}
199
200static int wait_write_slots(size_t cnt)
201{
202 struct stopwatch sw;
203
Subrata Banik03aef282021-09-28 18:10:24 +0530204 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800205 while (host_empty_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530206 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800207 if (stopwatch_expired(&sw)) {
208 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
209 return 0;
210 }
211 }
212 return 1;
213}
214
215static int wait_read_slots(size_t cnt)
216{
217 struct stopwatch sw;
218
Subrata Banik03aef282021-09-28 18:10:24 +0530219 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800220 while (cse_filled_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530221 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800222 if (stopwatch_expired(&sw)) {
223 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
224 return 0;
225 }
226 }
227 return 1;
228}
229
230/* get number of full 4-byte slots */
231static size_t bytes_to_slots(size_t bytes)
232{
233 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
234}
235
236static int cse_ready(void)
237{
238 uint32_t csr;
239 csr = read_cse_csr();
240 return csr & CSR_READY;
241}
242
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530243static bool cse_check_hfs1_com(int mode)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530244{
245 union me_hfsts1 hfs1;
246 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530247 return hfs1.fields.operation_mode == mode;
248}
249
Michał Żygowskidaa17102022-10-04 10:55:38 +0200250static bool cse_is_hfs1_fw_init_complete(void)
251{
252 union me_hfsts1 hfs1;
253 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
254 if (hfs1.fields.fw_init_complete)
255 return true;
256 return false;
257}
258
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530259bool cse_is_hfs1_cws_normal(void)
260{
261 union me_hfsts1 hfs1;
262 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
263 if (hfs1.fields.working_state == ME_HFS1_CWS_NORMAL)
264 return true;
265 return false;
266}
267
268bool cse_is_hfs1_com_normal(void)
269{
270 return cse_check_hfs1_com(ME_HFS1_COM_NORMAL);
271}
272
273bool cse_is_hfs1_com_secover_mei_msg(void)
274{
275 return cse_check_hfs1_com(ME_HFS1_COM_SECOVER_MEI_MSG);
276}
277
278bool cse_is_hfs1_com_soft_temp_disable(void)
279{
280 return cse_check_hfs1_com(ME_HFS1_COM_SOFT_TEMP_DISABLE);
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530281}
282
Subrata Banike74ebcd2021-12-27 10:49:19 +0000283/*
Sridhar Siricilla90a43932022-09-12 10:37:17 +0530284 * Starting from TGL platform, HFSTS1.spi_protection_mode replaces mfg_mode to indicate
285 * SPI protection status as well as end-of-manufacturing(EOM) status where EOM flow is
286 * triggered in single staged operation (either through first boot with required MFIT
287 * configuratin or FPT /CLOSEMANUF).
288 * In staged manufacturing flow, spi_protection_mode alone doesn't indicate the EOM status.
Subrata Banike74ebcd2021-12-27 10:49:19 +0000289 *
Sridhar Siricilla90a43932022-09-12 10:37:17 +0530290 * HFSTS1.spi_protection_mode description:
291 * mfg_mode = 0 means SPI protection is on.
Subrata Banike74ebcd2021-12-27 10:49:19 +0000292 * mfg_mode = 1 means SPI is unprotected.
293 */
294bool cse_is_hfs1_spi_protected(void)
295{
296 union me_hfsts1 hfs1;
297 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
298 return !hfs1.fields.mfg_mode;
299}
300
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530301bool cse_is_hfs3_fw_sku_lite(void)
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530302{
303 union me_hfsts3 hfs3;
304 hfs3.data = me_read_config32(PCI_ME_HFSTS3);
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530305 return hfs3.fields.fw_sku == ME_HFS3_FW_SKU_LITE;
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530306}
307
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530308/* Makes the host ready to communicate with CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530309void cse_set_host_ready(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530310{
311 uint32_t csr;
312 csr = read_host_csr();
313 csr &= ~CSR_RESET;
314 csr |= (CSR_IG | CSR_READY);
315 write_host_csr(csr);
316}
317
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530318/* Polls for ME mode ME_HFS1_COM_SECOVER_MEI_MSG for 15 seconds */
319uint8_t cse_wait_sec_override_mode(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530320{
321 struct stopwatch sw;
Subrata Banik03aef282021-09-28 18:10:24 +0530322 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530323 while (!cse_is_hfs1_com_secover_mei_msg()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530324 udelay(HECI_DELAY_US);
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530325 if (stopwatch_expired(&sw)) {
326 printk(BIOS_ERR, "HECI: Timed out waiting for SEC_OVERRIDE mode!\n");
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530327 return 0;
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530328 }
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530329 }
Rob Barnesd522f382022-09-12 06:31:47 -0600330 printk(BIOS_DEBUG, "HECI: CSE took %lld ms to enter security override mode\n",
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530331 stopwatch_duration_msecs(&sw));
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530332 return 1;
333}
334
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530335/*
336 * Polls for CSE's current operation mode 'Soft Temporary Disable'.
337 * The CSE enters the current operation mode when it boots from RO(BP1).
338 */
339uint8_t cse_wait_com_soft_temp_disable(void)
340{
341 struct stopwatch sw;
Subrata Banikf5765812021-09-30 13:37:10 +0530342 stopwatch_init_msecs_expire(&sw, CSE_DELAY_BOOT_TO_RO_MS);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530343 while (!cse_is_hfs1_com_soft_temp_disable()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530344 udelay(HECI_DELAY_US);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530345 if (stopwatch_expired(&sw)) {
346 printk(BIOS_ERR, "HECI: Timed out waiting for CSE to boot from RO!\n");
347 return 0;
348 }
349 }
Rob Barnesd522f382022-09-12 06:31:47 -0600350 printk(BIOS_SPEW, "HECI: CSE took %lld ms to boot from RO\n",
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530351 stopwatch_duration_msecs(&sw));
352 return 1;
353}
354
Andrey Petrov04a72c42017-03-01 15:51:57 -0800355static int wait_heci_ready(void)
356{
357 struct stopwatch sw;
358
Subrata Banik03aef282021-09-28 18:10:24 +0530359 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800360 while (!cse_ready()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530361 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800362 if (stopwatch_expired(&sw))
363 return 0;
364 }
365
366 return 1;
367}
368
369static void host_gen_interrupt(void)
370{
371 uint32_t csr;
372 csr = read_host_csr();
373 csr |= CSR_IG;
374 write_host_csr(csr);
375}
376
377static size_t hdr_get_length(uint32_t hdr)
378{
379 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
380}
381
382static int
383send_one_message(uint32_t hdr, const void *buff)
384{
385 size_t pend_len, pend_slots, remainder, i;
386 uint32_t tmp;
387 const uint32_t *p = buff;
388
389 /* Get space for the header */
390 if (!wait_write_slots(1))
391 return 0;
392
393 /* First, write header */
394 write_slot(hdr);
395
396 pend_len = hdr_get_length(hdr);
397 pend_slots = bytes_to_slots(pend_len);
398
399 if (!wait_write_slots(pend_slots))
400 return 0;
401
402 /* Write the body in whole slots */
403 i = 0;
404 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
405 write_slot(*p++);
406 i += SLOT_SIZE;
407 }
408
409 remainder = pend_len % SLOT_SIZE;
410 /* Pad to 4 bytes not touching caller's buffer */
411 if (remainder) {
412 memcpy(&tmp, p, remainder);
413 write_slot(tmp);
414 }
415
416 host_gen_interrupt();
417
418 /* Make sure nothing bad happened during transmission */
419 if (!cse_ready())
420 return 0;
421
422 return pend_len;
423}
424
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530425/*
426 * Send message msg of size len to host from host_addr to cse_addr.
Sridhar Siricillac760e41a2022-08-15 21:10:58 +0530427 * Returns CSE_TX_RX_SUCCESS on success and other enum values on failure scenarios.
428 * Also, in case of errors, heci_reset() is triggered.
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530429 */
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530430static enum cse_tx_rx_status
Andrey Petrov04a72c42017-03-01 15:51:57 -0800431heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
432{
Subrata Banik5c08c732017-11-13 14:54:37 +0530433 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800434 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530435 size_t sent, remaining, cb_size, max_length;
436 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800437
438 if (!msg || !len)
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530439 return CSE_TX_ERR_INPUT;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800440
441 clear_int();
442
Subrata Banik5c08c732017-11-13 14:54:37 +0530443 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
444 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800445
Subrata Banik5c08c732017-11-13 14:54:37 +0530446 if (!wait_heci_ready()) {
447 printk(BIOS_ERR, "HECI: not ready\n");
448 continue;
449 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800450
Subrata Banik4a722f52017-11-13 14:56:42 +0530451 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530452 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
453 /*
454 * Reserve one slot for the header. Limit max message
455 * length by 9 bits that are available in the header.
456 */
457 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
458 - SLOT_SIZE;
459 remaining = len;
460
461 /*
462 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100463 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530464 */
465 do {
466 hdr = MIN(max_length, remaining)
467 << MEI_HDR_LENGTH_START;
468 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
469 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
470 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800471 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530472 sent = send_one_message(hdr, p);
473 p += sent;
474 remaining -= sent;
475 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800476
Subrata Banik5c08c732017-11-13 14:54:37 +0530477 if (!remaining)
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530478 return CSE_TX_RX_SUCCESS;
Subrata Banik5c08c732017-11-13 14:54:37 +0530479 }
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530480
Sridhar Siricilla1506b772022-03-05 10:02:25 +0530481 printk(BIOS_DEBUG, "HECI: Trigger HECI reset\n");
482 heci_reset();
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530483 return CSE_TX_ERR_CSE_NOT_READY;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800484}
485
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530486static enum cse_tx_rx_status
487recv_one_message(uint32_t *hdr, void *buff, size_t maxlen, size_t *recv_len)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800488{
489 uint32_t reg, *p = buff;
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530490 size_t recv_slots, remainder, i;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800491
492 /* first get the header */
493 if (!wait_read_slots(1))
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530494 return CSE_RX_ERR_TIMEOUT;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800495
496 *hdr = read_slot();
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530497 *recv_len = hdr_get_length(*hdr);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800498
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530499 if (!*recv_len)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800500 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
501
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530502 recv_slots = bytes_to_slots(*recv_len);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800503
504 i = 0;
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530505 if (*recv_len > maxlen) {
Andrey Petrov04a72c42017-03-01 15:51:57 -0800506 printk(BIOS_ERR, "HECI: response is too big\n");
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530507 return CSE_RX_ERR_RESP_LEN_MISMATCH;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800508 }
509
510 /* wait for the rest of messages to arrive */
511 wait_read_slots(recv_slots);
512
513 /* fetch whole slots first */
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530514 while (i < ALIGN_DOWN(*recv_len, SLOT_SIZE)) {
Andrey Petrov04a72c42017-03-01 15:51:57 -0800515 *p++ = read_slot();
516 i += SLOT_SIZE;
517 }
518
Subrata Banik5c08c732017-11-13 14:54:37 +0530519 /*
520 * If ME is not ready, something went wrong and
521 * we received junk
522 */
523 if (!cse_ready())
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530524 return CSE_RX_ERR_CSE_NOT_READY;
Subrata Banik5c08c732017-11-13 14:54:37 +0530525
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530526 remainder = *recv_len % SLOT_SIZE;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800527
528 if (remainder) {
529 reg = read_slot();
530 memcpy(p, &reg, remainder);
531 }
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530532 return CSE_TX_RX_SUCCESS;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800533}
534
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530535/*
536 * Receive message into buff not exceeding maxlen. Message is considered
537 * successfully received if a 'complete' indication is read from ME side
538 * and there was enough space in the buffer to fit that message. maxlen
Sridhar Siricillac760e41a2022-08-15 21:10:58 +0530539 * is updated with size of message that was received.
540 * Returns CSE_TX_RX_SUCCESS on success and other enum values on failure scenarios.
541 * Also, in case of errors, heci_reset() is triggered.
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530542 */
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530543static enum cse_tx_rx_status heci_receive(void *buff, size_t *maxlen)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800544{
Subrata Banik5c08c732017-11-13 14:54:37 +0530545 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800546 size_t left, received;
547 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530548 uint8_t *p;
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530549 enum cse_tx_rx_status ret = CSE_RX_ERR_TIMEOUT;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800550
551 if (!buff || !maxlen || !*maxlen)
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530552 return CSE_RX_ERR_INPUT;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800553
Andrey Petrov04a72c42017-03-01 15:51:57 -0800554 clear_int();
555
Subrata Banik5c08c732017-11-13 14:54:37 +0530556 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
557 p = buff;
558 left = *maxlen;
559
560 if (!wait_heci_ready()) {
561 printk(BIOS_ERR, "HECI: not ready\n");
562 continue;
563 }
564
565 /*
566 * Receive multiple packets until we meet one marked
567 * complete or we run out of space in caller-provided buffer.
568 */
569 do {
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530570 ret = recv_one_message(&hdr, p, left, &received);
571 if (ret) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200572 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Sridhar Siricilla1506b772022-03-05 10:02:25 +0530573 goto CSE_RX_ERR_HANDLE;
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800574 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530575 left -= received;
576 p += received;
577 /* If we read out everything ping to send more */
578 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
579 host_gen_interrupt();
580 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
581
582 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
Elyes Haouas9018dee2022-11-18 15:07:33 +0100583 *maxlen = p - (uint8_t *)buff;
Johnny Lina3e68c92022-08-09 15:36:30 +0800584 if (CONFIG(SOC_INTEL_CSE_SERVER_SKU))
585 clear_int();
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530586 return CSE_TX_RX_SUCCESS;
Subrata Banik5c08c732017-11-13 14:54:37 +0530587 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800588 }
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530589
Sridhar Siricilla1506b772022-03-05 10:02:25 +0530590CSE_RX_ERR_HANDLE:
591 printk(BIOS_DEBUG, "HECI: Trigger HECI Reset\n");
592 heci_reset();
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530593 return CSE_RX_ERR_CSE_NOT_READY;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800594}
595
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530596enum cse_tx_rx_status heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg,
597 size_t *rcv_sz, uint8_t cse_addr)
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530598{
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530599 enum cse_tx_rx_status ret;
600
601 ret = heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, cse_addr);
602 if (ret) {
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530603 printk(BIOS_ERR, "HECI: send Failed\n");
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530604 return ret;
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530605 }
606
607 if (rcv_msg != NULL) {
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530608 ret = heci_receive(rcv_msg, rcv_sz);
609 if (ret) {
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530610 printk(BIOS_ERR, "HECI: receive Failed\n");
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530611 return ret;
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530612 }
613 }
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530614 return ret;
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530615}
616
Andrey Petrov04a72c42017-03-01 15:51:57 -0800617/*
618 * Attempt to reset the device. This is useful when host and ME are out
619 * of sync during transmission or ME didn't understand the message.
620 */
621int heci_reset(void)
622{
623 uint32_t csr;
624
Duncan Laurie15ca9032020-11-05 10:09:07 -0800625 /* Clear post code to prevent eventlog entry from unknown code. */
Martin Roth8c974502022-11-20 17:56:44 -0700626 post_code(POST_CODE_ZERO);
Duncan Laurie15ca9032020-11-05 10:09:07 -0800627
Andrey Petrov04a72c42017-03-01 15:51:57 -0800628 /* Send reset request */
629 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530630 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800631 write_host_csr(csr);
632
633 if (wait_heci_ready()) {
634 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530635 cse_set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800636 return 1;
637 }
638
639 printk(BIOS_CRIT, "HECI: reset failed\n");
640
641 return 0;
642}
643
Subrata Banik3710e992021-09-30 16:59:09 +0530644bool is_cse_devfn_visible(unsigned int devfn)
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530645{
Subrata Banik3710e992021-09-30 16:59:09 +0530646 int slot = PCI_SLOT(devfn);
647 int func = PCI_FUNC(devfn);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530648
Subrata Banik3710e992021-09-30 16:59:09 +0530649 if (!is_devfn_enabled(devfn)) {
650 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is disabled\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530651 return false;
652 }
653
Subrata Banik3710e992021-09-30 16:59:09 +0530654 if (pci_read_config16(PCI_DEV(0, slot, func), PCI_VENDOR_ID) == 0xFFFF) {
655 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is hidden\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530656 return false;
657 }
658
659 return true;
660}
661
Subrata Banik3710e992021-09-30 16:59:09 +0530662bool is_cse_enabled(void)
663{
664 return is_cse_devfn_visible(PCH_DEVFN_CSE);
665}
666
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530667uint32_t me_read_config32(int offset)
668{
669 return pci_read_config32(PCH_DEV_CSE, offset);
670}
671
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530672static bool cse_is_global_reset_allowed(void)
673{
674 /*
675 * Allow sending GLOBAL_RESET command only if:
676 * - CSE's current working state is Normal and current operation mode is Normal.
677 * - (or) CSE's current working state is normal and current operation mode can
678 * be Soft Temp Disable or Security Override Mode if CSE's Firmware SKU is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530679 * Lite.
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530680 */
681 if (!cse_is_hfs1_cws_normal())
682 return false;
683
684 if (cse_is_hfs1_com_normal())
685 return true;
686
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530687 if (cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530688 if (cse_is_hfs1_com_soft_temp_disable() || cse_is_hfs1_com_secover_mei_msg())
689 return true;
690 }
691 return false;
692}
693
Sridhar Siricillad415c202019-08-31 14:54:57 +0530694/*
Subrata Banikf463dc02020-09-14 19:04:03 +0530695 * Sends GLOBAL_RESET_REQ cmd to CSE with reset type GLOBAL_RESET.
696 * Returns 0 on failure and 1 on success.
Sridhar Siricillad415c202019-08-31 14:54:57 +0530697 */
Subrata Banikf463dc02020-09-14 19:04:03 +0530698static int cse_request_reset(enum rst_req_type rst_type)
Sridhar Siricillad415c202019-08-31 14:54:57 +0530699{
700 int status;
701 struct mkhi_hdr reply;
702 struct reset_message {
703 struct mkhi_hdr hdr;
704 uint8_t req_origin;
705 uint8_t reset_type;
706 } __packed;
707 struct reset_message msg = {
708 .hdr = {
709 .group_id = MKHI_GROUP_ID_CBM,
Sridhar Siricillae202e672020-01-07 23:36:40 +0530710 .command = MKHI_CBM_GLOBAL_RESET_REQ,
Sridhar Siricillad415c202019-08-31 14:54:57 +0530711 },
712 .req_origin = GR_ORIGIN_BIOS_POST,
713 .reset_type = rst_type
714 };
715 size_t reply_size;
716
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530717 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530718
Sridhar Siricillac2a2d2b2020-02-27 17:16:13 +0530719 if (!(rst_type == GLOBAL_RESET || rst_type == CSE_RESET_ONLY)) {
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530720 printk(BIOS_ERR, "HECI: Unsupported reset type is requested\n");
721 return 0;
722 }
Sridhar Siricillad415c202019-08-31 14:54:57 +0530723
Subrata Banikf463dc02020-09-14 19:04:03 +0530724 if (!cse_is_global_reset_allowed() || !is_cse_enabled()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530725 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
726 return 0;
727 }
728
Sridhar Siricillad415c202019-08-31 14:54:57 +0530729 heci_reset();
730
731 reply_size = sizeof(reply);
732 memset(&reply, 0, reply_size);
733
Sridhar Siricillad415c202019-08-31 14:54:57 +0530734 if (rst_type == CSE_RESET_ONLY)
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530735 status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530736 else
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530737 status = heci_send_receive(&msg, sizeof(msg), &reply, &reply_size,
738 HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530739
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530740 printk(BIOS_DEBUG, "HECI: Global Reset %s!\n", !status ? "success" : "failure");
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530741 return status;
Sridhar Siricillad415c202019-08-31 14:54:57 +0530742}
743
Subrata Banikf463dc02020-09-14 19:04:03 +0530744int cse_request_global_reset(void)
745{
746 return cse_request_reset(GLOBAL_RESET);
747}
748
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530749static bool cse_is_hmrfpo_enable_allowed(void)
750{
751 /*
752 * Allow sending HMRFPO ENABLE command only if:
753 * - CSE's current working state is Normal and current operation mode is Normal
754 * - (or) cse's current working state is normal and current operation mode is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530755 * Soft Temp Disable if CSE's Firmware SKU is Lite
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530756 */
757 if (!cse_is_hfs1_cws_normal())
758 return false;
759
760 if (cse_is_hfs1_com_normal())
761 return true;
762
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530763 if (cse_is_hfs3_fw_sku_lite() && cse_is_hfs1_com_soft_temp_disable())
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530764 return true;
765
766 return false;
767}
768
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530769/* Sends HMRFPO Enable command to CSE */
Sridhar Siricillaad6d3122023-01-10 14:59:35 +0530770enum cb_err cse_hmrfpo_enable(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530771{
772 struct hmrfpo_enable_msg {
773 struct mkhi_hdr hdr;
774 uint32_t nonce[2];
775 } __packed;
776
777 /* HMRFPO Enable message */
778 struct hmrfpo_enable_msg msg = {
779 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530780 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530781 .command = MKHI_HMRFPO_ENABLE,
782 },
783 .nonce = {0},
784 };
785
786 /* HMRFPO Enable response */
787 struct hmrfpo_enable_resp {
788 struct mkhi_hdr hdr;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530789 /* Base addr for factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530790 uint32_t fct_base;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530791 /* Length of factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530792 uint32_t fct_limit;
793 uint8_t status;
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530794 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530795 } __packed;
796
797 struct hmrfpo_enable_resp resp;
798 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530799
Sridhar Siricilla49c25f22021-11-27 19:56:47 +0530800 if (cse_is_hfs1_com_secover_mei_msg()) {
801 printk(BIOS_DEBUG, "HECI: CSE is already in security override mode, "
802 "skip sending HMRFPO_ENABLE command to CSE\n");
Sridhar Siricillaad6d3122023-01-10 14:59:35 +0530803 return CB_SUCCESS;
Sridhar Siricilla49c25f22021-11-27 19:56:47 +0530804 }
805
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530806 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530807
808 if (!cse_is_hmrfpo_enable_allowed()) {
809 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
Sridhar Siricillaad6d3122023-01-10 14:59:35 +0530810 return CB_ERR;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530811 }
812
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530813 if (heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530814 &resp, &resp_size, HECI_MKHI_ADDR))
Sridhar Siricillaad6d3122023-01-10 14:59:35 +0530815 return CB_ERR;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530816
817 if (resp.hdr.result) {
818 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
Sridhar Siricillaad6d3122023-01-10 14:59:35 +0530819 return CB_ERR;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530820 }
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530821
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530822 if (resp.status) {
823 printk(BIOS_ERR, "HECI: HMRFPO_Enable Failed (resp status: %d)\n", resp.status);
Sridhar Siricillaad6d3122023-01-10 14:59:35 +0530824 return CB_ERR;
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530825 }
826
Sridhar Siricillaad6d3122023-01-10 14:59:35 +0530827 return CB_SUCCESS;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530828}
829
830/*
831 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530832 * The status can be DISABLED/LOCKED/ENABLED
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530833 */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530834int cse_hmrfpo_get_status(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530835{
836 struct hmrfpo_get_status_msg {
837 struct mkhi_hdr hdr;
838 } __packed;
839
840 struct hmrfpo_get_status_resp {
841 struct mkhi_hdr hdr;
842 uint8_t status;
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530843 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530844 } __packed;
845
846 struct hmrfpo_get_status_msg msg = {
847 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530848 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530849 .command = MKHI_HMRFPO_GET_STATUS,
850 },
851 };
852 struct hmrfpo_get_status_resp resp;
853 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
854
855 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
856
Sridhar Siricilla206905c2020-02-06 18:48:22 +0530857 if (!cse_is_hfs1_cws_normal()) {
858 printk(BIOS_ERR, "HECI: CSE's current working state is not Normal\n");
859 return -1;
860 }
861
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530862 if (heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530863 &resp, &resp_size, HECI_MKHI_ADDR)) {
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530864 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
865 return -1;
866 }
867
868 if (resp.hdr.result) {
869 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
870 resp.hdr.result);
871 return -1;
872 }
873
874 return resp.status;
875}
876
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530877void print_me_fw_version(void *unused)
878{
Johnny Lin72e76672021-10-09 12:35:35 +0800879 struct me_fw_ver_resp resp = {0};
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530880
881 /* Ignore if UART debugging is disabled */
882 if (!CONFIG(CONSOLE_SERIAL))
883 return;
884
Johnny Lin72e76672021-10-09 12:35:35 +0800885 if (get_me_fw_version(&resp) == CB_SUCCESS) {
886 printk(BIOS_DEBUG, "ME: Version: %d.%d.%d.%d\n", resp.code.major,
887 resp.code.minor, resp.code.hotfix, resp.code.build);
888 return;
889 }
890 printk(BIOS_DEBUG, "ME: Version: Unavailable\n");
891}
892
893enum cb_err get_me_fw_version(struct me_fw_ver_resp *resp)
894{
895 const struct mkhi_hdr fw_ver_msg = {
896 .group_id = MKHI_GROUP_ID_GEN,
897 .command = MKHI_GEN_GET_FW_VERSION,
898 };
899
900 if (resp == NULL) {
901 printk(BIOS_ERR, "%s failed, null pointer parameter\n", __func__);
902 return CB_ERR;
903 }
904 size_t resp_size = sizeof(*resp);
905
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200906 /* Ignore if CSE is disabled */
907 if (!is_cse_enabled())
Johnny Lin72e76672021-10-09 12:35:35 +0800908 return CB_ERR;
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200909
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530910 /*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530911 * Ignore if ME Firmware SKU type is Lite since
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530912 * print_boot_partition_info() logs RO(BP1) and RW(BP2) versions.
913 */
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530914 if (cse_is_hfs3_fw_sku_lite())
Johnny Lin72e76672021-10-09 12:35:35 +0800915 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530916
917 /*
918 * Prerequisites:
919 * 1) HFSTS1 Current Working State is Normal
920 * 2) HFSTS1 Current Operation Mode is Normal
921 * 3) It's after DRAM INIT DONE message (taken care of by calling it
922 * during ramstage
923 */
924 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal())
Johnny Lin72e76672021-10-09 12:35:35 +0800925 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530926
927 heci_reset();
928
Sridhar Siricilla6836da22022-02-23 23:36:45 +0530929 if (heci_send_receive(&fw_ver_msg, sizeof(fw_ver_msg), resp, &resp_size,
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530930 HECI_MKHI_ADDR))
Johnny Lin72e76672021-10-09 12:35:35 +0800931 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530932
Johnny Lin72e76672021-10-09 12:35:35 +0800933 if (resp->hdr.result)
934 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530935
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530936
Johnny Lin72e76672021-10-09 12:35:35 +0800937 return CB_SUCCESS;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530938}
939
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600940void cse_trigger_vboot_recovery(enum csme_failure_reason reason)
941{
942 printk(BIOS_DEBUG, "cse: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
943 "HFSTS3: 0x%x\n", me_read_config32(PCI_ME_HFSTS1),
944 me_read_config32(PCI_ME_HFSTS2), me_read_config32(PCI_ME_HFSTS3));
945
Jakub Czapiga605f7932022-11-04 12:18:04 +0000946 if (CONFIG(VBOOT))
947 vboot_fail_and_reboot(vboot_get_context(), VB2_RECOVERY_INTEL_CSE_LITE_SKU,
948 reason);
949
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600950 die("cse: Failed to trigger recovery mode(recovery subcode:%d)\n", reason);
951}
952
Subrata Banikc6e25522021-09-30 18:14:09 +0530953static bool disable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530954{
955 struct stopwatch sw;
Subrata Banikc6e25522021-09-30 18:14:09 +0530956 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530957 dev_idle_ctrl &= ~CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530958 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530959
Subrata Banik03aef282021-09-28 18:10:24 +0530960 stopwatch_init_usecs_expire(&sw, HECI_CIP_TIMEOUT_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530961 do {
Subrata Banikc6e25522021-09-30 18:14:09 +0530962 dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530963 if ((dev_idle_ctrl & CSE_DEV_CIP) == CSE_DEV_CIP)
964 return true;
Subrata Banik03aef282021-09-28 18:10:24 +0530965 udelay(HECI_DELAY_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530966 } while (!stopwatch_expired(&sw));
967
968 return false;
969}
970
Subrata Banikc6e25522021-09-30 18:14:09 +0530971static void enable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530972{
Subrata Banikc6e25522021-09-30 18:14:09 +0530973 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530974 dev_idle_ctrl |= CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530975 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530976}
977
Subrata Banikc6e25522021-09-30 18:14:09 +0530978enum cse_device_state get_cse_device_state(unsigned int devfn)
Subrata Banika219edb2021-09-25 15:02:37 +0530979{
Subrata Banikc6e25522021-09-30 18:14:09 +0530980 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
981 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530982 if ((dev_idle_ctrl & CSE_DEV_IDLE) == CSE_DEV_IDLE)
983 return DEV_IDLE;
984
985 return DEV_ACTIVE;
986}
987
Subrata Banikc6e25522021-09-30 18:14:09 +0530988static enum cse_device_state ensure_cse_active(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530989{
Subrata Banikc6e25522021-09-30 18:14:09 +0530990 if (!disable_cse_idle(dev))
Subrata Banika219edb2021-09-25 15:02:37 +0530991 return DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530992 pci_or_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
Subrata Banika219edb2021-09-25 15:02:37 +0530993
994 return DEV_ACTIVE;
995}
996
Subrata Banikc6e25522021-09-30 18:14:09 +0530997static void ensure_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530998{
Subrata Banikc6e25522021-09-30 18:14:09 +0530999 enable_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +05301000
Subrata Banikc6e25522021-09-30 18:14:09 +05301001 pci_and_config32(dev, PCI_COMMAND, ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
Subrata Banika219edb2021-09-25 15:02:37 +05301002}
1003
Subrata Banikc6e25522021-09-30 18:14:09 +05301004bool set_cse_device_state(unsigned int devfn, enum cse_device_state requested_state)
Subrata Banika219edb2021-09-25 15:02:37 +05301005{
Subrata Banikc6e25522021-09-30 18:14:09 +05301006 enum cse_device_state current_state = get_cse_device_state(devfn);
1007 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
Subrata Banika219edb2021-09-25 15:02:37 +05301008
1009 if (current_state == requested_state)
1010 return true;
1011
1012 if (requested_state == DEV_ACTIVE)
Subrata Banikc6e25522021-09-30 18:14:09 +05301013 return ensure_cse_active(dev) == requested_state;
Subrata Banika219edb2021-09-25 15:02:37 +05301014 else
Subrata Banikc6e25522021-09-30 18:14:09 +05301015 ensure_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +05301016
1017 return true;
1018}
1019
Subrata Banik526cc3e2022-01-31 21:55:51 +05301020void cse_set_to_d0i3(void)
1021{
1022 if (!is_cse_devfn_visible(PCH_DEVFN_CSE))
1023 return;
1024
1025 set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE);
1026}
1027
1028/* Function to set D0I3 for all HECI devices */
1029void heci_set_to_d0i3(void)
1030{
1031 for (int i = 0; i < CONFIG_MAX_HECI_DEVICES; i++) {
Subrata Banik57909562022-06-02 00:25:36 +05301032 unsigned int devfn = PCI_DEVFN(PCH_DEV_SLOT_CSE, i);
Subrata Banik01bf0022022-04-06 18:59:37 +05301033 if (!is_cse_devfn_visible(devfn))
Subrata Banik526cc3e2022-01-31 21:55:51 +05301034 continue;
1035
Subrata Banik01bf0022022-04-06 18:59:37 +05301036 set_cse_device_state(devfn, DEV_IDLE);
Subrata Banik526cc3e2022-01-31 21:55:51 +05301037 }
1038}
1039
Subrata Banik801dbf42022-06-01 07:56:40 +00001040/* Initialize the HECI devices. */
1041void heci_init(void)
1042{
1043 for (int i = 0; i < CONFIG_MAX_HECI_DEVICES; i++) {
1044 unsigned int devfn = PCI_DEVFN(PCH_DEV_SLOT_CSE, i);
1045 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
1046
1047 if (!is_cse_devfn_visible(devfn))
1048 continue;
1049
1050 /* Assume it is already initialized, nothing else to do */
1051 if (get_cse_bar(dev))
1052 return;
1053
1054 heci_assign_resource(dev, HECI1_BASE_ADDRESS + (i * HECI_BASE_SIZE));
1055
1056 ensure_cse_active(dev);
1057 }
1058 /* Trigger HECI Reset and make Host ready for communication with CSE */
1059 heci_reset();
1060}
1061
Subrata Banik80c92892022-02-01 00:26:55 +05301062void cse_control_global_reset_lock(void)
1063{
1064 /*
1065 * As per ME BWG recommendation the BIOS should not lock down CF9GR bit during
1066 * manufacturing and re-manufacturing environment if HFSTS1 [4] is set. Note:
1067 * this recommendation is not applicable for CSE-Lite SKUs where BIOS should set
1068 * CF9LOCK bit irrespectively.
1069 *
1070 * Other than that, make sure payload/OS can't trigger global reset.
1071 *
1072 * BIOS must also ensure that CF9GR is cleared and locked (Bit31 of ETR3)
1073 * prior to transferring control to the OS.
1074 */
1075 if (CONFIG(SOC_INTEL_CSE_LITE_SKU) || cse_is_hfs1_spi_protected())
1076 pmc_global_reset_disable_and_lock();
1077 else
1078 pmc_global_reset_enable(false);
1079}
1080
Michał Żygowskidaa17102022-10-04 10:55:38 +02001081enum cb_err cse_get_fw_feature_state(uint32_t *feature_state)
1082{
1083 struct fw_feature_state_msg {
1084 struct mkhi_hdr hdr;
1085 uint32_t rule_id;
1086 } __packed;
1087
1088 /* Get Firmware Feature State message */
1089 struct fw_feature_state_msg msg = {
1090 .hdr = {
1091 .group_id = MKHI_GROUP_ID_FWCAPS,
1092 .command = MKHI_FWCAPS_GET_FW_FEATURE_STATE,
1093 },
1094 .rule_id = ME_FEATURE_STATE_RULE_ID
1095 };
1096
1097 /* Get Firmware Feature State response */
1098 struct fw_feature_state_resp {
1099 struct mkhi_hdr hdr;
1100 uint32_t rule_id;
1101 uint8_t rule_len;
1102 uint32_t fw_runtime_status;
1103 } __packed;
1104
1105 struct fw_feature_state_resp resp;
1106 size_t resp_size = sizeof(struct fw_feature_state_resp);
1107
1108 /* Ignore if CSE is disabled or input buffer is invalid */
1109 if (!is_cse_enabled() || !feature_state)
1110 return CB_ERR;
1111
1112 /*
1113 * Prerequisites:
1114 * 1) HFSTS1 Current Working State is Normal
1115 * 2) HFSTS1 Current Operation Mode is Normal
1116 * 3) It's after DRAM INIT DONE message (taken care of by calling it
1117 * during ramstage)
1118 */
1119 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal() || !ENV_RAMSTAGE)
1120 return CB_ERR;
1121
1122 printk(BIOS_DEBUG, "HECI: Send GET FW FEATURE STATE Command\n");
1123
1124 if (heci_send_receive(&msg, sizeof(struct fw_feature_state_msg),
1125 &resp, &resp_size, HECI_MKHI_ADDR))
1126 return CB_ERR;
1127
1128 if (resp.hdr.result) {
1129 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
1130 return CB_ERR;
1131 }
1132
1133 if (resp.rule_len != sizeof(resp.fw_runtime_status)) {
1134 printk(BIOS_ERR, "HECI: GET FW FEATURE STATE has invalid rule data length\n");
1135 return CB_ERR;
1136 }
1137
1138 *feature_state = resp.fw_runtime_status;
1139
1140 return CB_SUCCESS;
1141}
1142
1143void cse_enable_ptt(bool state)
1144{
1145 struct fw_feature_shipment_override_msg {
1146 struct mkhi_hdr hdr;
1147 uint32_t enable_mask;
1148 uint32_t disable_mask;
1149 } __packed;
1150
1151 /* FW Feature Shipment Time State Override message */
1152 struct fw_feature_shipment_override_msg msg = {
1153 .hdr = {
1154 .group_id = MKHI_GROUP_ID_GEN,
1155 .command = MKHI_GEN_FW_FEATURE_SHIPMENT_OVER,
1156 },
1157 .enable_mask = 0,
1158 .disable_mask = 0
1159 };
1160
1161 /* FW Feature Shipment Time State Override response */
1162 struct fw_feature_shipment_override_resp {
1163 struct mkhi_hdr hdr;
1164 uint32_t data;
1165 } __packed;
1166
1167 struct fw_feature_shipment_override_resp resp;
1168 size_t resp_size = sizeof(struct fw_feature_shipment_override_resp);
1169 uint32_t feature_status;
1170
1171 /* Ignore if CSE is disabled */
1172 if (!is_cse_enabled())
1173 return;
1174
1175 printk(BIOS_DEBUG, "Requested to change PTT state to %sabled\n", state ? "en" : "dis");
1176
1177 /*
1178 * Prerequisites:
1179 * 1) HFSTS1 Current Working State is Normal
1180 * 2) HFSTS1 Current Operation Mode is Normal
1181 * 3) It's after DRAM INIT DONE message (taken care of by calling it
1182 * during ramstage
1183 * 4) HFSTS1 FW Init Complete is set
1184 * 5) Before EOP issued to CSE
1185 */
1186 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal() ||
1187 !cse_is_hfs1_fw_init_complete() || !ENV_RAMSTAGE) {
1188 printk(BIOS_ERR, "HECI: Unmet prerequisites for"
1189 "FW FEATURE SHIPMENT TIME STATE OVERRIDE\n");
1190 return;
1191 }
1192
1193 if (cse_get_fw_feature_state(&feature_status) != CB_SUCCESS) {
1194 printk(BIOS_ERR, "HECI: Cannot determine current feature status\n");
1195 return;
1196 }
1197
1198 if (!!(feature_status & ME_FW_FEATURE_PTT) == state) {
1199 printk(BIOS_DEBUG, "HECI: PTT is already in the requested state\n");
1200 return;
1201 }
1202
1203 printk(BIOS_DEBUG, "HECI: Send FW FEATURE SHIPMENT TIME STATE OVERRIDE Command\n");
1204
1205 if (state)
1206 msg.enable_mask |= ME_FW_FEATURE_PTT;
1207 else
1208 msg.disable_mask |= ME_FW_FEATURE_PTT;
1209
1210 if (heci_send_receive(&msg, sizeof(struct fw_feature_shipment_override_msg),
1211 &resp, &resp_size, HECI_MKHI_ADDR))
1212 return;
1213
1214 if (resp.hdr.result) {
1215 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
1216 return;
1217 }
1218
1219 /* Global reset is required after acceptance of the command */
1220 if (resp.data == 0) {
1221 printk(BIOS_DEBUG, "HECI: FW FEATURE SHIPMENT TIME STATE OVERRIDE success\n");
1222 do_global_reset();
1223 } else {
1224 printk(BIOS_ERR, "HECI: FW FEATURE SHIPMENT TIME STATE OVERRIDE error (%x)\n",
1225 resp.data);
1226 }
1227}
1228
Andrey Petrov04a72c42017-03-01 15:51:57 -08001229#if ENV_RAMSTAGE
1230
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001231/*
1232 * Disable the Intel (CS)Management Engine via HECI based on a cmos value
1233 * of `me_state`. A value of `0` will result in a (CS)ME state of `0` (working)
1234 * and value of `1` will result in a (CS)ME state of `3` (disabled).
1235 *
1236 * It isn't advised to use this in combination with me_cleaner.
1237 *
1238 * It is advisable to have a second cmos option called `me_state_counter`.
1239 * Whilst not essential, it avoid reboots loops if the (CS)ME fails to
1240 * change states after 3 attempts. Some versions of the (CS)ME need to be
1241 * reset 3 times.
1242 *
1243 * Ideal cmos values would be:
1244 *
1245 * # coreboot config options: cpu
1246 * 432 1 e 5 me_state
1247 * 440 4 h 0 me_state_counter
1248 *
1249 * #ID value text
1250 * 5 0 Enable
1251 * 5 1 Disable
1252 */
1253
1254static void me_reset_with_count(void)
1255{
1256 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter", UINT_MAX);
1257
1258 if (cmos_me_state_counter != UINT_MAX) {
1259 printk(BIOS_DEBUG, "CMOS: me_state_counter = %u\n", cmos_me_state_counter);
1260 /* Avoid boot loops by only trying a state change 3 times */
1261 if (cmos_me_state_counter < ME_DISABLE_ATTEMPTS) {
1262 cmos_me_state_counter++;
1263 set_uint_option("me_state_counter", cmos_me_state_counter);
1264 printk(BIOS_DEBUG, "ME: Reset attempt %u/%u.\n", cmos_me_state_counter,
1265 ME_DISABLE_ATTEMPTS);
1266 do_global_reset();
1267 } else {
1268 /*
1269 * If the (CS)ME fails to change states after 3 attempts, it will
1270 * likely need a cold boot, or recovering.
1271 */
Julius Wernere9665952022-01-21 17:06:20 -08001272 printk(BIOS_ERR, "Failed to change ME state in %u attempts!\n",
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001273 ME_DISABLE_ATTEMPTS);
1274
1275 }
1276 } else {
1277 printk(BIOS_DEBUG, "ME: Resetting");
1278 do_global_reset();
1279 }
1280}
1281
1282static void cse_set_state(struct device *dev)
1283{
1284
1285 /* (CS)ME Disable Command */
1286 struct me_disable_command {
1287 struct mkhi_hdr hdr;
1288 uint32_t rule_id;
1289 uint8_t rule_len;
1290 uint32_t rule_data;
1291 } __packed me_disable = {
1292 .hdr = {
1293 .group_id = MKHI_GROUP_ID_FWCAPS,
1294 .command = MKHI_SET_ME_DISABLE,
1295 },
1296 .rule_id = ME_DISABLE_RULE_ID,
1297 .rule_len = ME_DISABLE_RULE_LENGTH,
1298 .rule_data = ME_DISABLE_COMMAND,
1299 };
1300
1301 struct me_disable_reply {
1302 struct mkhi_hdr hdr;
1303 uint32_t rule_id;
1304 } __packed;
1305
1306 struct me_disable_reply disable_reply;
1307
1308 size_t disable_reply_size;
1309
1310 /* (CS)ME Enable Command */
1311 struct me_enable_command {
1312 struct mkhi_hdr hdr;
1313 } me_enable = {
1314 .hdr = {
1315 .group_id = MKHI_GROUP_ID_BUP_COMMON,
1316 .command = MKHI_SET_ME_ENABLE,
1317 },
1318 };
1319
1320 struct me_enable_reply {
1321 struct mkhi_hdr hdr;
1322 } __packed;
1323
1324 struct me_enable_reply enable_reply;
1325
1326 size_t enable_reply_size;
1327
1328 /* Function Start */
1329
1330 int send;
1331 int result;
1332 /*
1333 * Check if the CMOS value "me_state" exists, if it doesn't, then
1334 * don't do anything.
1335 */
1336 const unsigned int cmos_me_state = get_uint_option("me_state", UINT_MAX);
1337
1338 if (cmos_me_state == UINT_MAX)
1339 return;
1340
1341 printk(BIOS_DEBUG, "CMOS: me_state = %u\n", cmos_me_state);
1342
1343 /*
1344 * We only take action if the me_state doesn't match the CS(ME) working state
1345 */
1346
1347 const unsigned int soft_temp_disable = cse_is_hfs1_com_soft_temp_disable();
1348
1349 if (cmos_me_state && !soft_temp_disable) {
1350 /* me_state should be disabled, but it's enabled */
1351 printk(BIOS_DEBUG, "ME needs to be disabled.\n");
1352 send = heci_send_receive(&me_disable, sizeof(me_disable),
1353 &disable_reply, &disable_reply_size, HECI_MKHI_ADDR);
1354 result = disable_reply.hdr.result;
1355 } else if (!cmos_me_state && soft_temp_disable) {
1356 /* me_state should be enabled, but it's disabled */
1357 printk(BIOS_DEBUG, "ME needs to be enabled.\n");
1358 send = heci_send_receive(&me_enable, sizeof(me_enable),
1359 &enable_reply, &enable_reply_size, HECI_MKHI_ADDR);
1360 result = enable_reply.hdr.result;
1361 } else {
1362 printk(BIOS_DEBUG, "ME is %s.\n", cmos_me_state ? "disabled" : "enabled");
1363 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter",
1364 UINT_MAX);
1365 /* set me_state_counter to 0 */
1366 if ((cmos_me_state_counter != UINT_MAX && cmos_me_state_counter != 0))
1367 set_uint_option("me_state_counter", 0);
1368 return;
1369 }
1370
1371 printk(BIOS_DEBUG, "HECI: ME state change send %s!\n",
Sridhar Siricilla6836da22022-02-23 23:36:45 +05301372 !send ? "success" : "failure");
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001373 printk(BIOS_DEBUG, "HECI: ME state change result %s!\n",
1374 result ? "success" : "failure");
1375
1376 /*
1377 * Reset if the result was successful, or if the send failed as some older
1378 * version of the Intel (CS)ME won't successfully receive the message unless reset
1379 * twice.
1380 */
1381 if (send || !result)
1382 me_reset_with_count();
1383}
1384
Subrata Banik90e318b2022-02-06 16:26:45 +05301385/*
1386 * `cse_final_ready_to_boot` function is native implementation of equivalent events
1387 * performed by FSP NotifyPhase(Ready To Boot) API invocations.
1388 *
1389 * Operations are:
Subrata Banik5214c402022-11-24 20:43:37 +05301390 * 1. Perform global reset lock.
1391 * 2. Put HECI1 to D0i3 and disable the HECI1 if the user selects
Subrata Banik670572f2022-04-25 15:39:55 +05301392 * DISABLE_HECI1_AT_PRE_BOOT config or CSE HFSTS1 Operation Mode is
1393 * `Software Temporary Disable`.
Subrata Banik90e318b2022-02-06 16:26:45 +05301394 */
1395static void cse_final_ready_to_boot(void)
1396{
Subrata Banik90e318b2022-02-06 16:26:45 +05301397 cse_control_global_reset_lock();
1398
Subrata Banik670572f2022-04-25 15:39:55 +05301399 if (CONFIG(DISABLE_HECI1_AT_PRE_BOOT) || cse_is_hfs1_com_soft_temp_disable()) {
Subrata Banik90e318b2022-02-06 16:26:45 +05301400 cse_set_to_d0i3();
1401 heci1_disable();
1402 }
1403}
1404
1405/*
1406 * `cse_final_end_of_firmware` function is native implementation of equivalent events
1407 * performed by FSP NotifyPhase(End of Firmware) API invocations.
1408 *
1409 * Operations are:
1410 * 1. Set D0I3 for all HECI devices.
1411 */
1412static void cse_final_end_of_firmware(void)
1413{
1414 heci_set_to_d0i3();
1415}
1416
Subrata Banik90e318b2022-02-06 16:26:45 +05301417/*
Subrata Banik17a3da82022-11-24 21:51:42 +05301418 * This function to perform essential post EOP cse related operations
1419 * upon SoC selecting `SOC_INTEL_CSE_SEND_EOP_LATE` config
1420 */
1421void cse_late_finalize(void)
1422{
1423 if (!CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE))
1424 return;
1425
1426 if (!CONFIG(USE_FSP_NOTIFY_PHASE_READY_TO_BOOT))
1427 cse_final_ready_to_boot();
1428
1429 if (!CONFIG(USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE))
1430 cse_final_end_of_firmware();
1431}
1432
1433/*
Subrata Banik90e318b2022-02-06 16:26:45 +05301434 * `cse_final` function is native implementation of equivalent events performed by
1435 * each FSP NotifyPhase() API invocations.
1436 */
1437static void cse_final(struct device *dev)
1438{
Subrata Banik5214c402022-11-24 20:43:37 +05301439 /* SoC user decided to send EOP late */
1440 if (CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE))
1441 return;
1442
1443 /* 1. Send EOP to CSE if not done.*/
1444 if (CONFIG(SOC_INTEL_CSE_SET_EOP))
1445 cse_send_end_of_post();
1446
Angel Pons28315f82022-04-19 10:03:56 +02001447 if (!CONFIG(USE_FSP_NOTIFY_PHASE_READY_TO_BOOT))
1448 cse_final_ready_to_boot();
1449
1450 if (!CONFIG(USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE))
1451 cse_final_end_of_firmware();
Subrata Banik90e318b2022-02-06 16:26:45 +05301452}
1453
Nico Huber57686192022-08-06 19:11:55 +02001454struct device_operations cse_ops = {
Subrata Banik38abbda2021-09-30 13:15:50 +05301455 .set_resources = pci_dev_set_resources,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001456 .read_resources = pci_dev_read_resources,
1457 .enable_resources = pci_dev_enable_resources,
1458 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +05301459 .ops_pci = &pci_dev_ops_pci,
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001460 .enable = cse_set_state,
Subrata Banik90e318b2022-02-06 16:26:45 +05301461 .final = cse_final,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001462};
1463
Hannah Williams63142152017-06-12 14:03:18 -07001464static const unsigned short pci_device_ids[] = {
Wonkyu Kim9f401072020-11-13 15:16:32 -08001465 PCI_DID_INTEL_MTL_CSE0,
Felix Singer43b7f412022-03-07 04:34:52 +01001466 PCI_DID_INTEL_APL_CSE0,
1467 PCI_DID_INTEL_GLK_CSE0,
1468 PCI_DID_INTEL_CNL_CSE0,
Felix Singer43b7f412022-03-07 04:34:52 +01001469 PCI_DID_INTEL_LWB_CSE0,
1470 PCI_DID_INTEL_LWB_CSE0_SUPER,
1471 PCI_DID_INTEL_CNP_H_CSE0,
Felix Singer43b7f412022-03-07 04:34:52 +01001472 PCI_DID_INTEL_CMP_CSE0,
1473 PCI_DID_INTEL_CMP_H_CSE0,
1474 PCI_DID_INTEL_TGL_CSE0,
1475 PCI_DID_INTEL_TGL_H_CSE0,
1476 PCI_DID_INTEL_MCC_CSE0,
1477 PCI_DID_INTEL_MCC_CSE1,
1478 PCI_DID_INTEL_MCC_CSE2,
1479 PCI_DID_INTEL_MCC_CSE3,
1480 PCI_DID_INTEL_JSP_CSE0,
1481 PCI_DID_INTEL_JSP_CSE1,
1482 PCI_DID_INTEL_JSP_CSE2,
1483 PCI_DID_INTEL_JSP_CSE3,
1484 PCI_DID_INTEL_ADP_P_CSE0,
1485 PCI_DID_INTEL_ADP_P_CSE1,
1486 PCI_DID_INTEL_ADP_P_CSE2,
1487 PCI_DID_INTEL_ADP_P_CSE3,
1488 PCI_DID_INTEL_ADP_S_CSE0,
1489 PCI_DID_INTEL_ADP_S_CSE1,
1490 PCI_DID_INTEL_ADP_S_CSE2,
1491 PCI_DID_INTEL_ADP_S_CSE3,
1492 PCI_DID_INTEL_ADP_M_CSE0,
1493 PCI_DID_INTEL_ADP_M_CSE1,
1494 PCI_DID_INTEL_ADP_M_CSE2,
1495 PCI_DID_INTEL_ADP_M_CSE3,
Hannah Williams63142152017-06-12 14:03:18 -07001496 0,
1497};
1498
Andrey Petrov04a72c42017-03-01 15:51:57 -08001499static const struct pci_driver cse_driver __pci_driver = {
1500 .ops = &cse_ops,
Felix Singer43b7f412022-03-07 04:34:52 +01001501 .vendor = PCI_VID_INTEL,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001502 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -07001503 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -08001504};
1505
1506#endif