blob: b0b2c5adafffdc2eecada5fa273faa7761cba2ca [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>
Subrata Banik80c92892022-02-01 00:26:55 +053014#include <intelblocks/pmclib.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010015#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
Matt DeVillierf711bf02022-01-25 19:48:38 -060098 /* Check if device enabled */
99 if (!is_cse_enabled())
100 return;
101
Andrey Petrov04a72c42017-03-01 15:51:57 -0800102 /* Assume it is already initialized, nothing else to do */
Subrata Banikc6e25522021-09-30 18:14:09 +0530103 if (get_cse_bar(dev))
Andrey Petrov04a72c42017-03-01 15:51:57 -0800104 return;
105
106 /* Use default pre-ram bar */
107 if (!tempbar)
108 tempbar = HECI1_BASE_ADDRESS;
109
110 /* Assign Resources to HECI1 */
111 /* Clear BIT 1-2 of Command Register */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200112 pcireg = pci_read_config16(dev, PCI_COMMAND);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800113 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200114 pci_write_config16(dev, PCI_COMMAND, pcireg);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800115
116 /* Program Temporary BAR for HECI1 */
117 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
118 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
119
120 /* Enable Bus Master and MMIO Space */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200121 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Sridhar Siricillacb2fd202021-06-09 19:27:06 +0530122
123 /* Trigger HECI Reset and make Host ready for communication with CSE */
124 heci_reset();
Subrata Banik05e06cd2017-11-09 15:04:09 +0530125}
126
Subrata Banikc6e25522021-09-30 18:14:09 +0530127static uint32_t read_bar(pci_devfn_t dev, uint32_t offset)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800128{
Subrata Banikc6e25522021-09-30 18:14:09 +0530129 return read32p(get_cse_bar(dev) + offset);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800130}
131
Subrata Banikc6e25522021-09-30 18:14:09 +0530132static void write_bar(pci_devfn_t dev, uint32_t offset, uint32_t val)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800133{
Subrata Banikc6e25522021-09-30 18:14:09 +0530134 return write32p(get_cse_bar(dev) + offset, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800135}
136
137static uint32_t read_cse_csr(void)
138{
Subrata Banikc6e25522021-09-30 18:14:09 +0530139 return read_bar(PCH_DEV_CSE, MMIO_CSE_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800140}
141
142static uint32_t read_host_csr(void)
143{
Subrata Banikc6e25522021-09-30 18:14:09 +0530144 return read_bar(PCH_DEV_CSE, MMIO_HOST_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800145}
146
147static void write_host_csr(uint32_t data)
148{
Subrata Banikc6e25522021-09-30 18:14:09 +0530149 write_bar(PCH_DEV_CSE, MMIO_HOST_CSR, data);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800150}
151
152static size_t filled_slots(uint32_t data)
153{
154 uint8_t wp, rp;
155 rp = data >> CSR_RP_START;
156 wp = data >> CSR_WP_START;
157 return (uint8_t) (wp - rp);
158}
159
160static size_t cse_filled_slots(void)
161{
162 return filled_slots(read_cse_csr());
163}
164
165static size_t host_empty_slots(void)
166{
167 uint32_t csr;
168 csr = read_host_csr();
169
170 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
171}
172
173static void clear_int(void)
174{
175 uint32_t csr;
176 csr = read_host_csr();
177 csr |= CSR_IS;
178 write_host_csr(csr);
179}
180
181static uint32_t read_slot(void)
182{
Subrata Banikc6e25522021-09-30 18:14:09 +0530183 return read_bar(PCH_DEV_CSE, MMIO_CSE_CB_RW);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800184}
185
186static void write_slot(uint32_t val)
187{
Subrata Banikc6e25522021-09-30 18:14:09 +0530188 write_bar(PCH_DEV_CSE, MMIO_CSE_CB_WW, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800189}
190
191static int wait_write_slots(size_t cnt)
192{
193 struct stopwatch sw;
194
Subrata Banik03aef282021-09-28 18:10:24 +0530195 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800196 while (host_empty_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530197 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800198 if (stopwatch_expired(&sw)) {
199 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
200 return 0;
201 }
202 }
203 return 1;
204}
205
206static int wait_read_slots(size_t cnt)
207{
208 struct stopwatch sw;
209
Subrata Banik03aef282021-09-28 18:10:24 +0530210 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800211 while (cse_filled_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530212 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800213 if (stopwatch_expired(&sw)) {
214 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
215 return 0;
216 }
217 }
218 return 1;
219}
220
221/* get number of full 4-byte slots */
222static size_t bytes_to_slots(size_t bytes)
223{
224 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
225}
226
227static int cse_ready(void)
228{
229 uint32_t csr;
230 csr = read_cse_csr();
231 return csr & CSR_READY;
232}
233
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530234static bool cse_check_hfs1_com(int mode)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530235{
236 union me_hfsts1 hfs1;
237 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530238 return hfs1.fields.operation_mode == mode;
239}
240
241bool cse_is_hfs1_cws_normal(void)
242{
243 union me_hfsts1 hfs1;
244 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
245 if (hfs1.fields.working_state == ME_HFS1_CWS_NORMAL)
246 return true;
247 return false;
248}
249
250bool cse_is_hfs1_com_normal(void)
251{
252 return cse_check_hfs1_com(ME_HFS1_COM_NORMAL);
253}
254
255bool cse_is_hfs1_com_secover_mei_msg(void)
256{
257 return cse_check_hfs1_com(ME_HFS1_COM_SECOVER_MEI_MSG);
258}
259
260bool cse_is_hfs1_com_soft_temp_disable(void)
261{
262 return cse_check_hfs1_com(ME_HFS1_COM_SOFT_TEMP_DISABLE);
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530263}
264
Subrata Banike74ebcd2021-12-27 10:49:19 +0000265/*
266 * TGL HFSTS1.spi_protection_mode bit replaces the previous
267 * `manufacturing mode (mfg_mode)` without changing the offset and purpose
268 * of this bit.
269 *
270 * Using HFSTS1.mfg_mode to get the SPI protection status for all PCH.
271 * mfg_mode = 0 means SPI protection in on.
272 * mfg_mode = 1 means SPI is unprotected.
273 */
274bool cse_is_hfs1_spi_protected(void)
275{
276 union me_hfsts1 hfs1;
277 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
278 return !hfs1.fields.mfg_mode;
279}
280
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530281bool cse_is_hfs3_fw_sku_lite(void)
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530282{
283 union me_hfsts3 hfs3;
284 hfs3.data = me_read_config32(PCI_ME_HFSTS3);
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530285 return hfs3.fields.fw_sku == ME_HFS3_FW_SKU_LITE;
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530286}
287
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530288/* Makes the host ready to communicate with CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530289void cse_set_host_ready(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530290{
291 uint32_t csr;
292 csr = read_host_csr();
293 csr &= ~CSR_RESET;
294 csr |= (CSR_IG | CSR_READY);
295 write_host_csr(csr);
296}
297
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530298/* Polls for ME mode ME_HFS1_COM_SECOVER_MEI_MSG for 15 seconds */
299uint8_t cse_wait_sec_override_mode(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530300{
301 struct stopwatch sw;
Subrata Banik03aef282021-09-28 18:10:24 +0530302 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530303 while (!cse_is_hfs1_com_secover_mei_msg()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530304 udelay(HECI_DELAY_US);
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530305 if (stopwatch_expired(&sw)) {
306 printk(BIOS_ERR, "HECI: Timed out waiting for SEC_OVERRIDE mode!\n");
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530307 return 0;
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530308 }
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530309 }
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530310 printk(BIOS_DEBUG, "HECI: CSE took %lu ms to enter security override mode\n",
311 stopwatch_duration_msecs(&sw));
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530312 return 1;
313}
314
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530315/*
316 * Polls for CSE's current operation mode 'Soft Temporary Disable'.
317 * The CSE enters the current operation mode when it boots from RO(BP1).
318 */
319uint8_t cse_wait_com_soft_temp_disable(void)
320{
321 struct stopwatch sw;
Subrata Banikf5765812021-09-30 13:37:10 +0530322 stopwatch_init_msecs_expire(&sw, CSE_DELAY_BOOT_TO_RO_MS);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530323 while (!cse_is_hfs1_com_soft_temp_disable()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530324 udelay(HECI_DELAY_US);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530325 if (stopwatch_expired(&sw)) {
326 printk(BIOS_ERR, "HECI: Timed out waiting for CSE to boot from RO!\n");
327 return 0;
328 }
329 }
330 printk(BIOS_SPEW, "HECI: CSE took %lu ms to boot from RO\n",
331 stopwatch_duration_msecs(&sw));
332 return 1;
333}
334
Andrey Petrov04a72c42017-03-01 15:51:57 -0800335static int wait_heci_ready(void)
336{
337 struct stopwatch sw;
338
Subrata Banik03aef282021-09-28 18:10:24 +0530339 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800340 while (!cse_ready()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530341 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800342 if (stopwatch_expired(&sw))
343 return 0;
344 }
345
346 return 1;
347}
348
349static void host_gen_interrupt(void)
350{
351 uint32_t csr;
352 csr = read_host_csr();
353 csr |= CSR_IG;
354 write_host_csr(csr);
355}
356
357static size_t hdr_get_length(uint32_t hdr)
358{
359 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
360}
361
362static int
363send_one_message(uint32_t hdr, const void *buff)
364{
365 size_t pend_len, pend_slots, remainder, i;
366 uint32_t tmp;
367 const uint32_t *p = buff;
368
369 /* Get space for the header */
370 if (!wait_write_slots(1))
371 return 0;
372
373 /* First, write header */
374 write_slot(hdr);
375
376 pend_len = hdr_get_length(hdr);
377 pend_slots = bytes_to_slots(pend_len);
378
379 if (!wait_write_slots(pend_slots))
380 return 0;
381
382 /* Write the body in whole slots */
383 i = 0;
384 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
385 write_slot(*p++);
386 i += SLOT_SIZE;
387 }
388
389 remainder = pend_len % SLOT_SIZE;
390 /* Pad to 4 bytes not touching caller's buffer */
391 if (remainder) {
392 memcpy(&tmp, p, remainder);
393 write_slot(tmp);
394 }
395
396 host_gen_interrupt();
397
398 /* Make sure nothing bad happened during transmission */
399 if (!cse_ready())
400 return 0;
401
402 return pend_len;
403}
404
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530405/*
406 * Send message msg of size len to host from host_addr to cse_addr.
407 * Returns 1 on success and 0 otherwise.
408 * In case of error heci_reset() may be required.
409 */
410static int
Andrey Petrov04a72c42017-03-01 15:51:57 -0800411heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
412{
Subrata Banik5c08c732017-11-13 14:54:37 +0530413 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800414 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530415 size_t sent, remaining, cb_size, max_length;
416 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800417
418 if (!msg || !len)
419 return 0;
420
421 clear_int();
422
Subrata Banik5c08c732017-11-13 14:54:37 +0530423 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
424 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800425
Subrata Banik5c08c732017-11-13 14:54:37 +0530426 if (!wait_heci_ready()) {
427 printk(BIOS_ERR, "HECI: not ready\n");
428 continue;
429 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800430
Subrata Banik4a722f52017-11-13 14:56:42 +0530431 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530432 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
433 /*
434 * Reserve one slot for the header. Limit max message
435 * length by 9 bits that are available in the header.
436 */
437 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
438 - SLOT_SIZE;
439 remaining = len;
440
441 /*
442 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100443 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530444 */
445 do {
446 hdr = MIN(max_length, remaining)
447 << MEI_HDR_LENGTH_START;
448 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
449 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
450 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800451 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530452 sent = send_one_message(hdr, p);
453 p += sent;
454 remaining -= sent;
455 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800456
Subrata Banik5c08c732017-11-13 14:54:37 +0530457 if (!remaining)
458 return 1;
459 }
460 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800461}
462
463static size_t
464recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
465{
466 uint32_t reg, *p = buff;
467 size_t recv_slots, recv_len, remainder, i;
468
469 /* first get the header */
470 if (!wait_read_slots(1))
471 return 0;
472
473 *hdr = read_slot();
474 recv_len = hdr_get_length(*hdr);
475
476 if (!recv_len)
477 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
478
479 recv_slots = bytes_to_slots(recv_len);
480
481 i = 0;
482 if (recv_len > maxlen) {
483 printk(BIOS_ERR, "HECI: response is too big\n");
484 return 0;
485 }
486
487 /* wait for the rest of messages to arrive */
488 wait_read_slots(recv_slots);
489
490 /* fetch whole slots first */
491 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
492 *p++ = read_slot();
493 i += SLOT_SIZE;
494 }
495
Subrata Banik5c08c732017-11-13 14:54:37 +0530496 /*
497 * If ME is not ready, something went wrong and
498 * we received junk
499 */
500 if (!cse_ready())
501 return 0;
502
Andrey Petrov04a72c42017-03-01 15:51:57 -0800503 remainder = recv_len % SLOT_SIZE;
504
505 if (remainder) {
506 reg = read_slot();
507 memcpy(p, &reg, remainder);
508 }
509
510 return recv_len;
511}
512
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530513/*
514 * Receive message into buff not exceeding maxlen. Message is considered
515 * successfully received if a 'complete' indication is read from ME side
516 * and there was enough space in the buffer to fit that message. maxlen
517 * is updated with size of message that was received. Returns 0 on failure
518 * and 1 on success.
519 * In case of error heci_reset() may be required.
520 */
521static int heci_receive(void *buff, size_t *maxlen)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800522{
Subrata Banik5c08c732017-11-13 14:54:37 +0530523 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800524 size_t left, received;
525 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530526 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800527
528 if (!buff || !maxlen || !*maxlen)
529 return 0;
530
Andrey Petrov04a72c42017-03-01 15:51:57 -0800531 clear_int();
532
Subrata Banik5c08c732017-11-13 14:54:37 +0530533 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
534 p = buff;
535 left = *maxlen;
536
537 if (!wait_heci_ready()) {
538 printk(BIOS_ERR, "HECI: not ready\n");
539 continue;
540 }
541
542 /*
543 * Receive multiple packets until we meet one marked
544 * complete or we run out of space in caller-provided buffer.
545 */
546 do {
547 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800548 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200549 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800550 return 0;
551 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530552 left -= received;
553 p += received;
554 /* If we read out everything ping to send more */
555 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
556 host_gen_interrupt();
557 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
558
559 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
560 *maxlen = p - (uint8_t *) buff;
561 return 1;
562 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800563 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530564 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800565}
566
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530567int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz,
568 uint8_t cse_addr)
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530569{
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530570 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, cse_addr)) {
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530571 printk(BIOS_ERR, "HECI: send Failed\n");
572 return 0;
573 }
574
575 if (rcv_msg != NULL) {
576 if (!heci_receive(rcv_msg, rcv_sz)) {
577 printk(BIOS_ERR, "HECI: receive Failed\n");
578 return 0;
579 }
580 }
581 return 1;
582}
583
Andrey Petrov04a72c42017-03-01 15:51:57 -0800584/*
585 * Attempt to reset the device. This is useful when host and ME are out
586 * of sync during transmission or ME didn't understand the message.
587 */
588int heci_reset(void)
589{
590 uint32_t csr;
591
Duncan Laurie15ca9032020-11-05 10:09:07 -0800592 /* Clear post code to prevent eventlog entry from unknown code. */
593 post_code(0);
594
Andrey Petrov04a72c42017-03-01 15:51:57 -0800595 /* Send reset request */
596 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530597 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800598 write_host_csr(csr);
599
600 if (wait_heci_ready()) {
601 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530602 cse_set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800603 return 1;
604 }
605
606 printk(BIOS_CRIT, "HECI: reset failed\n");
607
608 return 0;
609}
610
Subrata Banik3710e992021-09-30 16:59:09 +0530611bool is_cse_devfn_visible(unsigned int devfn)
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530612{
Subrata Banik3710e992021-09-30 16:59:09 +0530613 int slot = PCI_SLOT(devfn);
614 int func = PCI_FUNC(devfn);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530615
Subrata Banik3710e992021-09-30 16:59:09 +0530616 if (!is_devfn_enabled(devfn)) {
617 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is disabled\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530618 return false;
619 }
620
Subrata Banik3710e992021-09-30 16:59:09 +0530621 if (pci_read_config16(PCI_DEV(0, slot, func), PCI_VENDOR_ID) == 0xFFFF) {
622 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is hidden\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530623 return false;
624 }
625
626 return true;
627}
628
Subrata Banik3710e992021-09-30 16:59:09 +0530629bool is_cse_enabled(void)
630{
631 return is_cse_devfn_visible(PCH_DEVFN_CSE);
632}
633
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530634uint32_t me_read_config32(int offset)
635{
636 return pci_read_config32(PCH_DEV_CSE, offset);
637}
638
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530639static bool cse_is_global_reset_allowed(void)
640{
641 /*
642 * Allow sending GLOBAL_RESET command only if:
643 * - CSE's current working state is Normal and current operation mode is Normal.
644 * - (or) CSE's current working state is normal and current operation mode can
645 * be Soft Temp Disable or Security Override Mode if CSE's Firmware SKU is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530646 * Lite.
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530647 */
648 if (!cse_is_hfs1_cws_normal())
649 return false;
650
651 if (cse_is_hfs1_com_normal())
652 return true;
653
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530654 if (cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530655 if (cse_is_hfs1_com_soft_temp_disable() || cse_is_hfs1_com_secover_mei_msg())
656 return true;
657 }
658 return false;
659}
660
Sridhar Siricillad415c202019-08-31 14:54:57 +0530661/*
Subrata Banikf463dc02020-09-14 19:04:03 +0530662 * Sends GLOBAL_RESET_REQ cmd to CSE with reset type GLOBAL_RESET.
663 * Returns 0 on failure and 1 on success.
Sridhar Siricillad415c202019-08-31 14:54:57 +0530664 */
Subrata Banikf463dc02020-09-14 19:04:03 +0530665static int cse_request_reset(enum rst_req_type rst_type)
Sridhar Siricillad415c202019-08-31 14:54:57 +0530666{
667 int status;
668 struct mkhi_hdr reply;
669 struct reset_message {
670 struct mkhi_hdr hdr;
671 uint8_t req_origin;
672 uint8_t reset_type;
673 } __packed;
674 struct reset_message msg = {
675 .hdr = {
676 .group_id = MKHI_GROUP_ID_CBM,
Sridhar Siricillae202e672020-01-07 23:36:40 +0530677 .command = MKHI_CBM_GLOBAL_RESET_REQ,
Sridhar Siricillad415c202019-08-31 14:54:57 +0530678 },
679 .req_origin = GR_ORIGIN_BIOS_POST,
680 .reset_type = rst_type
681 };
682 size_t reply_size;
683
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530684 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530685
Sridhar Siricillac2a2d2b2020-02-27 17:16:13 +0530686 if (!(rst_type == GLOBAL_RESET || rst_type == CSE_RESET_ONLY)) {
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530687 printk(BIOS_ERR, "HECI: Unsupported reset type is requested\n");
688 return 0;
689 }
Sridhar Siricillad415c202019-08-31 14:54:57 +0530690
Subrata Banikf463dc02020-09-14 19:04:03 +0530691 if (!cse_is_global_reset_allowed() || !is_cse_enabled()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530692 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
693 return 0;
694 }
695
Sridhar Siricillad415c202019-08-31 14:54:57 +0530696 heci_reset();
697
698 reply_size = sizeof(reply);
699 memset(&reply, 0, reply_size);
700
Sridhar Siricillad415c202019-08-31 14:54:57 +0530701 if (rst_type == CSE_RESET_ONLY)
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530702 status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530703 else
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530704 status = heci_send_receive(&msg, sizeof(msg), &reply, &reply_size,
705 HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530706
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530707 printk(BIOS_DEBUG, "HECI: Global Reset %s!\n", status ? "success" : "failure");
708 return status;
Sridhar Siricillad415c202019-08-31 14:54:57 +0530709}
710
Subrata Banikf463dc02020-09-14 19:04:03 +0530711int cse_request_global_reset(void)
712{
713 return cse_request_reset(GLOBAL_RESET);
714}
715
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530716static bool cse_is_hmrfpo_enable_allowed(void)
717{
718 /*
719 * Allow sending HMRFPO ENABLE command only if:
720 * - CSE's current working state is Normal and current operation mode is Normal
721 * - (or) cse's current working state is normal and current operation mode is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530722 * Soft Temp Disable if CSE's Firmware SKU is Lite
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530723 */
724 if (!cse_is_hfs1_cws_normal())
725 return false;
726
727 if (cse_is_hfs1_com_normal())
728 return true;
729
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530730 if (cse_is_hfs3_fw_sku_lite() && cse_is_hfs1_com_soft_temp_disable())
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530731 return true;
732
733 return false;
734}
735
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530736/* Sends HMRFPO Enable command to CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530737int cse_hmrfpo_enable(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530738{
739 struct hmrfpo_enable_msg {
740 struct mkhi_hdr hdr;
741 uint32_t nonce[2];
742 } __packed;
743
744 /* HMRFPO Enable message */
745 struct hmrfpo_enable_msg msg = {
746 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530747 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530748 .command = MKHI_HMRFPO_ENABLE,
749 },
750 .nonce = {0},
751 };
752
753 /* HMRFPO Enable response */
754 struct hmrfpo_enable_resp {
755 struct mkhi_hdr hdr;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530756 /* Base addr for factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530757 uint32_t fct_base;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530758 /* Length of factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530759 uint32_t fct_limit;
760 uint8_t status;
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530761 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530762 } __packed;
763
764 struct hmrfpo_enable_resp resp;
765 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530766
Sridhar Siricilla49c25f22021-11-27 19:56:47 +0530767 if (cse_is_hfs1_com_secover_mei_msg()) {
768 printk(BIOS_DEBUG, "HECI: CSE is already in security override mode, "
769 "skip sending HMRFPO_ENABLE command to CSE\n");
770 return 1;
771 }
772
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530773 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530774
775 if (!cse_is_hmrfpo_enable_allowed()) {
776 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
777 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530778 }
779
780 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530781 &resp, &resp_size, HECI_MKHI_ADDR))
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530782 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530783
784 if (resp.hdr.result) {
785 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530786 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530787 }
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530788
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530789 if (resp.status) {
790 printk(BIOS_ERR, "HECI: HMRFPO_Enable Failed (resp status: %d)\n", resp.status);
791 return 0;
792 }
793
794 return 1;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530795}
796
797/*
798 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530799 * The status can be DISABLED/LOCKED/ENABLED
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530800 */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530801int cse_hmrfpo_get_status(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530802{
803 struct hmrfpo_get_status_msg {
804 struct mkhi_hdr hdr;
805 } __packed;
806
807 struct hmrfpo_get_status_resp {
808 struct mkhi_hdr hdr;
809 uint8_t status;
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530810 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530811 } __packed;
812
813 struct hmrfpo_get_status_msg msg = {
814 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530815 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530816 .command = MKHI_HMRFPO_GET_STATUS,
817 },
818 };
819 struct hmrfpo_get_status_resp resp;
820 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
821
822 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
823
Sridhar Siricilla206905c2020-02-06 18:48:22 +0530824 if (!cse_is_hfs1_cws_normal()) {
825 printk(BIOS_ERR, "HECI: CSE's current working state is not Normal\n");
826 return -1;
827 }
828
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530829 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530830 &resp, &resp_size, HECI_MKHI_ADDR)) {
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530831 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
832 return -1;
833 }
834
835 if (resp.hdr.result) {
836 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
837 resp.hdr.result);
838 return -1;
839 }
840
841 return resp.status;
842}
843
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530844void print_me_fw_version(void *unused)
845{
Johnny Lin72e76672021-10-09 12:35:35 +0800846 struct me_fw_ver_resp resp = {0};
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530847
848 /* Ignore if UART debugging is disabled */
849 if (!CONFIG(CONSOLE_SERIAL))
850 return;
851
Johnny Lin72e76672021-10-09 12:35:35 +0800852 if (get_me_fw_version(&resp) == CB_SUCCESS) {
853 printk(BIOS_DEBUG, "ME: Version: %d.%d.%d.%d\n", resp.code.major,
854 resp.code.minor, resp.code.hotfix, resp.code.build);
855 return;
856 }
857 printk(BIOS_DEBUG, "ME: Version: Unavailable\n");
858}
859
860enum cb_err get_me_fw_version(struct me_fw_ver_resp *resp)
861{
862 const struct mkhi_hdr fw_ver_msg = {
863 .group_id = MKHI_GROUP_ID_GEN,
864 .command = MKHI_GEN_GET_FW_VERSION,
865 };
866
867 if (resp == NULL) {
868 printk(BIOS_ERR, "%s failed, null pointer parameter\n", __func__);
869 return CB_ERR;
870 }
871 size_t resp_size = sizeof(*resp);
872
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200873 /* Ignore if CSE is disabled */
874 if (!is_cse_enabled())
Johnny Lin72e76672021-10-09 12:35:35 +0800875 return CB_ERR;
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200876
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530877 /*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530878 * Ignore if ME Firmware SKU type is Lite since
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530879 * print_boot_partition_info() logs RO(BP1) and RW(BP2) versions.
880 */
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530881 if (cse_is_hfs3_fw_sku_lite())
Johnny Lin72e76672021-10-09 12:35:35 +0800882 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530883
884 /*
885 * Prerequisites:
886 * 1) HFSTS1 Current Working State is Normal
887 * 2) HFSTS1 Current Operation Mode is Normal
888 * 3) It's after DRAM INIT DONE message (taken care of by calling it
889 * during ramstage
890 */
891 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal())
Johnny Lin72e76672021-10-09 12:35:35 +0800892 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530893
894 heci_reset();
895
Johnny Lin72e76672021-10-09 12:35:35 +0800896 if (!heci_send_receive(&fw_ver_msg, sizeof(fw_ver_msg), resp, &resp_size,
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530897 HECI_MKHI_ADDR))
Johnny Lin72e76672021-10-09 12:35:35 +0800898 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530899
Johnny Lin72e76672021-10-09 12:35:35 +0800900 if (resp->hdr.result)
901 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530902
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530903
Johnny Lin72e76672021-10-09 12:35:35 +0800904 return CB_SUCCESS;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530905}
906
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600907void cse_trigger_vboot_recovery(enum csme_failure_reason reason)
908{
909 printk(BIOS_DEBUG, "cse: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
910 "HFSTS3: 0x%x\n", me_read_config32(PCI_ME_HFSTS1),
911 me_read_config32(PCI_ME_HFSTS2), me_read_config32(PCI_ME_HFSTS3));
912
913 if (CONFIG(VBOOT)) {
914 struct vb2_context *ctx = vboot_get_context();
915 if (ctx == NULL)
916 goto failure;
917 vb2api_fail(ctx, VB2_RECOVERY_INTEL_CSE_LITE_SKU, reason);
918 vboot_save_data(ctx);
919 vboot_reboot();
920 }
921failure:
922 die("cse: Failed to trigger recovery mode(recovery subcode:%d)\n", reason);
923}
924
Subrata Banikc6e25522021-09-30 18:14:09 +0530925static bool disable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530926{
927 struct stopwatch sw;
Subrata Banikc6e25522021-09-30 18:14:09 +0530928 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530929 dev_idle_ctrl &= ~CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530930 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530931
Subrata Banik03aef282021-09-28 18:10:24 +0530932 stopwatch_init_usecs_expire(&sw, HECI_CIP_TIMEOUT_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530933 do {
Subrata Banikc6e25522021-09-30 18:14:09 +0530934 dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530935 if ((dev_idle_ctrl & CSE_DEV_CIP) == CSE_DEV_CIP)
936 return true;
Subrata Banik03aef282021-09-28 18:10:24 +0530937 udelay(HECI_DELAY_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530938 } while (!stopwatch_expired(&sw));
939
940 return false;
941}
942
Subrata Banikc6e25522021-09-30 18:14:09 +0530943static void enable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530944{
Subrata Banikc6e25522021-09-30 18:14:09 +0530945 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530946 dev_idle_ctrl |= CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530947 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530948}
949
Subrata Banikc6e25522021-09-30 18:14:09 +0530950enum cse_device_state get_cse_device_state(unsigned int devfn)
Subrata Banika219edb2021-09-25 15:02:37 +0530951{
Subrata Banikc6e25522021-09-30 18:14:09 +0530952 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
953 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530954 if ((dev_idle_ctrl & CSE_DEV_IDLE) == CSE_DEV_IDLE)
955 return DEV_IDLE;
956
957 return DEV_ACTIVE;
958}
959
Subrata Banikc6e25522021-09-30 18:14:09 +0530960static enum cse_device_state ensure_cse_active(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530961{
Subrata Banikc6e25522021-09-30 18:14:09 +0530962 if (!disable_cse_idle(dev))
Subrata Banika219edb2021-09-25 15:02:37 +0530963 return DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530964 pci_or_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
Subrata Banika219edb2021-09-25 15:02:37 +0530965
966 return DEV_ACTIVE;
967}
968
Subrata Banikc6e25522021-09-30 18:14:09 +0530969static void ensure_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530970{
Subrata Banikc6e25522021-09-30 18:14:09 +0530971 enable_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +0530972
Subrata Banikc6e25522021-09-30 18:14:09 +0530973 pci_and_config32(dev, PCI_COMMAND, ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
Subrata Banika219edb2021-09-25 15:02:37 +0530974}
975
Subrata Banikc6e25522021-09-30 18:14:09 +0530976bool set_cse_device_state(unsigned int devfn, enum cse_device_state requested_state)
Subrata Banika219edb2021-09-25 15:02:37 +0530977{
Subrata Banikc6e25522021-09-30 18:14:09 +0530978 enum cse_device_state current_state = get_cse_device_state(devfn);
979 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
Subrata Banika219edb2021-09-25 15:02:37 +0530980
981 if (current_state == requested_state)
982 return true;
983
984 if (requested_state == DEV_ACTIVE)
Subrata Banikc6e25522021-09-30 18:14:09 +0530985 return ensure_cse_active(dev) == requested_state;
Subrata Banika219edb2021-09-25 15:02:37 +0530986 else
Subrata Banikc6e25522021-09-30 18:14:09 +0530987 ensure_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +0530988
989 return true;
990}
991
Subrata Banik526cc3e2022-01-31 21:55:51 +0530992void cse_set_to_d0i3(void)
993{
994 if (!is_cse_devfn_visible(PCH_DEVFN_CSE))
995 return;
996
997 set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE);
998}
999
1000/* Function to set D0I3 for all HECI devices */
1001void heci_set_to_d0i3(void)
1002{
1003 for (int i = 0; i < CONFIG_MAX_HECI_DEVICES; i++) {
1004 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(PCH_DEV_SLOT_CSE), PCI_FUNC(i));
1005 if (!is_cse_devfn_visible(dev))
1006 continue;
1007
1008 set_cse_device_state(dev, DEV_IDLE);
1009 }
1010}
1011
Subrata Banik80c92892022-02-01 00:26:55 +05301012void cse_control_global_reset_lock(void)
1013{
1014 /*
1015 * As per ME BWG recommendation the BIOS should not lock down CF9GR bit during
1016 * manufacturing and re-manufacturing environment if HFSTS1 [4] is set. Note:
1017 * this recommendation is not applicable for CSE-Lite SKUs where BIOS should set
1018 * CF9LOCK bit irrespectively.
1019 *
1020 * Other than that, make sure payload/OS can't trigger global reset.
1021 *
1022 * BIOS must also ensure that CF9GR is cleared and locked (Bit31 of ETR3)
1023 * prior to transferring control to the OS.
1024 */
1025 if (CONFIG(SOC_INTEL_CSE_LITE_SKU) || cse_is_hfs1_spi_protected())
1026 pmc_global_reset_disable_and_lock();
1027 else
1028 pmc_global_reset_enable(false);
1029}
1030
Andrey Petrov04a72c42017-03-01 15:51:57 -08001031#if ENV_RAMSTAGE
1032
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001033/*
1034 * Disable the Intel (CS)Management Engine via HECI based on a cmos value
1035 * of `me_state`. A value of `0` will result in a (CS)ME state of `0` (working)
1036 * and value of `1` will result in a (CS)ME state of `3` (disabled).
1037 *
1038 * It isn't advised to use this in combination with me_cleaner.
1039 *
1040 * It is advisable to have a second cmos option called `me_state_counter`.
1041 * Whilst not essential, it avoid reboots loops if the (CS)ME fails to
1042 * change states after 3 attempts. Some versions of the (CS)ME need to be
1043 * reset 3 times.
1044 *
1045 * Ideal cmos values would be:
1046 *
1047 * # coreboot config options: cpu
1048 * 432 1 e 5 me_state
1049 * 440 4 h 0 me_state_counter
1050 *
1051 * #ID value text
1052 * 5 0 Enable
1053 * 5 1 Disable
1054 */
1055
1056static void me_reset_with_count(void)
1057{
1058 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter", UINT_MAX);
1059
1060 if (cmos_me_state_counter != UINT_MAX) {
1061 printk(BIOS_DEBUG, "CMOS: me_state_counter = %u\n", cmos_me_state_counter);
1062 /* Avoid boot loops by only trying a state change 3 times */
1063 if (cmos_me_state_counter < ME_DISABLE_ATTEMPTS) {
1064 cmos_me_state_counter++;
1065 set_uint_option("me_state_counter", cmos_me_state_counter);
1066 printk(BIOS_DEBUG, "ME: Reset attempt %u/%u.\n", cmos_me_state_counter,
1067 ME_DISABLE_ATTEMPTS);
1068 do_global_reset();
1069 } else {
1070 /*
1071 * If the (CS)ME fails to change states after 3 attempts, it will
1072 * likely need a cold boot, or recovering.
1073 */
Julius Wernere9665952022-01-21 17:06:20 -08001074 printk(BIOS_ERR, "Failed to change ME state in %u attempts!\n",
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001075 ME_DISABLE_ATTEMPTS);
1076
1077 }
1078 } else {
1079 printk(BIOS_DEBUG, "ME: Resetting");
1080 do_global_reset();
1081 }
1082}
1083
1084static void cse_set_state(struct device *dev)
1085{
1086
1087 /* (CS)ME Disable Command */
1088 struct me_disable_command {
1089 struct mkhi_hdr hdr;
1090 uint32_t rule_id;
1091 uint8_t rule_len;
1092 uint32_t rule_data;
1093 } __packed me_disable = {
1094 .hdr = {
1095 .group_id = MKHI_GROUP_ID_FWCAPS,
1096 .command = MKHI_SET_ME_DISABLE,
1097 },
1098 .rule_id = ME_DISABLE_RULE_ID,
1099 .rule_len = ME_DISABLE_RULE_LENGTH,
1100 .rule_data = ME_DISABLE_COMMAND,
1101 };
1102
1103 struct me_disable_reply {
1104 struct mkhi_hdr hdr;
1105 uint32_t rule_id;
1106 } __packed;
1107
1108 struct me_disable_reply disable_reply;
1109
1110 size_t disable_reply_size;
1111
1112 /* (CS)ME Enable Command */
1113 struct me_enable_command {
1114 struct mkhi_hdr hdr;
1115 } me_enable = {
1116 .hdr = {
1117 .group_id = MKHI_GROUP_ID_BUP_COMMON,
1118 .command = MKHI_SET_ME_ENABLE,
1119 },
1120 };
1121
1122 struct me_enable_reply {
1123 struct mkhi_hdr hdr;
1124 } __packed;
1125
1126 struct me_enable_reply enable_reply;
1127
1128 size_t enable_reply_size;
1129
1130 /* Function Start */
1131
1132 int send;
1133 int result;
1134 /*
1135 * Check if the CMOS value "me_state" exists, if it doesn't, then
1136 * don't do anything.
1137 */
1138 const unsigned int cmos_me_state = get_uint_option("me_state", UINT_MAX);
1139
1140 if (cmos_me_state == UINT_MAX)
1141 return;
1142
1143 printk(BIOS_DEBUG, "CMOS: me_state = %u\n", cmos_me_state);
1144
1145 /*
1146 * We only take action if the me_state doesn't match the CS(ME) working state
1147 */
1148
1149 const unsigned int soft_temp_disable = cse_is_hfs1_com_soft_temp_disable();
1150
1151 if (cmos_me_state && !soft_temp_disable) {
1152 /* me_state should be disabled, but it's enabled */
1153 printk(BIOS_DEBUG, "ME needs to be disabled.\n");
1154 send = heci_send_receive(&me_disable, sizeof(me_disable),
1155 &disable_reply, &disable_reply_size, HECI_MKHI_ADDR);
1156 result = disable_reply.hdr.result;
1157 } else if (!cmos_me_state && soft_temp_disable) {
1158 /* me_state should be enabled, but it's disabled */
1159 printk(BIOS_DEBUG, "ME needs to be enabled.\n");
1160 send = heci_send_receive(&me_enable, sizeof(me_enable),
1161 &enable_reply, &enable_reply_size, HECI_MKHI_ADDR);
1162 result = enable_reply.hdr.result;
1163 } else {
1164 printk(BIOS_DEBUG, "ME is %s.\n", cmos_me_state ? "disabled" : "enabled");
1165 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter",
1166 UINT_MAX);
1167 /* set me_state_counter to 0 */
1168 if ((cmos_me_state_counter != UINT_MAX && cmos_me_state_counter != 0))
1169 set_uint_option("me_state_counter", 0);
1170 return;
1171 }
1172
1173 printk(BIOS_DEBUG, "HECI: ME state change send %s!\n",
1174 send ? "success" : "failure");
1175 printk(BIOS_DEBUG, "HECI: ME state change result %s!\n",
1176 result ? "success" : "failure");
1177
1178 /*
1179 * Reset if the result was successful, or if the send failed as some older
1180 * version of the Intel (CS)ME won't successfully receive the message unless reset
1181 * twice.
1182 */
1183 if (send || !result)
1184 me_reset_with_count();
1185}
1186
Subrata Banik90e318b2022-02-06 16:26:45 +05301187struct cse_notify_phase_data {
1188 bool skip;
1189 void (*notify_func)(void);
1190};
1191
1192/*
1193 * `cse_final_ready_to_boot` function is native implementation of equivalent events
1194 * performed by FSP NotifyPhase(Ready To Boot) API invocations.
1195 *
1196 * Operations are:
1197 * 1. Send EOP to CSE if not done.
1198 * 2. Perform global reset lock.
1199 * 3. Put HECI1 to D0i3 and disable the HECI1 if the user selects
1200 * DISABLE_HECI1_AT_PRE_BOOT config.
1201 */
1202static void cse_final_ready_to_boot(void)
1203{
1204 cse_send_end_of_post();
1205
1206 cse_control_global_reset_lock();
1207
1208 if (CONFIG(DISABLE_HECI1_AT_PRE_BOOT)) {
1209 cse_set_to_d0i3();
1210 heci1_disable();
1211 }
1212}
1213
1214/*
1215 * `cse_final_end_of_firmware` function is native implementation of equivalent events
1216 * performed by FSP NotifyPhase(End of Firmware) API invocations.
1217 *
1218 * Operations are:
1219 * 1. Set D0I3 for all HECI devices.
1220 */
1221static void cse_final_end_of_firmware(void)
1222{
1223 heci_set_to_d0i3();
1224}
1225
1226static const struct cse_notify_phase_data notify_data[] = {
1227 {
1228 .skip = CONFIG(USE_FSP_NOTIFY_PHASE_READY_TO_BOOT),
1229 .notify_func = cse_final_ready_to_boot,
1230 },
1231 {
1232 .skip = CONFIG(USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE),
1233 .notify_func = cse_final_end_of_firmware,
1234 },
1235};
1236
1237/*
1238 * `cse_final` function is native implementation of equivalent events performed by
1239 * each FSP NotifyPhase() API invocations.
1240 */
1241static void cse_final(struct device *dev)
1242{
1243 for (size_t i = 0; i < ARRAY_SIZE(notify_data); i++) {
1244 if (!notify_data[i].skip)
1245 return notify_data[i].notify_func();
1246 }
1247}
1248
Andrey Petrov04a72c42017-03-01 15:51:57 -08001249static struct device_operations cse_ops = {
Subrata Banik38abbda2021-09-30 13:15:50 +05301250 .set_resources = pci_dev_set_resources,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001251 .read_resources = pci_dev_read_resources,
1252 .enable_resources = pci_dev_enable_resources,
1253 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +05301254 .ops_pci = &pci_dev_ops_pci,
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001255 .enable = cse_set_state,
Subrata Banik90e318b2022-02-06 16:26:45 +05301256 .final = cse_final,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001257};
1258
Hannah Williams63142152017-06-12 14:03:18 -07001259static const unsigned short pci_device_ids[] = {
Felix Singer43b7f412022-03-07 04:34:52 +01001260 PCI_DID_INTEL_APL_CSE0,
1261 PCI_DID_INTEL_GLK_CSE0,
1262 PCI_DID_INTEL_CNL_CSE0,
1263 PCI_DID_INTEL_SKL_CSE0,
1264 PCI_DID_INTEL_LWB_CSE0,
1265 PCI_DID_INTEL_LWB_CSE0_SUPER,
1266 PCI_DID_INTEL_CNP_H_CSE0,
1267 PCI_DID_INTEL_ICL_CSE0,
1268 PCI_DID_INTEL_CMP_CSE0,
1269 PCI_DID_INTEL_CMP_H_CSE0,
1270 PCI_DID_INTEL_TGL_CSE0,
1271 PCI_DID_INTEL_TGL_H_CSE0,
1272 PCI_DID_INTEL_MCC_CSE0,
1273 PCI_DID_INTEL_MCC_CSE1,
1274 PCI_DID_INTEL_MCC_CSE2,
1275 PCI_DID_INTEL_MCC_CSE3,
1276 PCI_DID_INTEL_JSP_CSE0,
1277 PCI_DID_INTEL_JSP_CSE1,
1278 PCI_DID_INTEL_JSP_CSE2,
1279 PCI_DID_INTEL_JSP_CSE3,
1280 PCI_DID_INTEL_ADP_P_CSE0,
1281 PCI_DID_INTEL_ADP_P_CSE1,
1282 PCI_DID_INTEL_ADP_P_CSE2,
1283 PCI_DID_INTEL_ADP_P_CSE3,
1284 PCI_DID_INTEL_ADP_S_CSE0,
1285 PCI_DID_INTEL_ADP_S_CSE1,
1286 PCI_DID_INTEL_ADP_S_CSE2,
1287 PCI_DID_INTEL_ADP_S_CSE3,
1288 PCI_DID_INTEL_ADP_M_CSE0,
1289 PCI_DID_INTEL_ADP_M_CSE1,
1290 PCI_DID_INTEL_ADP_M_CSE2,
1291 PCI_DID_INTEL_ADP_M_CSE3,
Hannah Williams63142152017-06-12 14:03:18 -07001292 0,
1293};
1294
Andrey Petrov04a72c42017-03-01 15:51:57 -08001295static const struct pci_driver cse_driver __pci_driver = {
1296 .ops = &cse_ops,
Felix Singer43b7f412022-03-07 04:34:52 +01001297 .vendor = PCI_VID_INTEL,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001298 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -07001299 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -08001300};
1301
1302#endif