blob: a9a619c24e40f6f91c26cc5ae820350ad7b03e64 [file] [log] [blame]
Angel Pons0612b272020-04-05 15:46:56 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Andrey Petrov04a72c42017-03-01 15:51:57 -08002
Subrata Banikc6e25522021-09-30 18:14:09 +05303#define __SIMPLE_DEVICE__
4
Subrata Banik05e06cd2017-11-09 15:04:09 +05305#include <assert.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08006#include <commonlib/helpers.h>
7#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02008#include <device/mmio.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -08009#include <delay.h>
10#include <device/pci.h>
11#include <device/pci_ids.h>
12#include <device/pci_ops.h>
13#include <intelblocks/cse.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010014#include <option.h>
Tim Wawrzynczak09635f42021-06-18 10:08:47 -060015#include <security/vboot/misc.h>
16#include <security/vboot/vboot_common.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010017#include <soc/intel/common/reset.h>
Subrata Banik05e06cd2017-11-09 15:04:09 +053018#include <soc/iomap.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080019#include <soc/pci_devs.h>
Sridhar Siricilla8e465452019-09-23 20:59:38 +053020#include <soc/me.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080021#include <string.h>
22#include <timer.h>
Sean Rhodes69ed3ed2021-04-30 16:38:17 +010023#include <types.h>
Andrey Petrov04a72c42017-03-01 15:51:57 -080024
Subrata Banik5c08c732017-11-13 14:54:37 +053025#define MAX_HECI_MESSAGE_RETRY_COUNT 5
26
Andrey Petrov04a72c42017-03-01 15:51:57 -080027/* Wait up to 15 sec for HECI to get ready */
Subrata Banik03aef282021-09-28 18:10:24 +053028#define HECI_DELAY_READY_MS (15 * 1000)
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +010029/* Wait up to 100 usec between circular buffer polls */
Subrata Banik03aef282021-09-28 18:10:24 +053030#define HECI_DELAY_US 100
Andrey Petrov04a72c42017-03-01 15:51:57 -080031/* Wait up to 5 sec for CSE to chew something we sent */
Subrata Banik03aef282021-09-28 18:10:24 +053032#define HECI_SEND_TIMEOUT_MS (5 * 1000)
Andrey Petrov04a72c42017-03-01 15:51:57 -080033/* Wait up to 5 sec for CSE to blurp a reply */
Subrata Banik03aef282021-09-28 18:10:24 +053034#define HECI_READ_TIMEOUT_MS (5 * 1000)
Subrata Banika219edb2021-09-25 15:02:37 +053035/* Wait up to 1 ms for CSE CIP */
Subrata Banik03aef282021-09-28 18:10:24 +053036#define HECI_CIP_TIMEOUT_US 1000
Subrata Banikf5765812021-09-30 13:37:10 +053037/* Wait up to 5 seconds for CSE to boot from RO(BP1) */
38#define CSE_DELAY_BOOT_TO_RO_MS (5 * 1000)
Andrey Petrov04a72c42017-03-01 15:51:57 -080039
40#define SLOT_SIZE sizeof(uint32_t)
41
42#define MMIO_CSE_CB_WW 0x00
43#define MMIO_HOST_CSR 0x04
44#define MMIO_CSE_CB_RW 0x08
45#define MMIO_CSE_CSR 0x0c
Subrata Banika219edb2021-09-25 15:02:37 +053046#define MMIO_CSE_DEVIDLE 0x800
47#define CSE_DEV_IDLE (1 << 2)
48#define CSE_DEV_CIP (1 << 0)
Andrey Petrov04a72c42017-03-01 15:51:57 -080049
50#define CSR_IE (1 << 0)
51#define CSR_IS (1 << 1)
52#define CSR_IG (1 << 2)
53#define CSR_READY (1 << 3)
54#define CSR_RESET (1 << 4)
55#define CSR_RP_START 8
56#define CSR_RP (((1 << 8) - 1) << CSR_RP_START)
57#define CSR_WP_START 16
58#define CSR_WP (((1 << 8) - 1) << CSR_WP_START)
59#define CSR_CBD_START 24
60#define CSR_CBD (((1 << 8) - 1) << CSR_CBD_START)
61
62#define MEI_HDR_IS_COMPLETE (1 << 31)
63#define MEI_HDR_LENGTH_START 16
64#define MEI_HDR_LENGTH_SIZE 9
65#define MEI_HDR_LENGTH (((1 << MEI_HDR_LENGTH_SIZE) - 1) \
66 << MEI_HDR_LENGTH_START)
67#define MEI_HDR_HOST_ADDR_START 8
68#define MEI_HDR_HOST_ADDR (((1 << 8) - 1) << MEI_HDR_HOST_ADDR_START)
69#define MEI_HDR_CSE_ADDR_START 0
70#define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START)
71
Subrata Banik38abbda2021-09-30 13:15:50 +053072/* Get HECI BAR 0 from PCI configuration space */
Subrata Banikc6e25522021-09-30 18:14:09 +053073static uintptr_t get_cse_bar(pci_devfn_t dev)
Subrata Banik38abbda2021-09-30 13:15:50 +053074{
75 uintptr_t bar;
76
Subrata Banikc6e25522021-09-30 18:14:09 +053077 bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
Subrata Banik38abbda2021-09-30 13:15:50 +053078 assert(bar != 0);
79 /*
80 * Bits 31-12 are the base address as per EDS for SPI,
81 * Don't care about 0-11 bit
82 */
83 return bar & ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
84}
Andrey Petrov04a72c42017-03-01 15:51:57 -080085
86/*
87 * Initialize the device with provided temporary BAR. If BAR is 0 use a
88 * default. This is intended for pre-mem usage only where BARs haven't been
89 * assigned yet and devices are not enabled.
90 */
91void heci_init(uintptr_t tempbar)
92{
Elyes HAOUAS68c851b2018-06-12 22:06:09 +020093 pci_devfn_t dev = PCH_DEV_CSE;
Subrata Banikc6e25522021-09-30 18:14:09 +053094
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +020095 u16 pcireg;
Andrey Petrov04a72c42017-03-01 15:51:57 -080096
Matt DeVillierf711bf02022-01-25 19:48:38 -060097 /* Check if device enabled */
98 if (!is_cse_enabled())
99 return;
100
Andrey Petrov04a72c42017-03-01 15:51:57 -0800101 /* Assume it is already initialized, nothing else to do */
Subrata Banikc6e25522021-09-30 18:14:09 +0530102 if (get_cse_bar(dev))
Andrey Petrov04a72c42017-03-01 15:51:57 -0800103 return;
104
105 /* Use default pre-ram bar */
106 if (!tempbar)
107 tempbar = HECI1_BASE_ADDRESS;
108
109 /* Assign Resources to HECI1 */
110 /* Clear BIT 1-2 of Command Register */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200111 pcireg = pci_read_config16(dev, PCI_COMMAND);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800112 pcireg &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200113 pci_write_config16(dev, PCI_COMMAND, pcireg);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800114
115 /* Program Temporary BAR for HECI1 */
116 pci_write_config32(dev, PCI_BASE_ADDRESS_0, tempbar);
117 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0x0);
118
119 /* Enable Bus Master and MMIO Space */
Elyes HAOUAS2ec1c132020-04-29 09:57:05 +0200120 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
Sridhar Siricillacb2fd202021-06-09 19:27:06 +0530121
122 /* Trigger HECI Reset and make Host ready for communication with CSE */
123 heci_reset();
Subrata Banik05e06cd2017-11-09 15:04:09 +0530124}
125
Subrata Banikc6e25522021-09-30 18:14:09 +0530126static uint32_t read_bar(pci_devfn_t dev, uint32_t offset)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800127{
Subrata Banikc6e25522021-09-30 18:14:09 +0530128 return read32p(get_cse_bar(dev) + offset);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800129}
130
Subrata Banikc6e25522021-09-30 18:14:09 +0530131static void write_bar(pci_devfn_t dev, uint32_t offset, uint32_t val)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800132{
Subrata Banikc6e25522021-09-30 18:14:09 +0530133 return write32p(get_cse_bar(dev) + offset, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800134}
135
136static uint32_t read_cse_csr(void)
137{
Subrata Banikc6e25522021-09-30 18:14:09 +0530138 return read_bar(PCH_DEV_CSE, MMIO_CSE_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800139}
140
141static uint32_t read_host_csr(void)
142{
Subrata Banikc6e25522021-09-30 18:14:09 +0530143 return read_bar(PCH_DEV_CSE, MMIO_HOST_CSR);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800144}
145
146static void write_host_csr(uint32_t data)
147{
Subrata Banikc6e25522021-09-30 18:14:09 +0530148 write_bar(PCH_DEV_CSE, MMIO_HOST_CSR, data);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800149}
150
151static size_t filled_slots(uint32_t data)
152{
153 uint8_t wp, rp;
154 rp = data >> CSR_RP_START;
155 wp = data >> CSR_WP_START;
156 return (uint8_t) (wp - rp);
157}
158
159static size_t cse_filled_slots(void)
160{
161 return filled_slots(read_cse_csr());
162}
163
164static size_t host_empty_slots(void)
165{
166 uint32_t csr;
167 csr = read_host_csr();
168
169 return ((csr & CSR_CBD) >> CSR_CBD_START) - filled_slots(csr);
170}
171
172static void clear_int(void)
173{
174 uint32_t csr;
175 csr = read_host_csr();
176 csr |= CSR_IS;
177 write_host_csr(csr);
178}
179
180static uint32_t read_slot(void)
181{
Subrata Banikc6e25522021-09-30 18:14:09 +0530182 return read_bar(PCH_DEV_CSE, MMIO_CSE_CB_RW);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800183}
184
185static void write_slot(uint32_t val)
186{
Subrata Banikc6e25522021-09-30 18:14:09 +0530187 write_bar(PCH_DEV_CSE, MMIO_CSE_CB_WW, val);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800188}
189
190static int wait_write_slots(size_t cnt)
191{
192 struct stopwatch sw;
193
Subrata Banik03aef282021-09-28 18:10:24 +0530194 stopwatch_init_msecs_expire(&sw, HECI_SEND_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800195 while (host_empty_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530196 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800197 if (stopwatch_expired(&sw)) {
198 printk(BIOS_ERR, "HECI: timeout, buffer not drained\n");
199 return 0;
200 }
201 }
202 return 1;
203}
204
205static int wait_read_slots(size_t cnt)
206{
207 struct stopwatch sw;
208
Subrata Banik03aef282021-09-28 18:10:24 +0530209 stopwatch_init_msecs_expire(&sw, HECI_READ_TIMEOUT_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800210 while (cse_filled_slots() < cnt) {
Subrata Banik03aef282021-09-28 18:10:24 +0530211 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800212 if (stopwatch_expired(&sw)) {
213 printk(BIOS_ERR, "HECI: timed out reading answer!\n");
214 return 0;
215 }
216 }
217 return 1;
218}
219
220/* get number of full 4-byte slots */
221static size_t bytes_to_slots(size_t bytes)
222{
223 return ALIGN_UP(bytes, SLOT_SIZE) / SLOT_SIZE;
224}
225
226static int cse_ready(void)
227{
228 uint32_t csr;
229 csr = read_cse_csr();
230 return csr & CSR_READY;
231}
232
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530233static bool cse_check_hfs1_com(int mode)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530234{
235 union me_hfsts1 hfs1;
236 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530237 return hfs1.fields.operation_mode == mode;
238}
239
240bool cse_is_hfs1_cws_normal(void)
241{
242 union me_hfsts1 hfs1;
243 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
244 if (hfs1.fields.working_state == ME_HFS1_CWS_NORMAL)
245 return true;
246 return false;
247}
248
249bool cse_is_hfs1_com_normal(void)
250{
251 return cse_check_hfs1_com(ME_HFS1_COM_NORMAL);
252}
253
254bool cse_is_hfs1_com_secover_mei_msg(void)
255{
256 return cse_check_hfs1_com(ME_HFS1_COM_SECOVER_MEI_MSG);
257}
258
259bool cse_is_hfs1_com_soft_temp_disable(void)
260{
261 return cse_check_hfs1_com(ME_HFS1_COM_SOFT_TEMP_DISABLE);
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530262}
263
Subrata Banike74ebcd2021-12-27 10:49:19 +0000264/*
265 * TGL HFSTS1.spi_protection_mode bit replaces the previous
266 * `manufacturing mode (mfg_mode)` without changing the offset and purpose
267 * of this bit.
268 *
269 * Using HFSTS1.mfg_mode to get the SPI protection status for all PCH.
270 * mfg_mode = 0 means SPI protection in on.
271 * mfg_mode = 1 means SPI is unprotected.
272 */
273bool cse_is_hfs1_spi_protected(void)
274{
275 union me_hfsts1 hfs1;
276 hfs1.data = me_read_config32(PCI_ME_HFSTS1);
277 return !hfs1.fields.mfg_mode;
278}
279
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530280bool cse_is_hfs3_fw_sku_lite(void)
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530281{
282 union me_hfsts3 hfs3;
283 hfs3.data = me_read_config32(PCI_ME_HFSTS3);
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530284 return hfs3.fields.fw_sku == ME_HFS3_FW_SKU_LITE;
Sridhar Siricilla3465d272020-02-06 15:31:04 +0530285}
286
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530287/* Makes the host ready to communicate with CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530288void cse_set_host_ready(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530289{
290 uint32_t csr;
291 csr = read_host_csr();
292 csr &= ~CSR_RESET;
293 csr |= (CSR_IG | CSR_READY);
294 write_host_csr(csr);
295}
296
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530297/* Polls for ME mode ME_HFS1_COM_SECOVER_MEI_MSG for 15 seconds */
298uint8_t cse_wait_sec_override_mode(void)
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530299{
300 struct stopwatch sw;
Subrata Banik03aef282021-09-28 18:10:24 +0530301 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Sridhar Siricilla8e465452019-09-23 20:59:38 +0530302 while (!cse_is_hfs1_com_secover_mei_msg()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530303 udelay(HECI_DELAY_US);
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530304 if (stopwatch_expired(&sw)) {
305 printk(BIOS_ERR, "HECI: Timed out waiting for SEC_OVERRIDE mode!\n");
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530306 return 0;
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530307 }
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530308 }
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530309 printk(BIOS_DEBUG, "HECI: CSE took %lu ms to enter security override mode\n",
310 stopwatch_duration_msecs(&sw));
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530311 return 1;
312}
313
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530314/*
315 * Polls for CSE's current operation mode 'Soft Temporary Disable'.
316 * The CSE enters the current operation mode when it boots from RO(BP1).
317 */
318uint8_t cse_wait_com_soft_temp_disable(void)
319{
320 struct stopwatch sw;
Subrata Banikf5765812021-09-30 13:37:10 +0530321 stopwatch_init_msecs_expire(&sw, CSE_DELAY_BOOT_TO_RO_MS);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530322 while (!cse_is_hfs1_com_soft_temp_disable()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530323 udelay(HECI_DELAY_US);
Sridhar Siricilla09ea3712019-11-12 23:35:50 +0530324 if (stopwatch_expired(&sw)) {
325 printk(BIOS_ERR, "HECI: Timed out waiting for CSE to boot from RO!\n");
326 return 0;
327 }
328 }
329 printk(BIOS_SPEW, "HECI: CSE took %lu ms to boot from RO\n",
330 stopwatch_duration_msecs(&sw));
331 return 1;
332}
333
Andrey Petrov04a72c42017-03-01 15:51:57 -0800334static int wait_heci_ready(void)
335{
336 struct stopwatch sw;
337
Subrata Banik03aef282021-09-28 18:10:24 +0530338 stopwatch_init_msecs_expire(&sw, HECI_DELAY_READY_MS);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800339 while (!cse_ready()) {
Subrata Banik03aef282021-09-28 18:10:24 +0530340 udelay(HECI_DELAY_US);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800341 if (stopwatch_expired(&sw))
342 return 0;
343 }
344
345 return 1;
346}
347
348static void host_gen_interrupt(void)
349{
350 uint32_t csr;
351 csr = read_host_csr();
352 csr |= CSR_IG;
353 write_host_csr(csr);
354}
355
356static size_t hdr_get_length(uint32_t hdr)
357{
358 return (hdr & MEI_HDR_LENGTH) >> MEI_HDR_LENGTH_START;
359}
360
361static int
362send_one_message(uint32_t hdr, const void *buff)
363{
364 size_t pend_len, pend_slots, remainder, i;
365 uint32_t tmp;
366 const uint32_t *p = buff;
367
368 /* Get space for the header */
369 if (!wait_write_slots(1))
370 return 0;
371
372 /* First, write header */
373 write_slot(hdr);
374
375 pend_len = hdr_get_length(hdr);
376 pend_slots = bytes_to_slots(pend_len);
377
378 if (!wait_write_slots(pend_slots))
379 return 0;
380
381 /* Write the body in whole slots */
382 i = 0;
383 while (i < ALIGN_DOWN(pend_len, SLOT_SIZE)) {
384 write_slot(*p++);
385 i += SLOT_SIZE;
386 }
387
388 remainder = pend_len % SLOT_SIZE;
389 /* Pad to 4 bytes not touching caller's buffer */
390 if (remainder) {
391 memcpy(&tmp, p, remainder);
392 write_slot(tmp);
393 }
394
395 host_gen_interrupt();
396
397 /* Make sure nothing bad happened during transmission */
398 if (!cse_ready())
399 return 0;
400
401 return pend_len;
402}
403
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530404/*
405 * Send message msg of size len to host from host_addr to cse_addr.
406 * Returns 1 on success and 0 otherwise.
407 * In case of error heci_reset() may be required.
408 */
409static int
Andrey Petrov04a72c42017-03-01 15:51:57 -0800410heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
411{
Subrata Banik5c08c732017-11-13 14:54:37 +0530412 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800413 uint32_t csr, hdr;
Subrata Banik5c08c732017-11-13 14:54:37 +0530414 size_t sent, remaining, cb_size, max_length;
415 const uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800416
417 if (!msg || !len)
418 return 0;
419
420 clear_int();
421
Subrata Banik5c08c732017-11-13 14:54:37 +0530422 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
423 p = msg;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800424
Subrata Banik5c08c732017-11-13 14:54:37 +0530425 if (!wait_heci_ready()) {
426 printk(BIOS_ERR, "HECI: not ready\n");
427 continue;
428 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800429
Subrata Banik4a722f52017-11-13 14:56:42 +0530430 csr = read_host_csr();
Subrata Banik5c08c732017-11-13 14:54:37 +0530431 cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
432 /*
433 * Reserve one slot for the header. Limit max message
434 * length by 9 bits that are available in the header.
435 */
436 max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
437 - SLOT_SIZE;
438 remaining = len;
439
440 /*
441 * Fragment the message into smaller messages not exceeding
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100442 * useful circular buffer length. Mark last message complete.
Subrata Banik5c08c732017-11-13 14:54:37 +0530443 */
444 do {
445 hdr = MIN(max_length, remaining)
446 << MEI_HDR_LENGTH_START;
447 hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
448 hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
449 hdr |= (MIN(max_length, remaining) == remaining) ?
Lee Leahy68ab0b52017-03-10 13:42:34 -0800450 MEI_HDR_IS_COMPLETE : 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530451 sent = send_one_message(hdr, p);
452 p += sent;
453 remaining -= sent;
454 } while (remaining > 0 && sent != 0);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800455
Subrata Banik5c08c732017-11-13 14:54:37 +0530456 if (!remaining)
457 return 1;
458 }
459 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800460}
461
462static size_t
463recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
464{
465 uint32_t reg, *p = buff;
466 size_t recv_slots, recv_len, remainder, i;
467
468 /* first get the header */
469 if (!wait_read_slots(1))
470 return 0;
471
472 *hdr = read_slot();
473 recv_len = hdr_get_length(*hdr);
474
475 if (!recv_len)
476 printk(BIOS_WARNING, "HECI: message is zero-sized\n");
477
478 recv_slots = bytes_to_slots(recv_len);
479
480 i = 0;
481 if (recv_len > maxlen) {
482 printk(BIOS_ERR, "HECI: response is too big\n");
483 return 0;
484 }
485
486 /* wait for the rest of messages to arrive */
487 wait_read_slots(recv_slots);
488
489 /* fetch whole slots first */
490 while (i < ALIGN_DOWN(recv_len, SLOT_SIZE)) {
491 *p++ = read_slot();
492 i += SLOT_SIZE;
493 }
494
Subrata Banik5c08c732017-11-13 14:54:37 +0530495 /*
496 * If ME is not ready, something went wrong and
497 * we received junk
498 */
499 if (!cse_ready())
500 return 0;
501
Andrey Petrov04a72c42017-03-01 15:51:57 -0800502 remainder = recv_len % SLOT_SIZE;
503
504 if (remainder) {
505 reg = read_slot();
506 memcpy(p, &reg, remainder);
507 }
508
509 return recv_len;
510}
511
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530512/*
513 * Receive message into buff not exceeding maxlen. Message is considered
514 * successfully received if a 'complete' indication is read from ME side
515 * and there was enough space in the buffer to fit that message. maxlen
516 * is updated with size of message that was received. Returns 0 on failure
517 * and 1 on success.
518 * In case of error heci_reset() may be required.
519 */
520static int heci_receive(void *buff, size_t *maxlen)
Andrey Petrov04a72c42017-03-01 15:51:57 -0800521{
Subrata Banik5c08c732017-11-13 14:54:37 +0530522 uint8_t retry;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800523 size_t left, received;
524 uint32_t hdr = 0;
Subrata Banik5c08c732017-11-13 14:54:37 +0530525 uint8_t *p;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800526
527 if (!buff || !maxlen || !*maxlen)
528 return 0;
529
Andrey Petrov04a72c42017-03-01 15:51:57 -0800530 clear_int();
531
Subrata Banik5c08c732017-11-13 14:54:37 +0530532 for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
533 p = buff;
534 left = *maxlen;
535
536 if (!wait_heci_ready()) {
537 printk(BIOS_ERR, "HECI: not ready\n");
538 continue;
539 }
540
541 /*
542 * Receive multiple packets until we meet one marked
543 * complete or we run out of space in caller-provided buffer.
544 */
545 do {
546 received = recv_one_message(&hdr, p, left);
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800547 if (!received) {
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200548 printk(BIOS_ERR, "HECI: Failed to receive!\n");
Lijian Zhaoc50296d2017-12-15 19:10:18 -0800549 return 0;
550 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530551 left -= received;
552 p += received;
553 /* If we read out everything ping to send more */
554 if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
555 host_gen_interrupt();
556 } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
557
558 if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
559 *maxlen = p - (uint8_t *) buff;
560 return 1;
561 }
Andrey Petrov04a72c42017-03-01 15:51:57 -0800562 }
Subrata Banik5c08c732017-11-13 14:54:37 +0530563 return 0;
Andrey Petrov04a72c42017-03-01 15:51:57 -0800564}
565
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530566int heci_send_receive(const void *snd_msg, size_t snd_sz, void *rcv_msg, size_t *rcv_sz,
567 uint8_t cse_addr)
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530568{
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530569 if (!heci_send(snd_msg, snd_sz, BIOS_HOST_ADDR, cse_addr)) {
Sridhar Siricillaa5208f52019-08-30 17:10:24 +0530570 printk(BIOS_ERR, "HECI: send Failed\n");
571 return 0;
572 }
573
574 if (rcv_msg != NULL) {
575 if (!heci_receive(rcv_msg, rcv_sz)) {
576 printk(BIOS_ERR, "HECI: receive Failed\n");
577 return 0;
578 }
579 }
580 return 1;
581}
582
Andrey Petrov04a72c42017-03-01 15:51:57 -0800583/*
584 * Attempt to reset the device. This is useful when host and ME are out
585 * of sync during transmission or ME didn't understand the message.
586 */
587int heci_reset(void)
588{
589 uint32_t csr;
590
Duncan Laurie15ca9032020-11-05 10:09:07 -0800591 /* Clear post code to prevent eventlog entry from unknown code. */
592 post_code(0);
593
Andrey Petrov04a72c42017-03-01 15:51:57 -0800594 /* Send reset request */
595 csr = read_host_csr();
Sridhar Siricillab9d075b2019-08-31 11:38:33 +0530596 csr |= (CSR_RESET | CSR_IG);
Andrey Petrov04a72c42017-03-01 15:51:57 -0800597 write_host_csr(csr);
598
599 if (wait_heci_ready()) {
600 /* Device is back on its imaginary feet, clear reset */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530601 cse_set_host_ready();
Andrey Petrov04a72c42017-03-01 15:51:57 -0800602 return 1;
603 }
604
605 printk(BIOS_CRIT, "HECI: reset failed\n");
606
607 return 0;
608}
609
Subrata Banik3710e992021-09-30 16:59:09 +0530610bool is_cse_devfn_visible(unsigned int devfn)
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530611{
Subrata Banik3710e992021-09-30 16:59:09 +0530612 int slot = PCI_SLOT(devfn);
613 int func = PCI_FUNC(devfn);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530614
Subrata Banik3710e992021-09-30 16:59:09 +0530615 if (!is_devfn_enabled(devfn)) {
616 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is disabled\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530617 return false;
618 }
619
Subrata Banik3710e992021-09-30 16:59:09 +0530620 if (pci_read_config16(PCI_DEV(0, slot, func), PCI_VENDOR_ID) == 0xFFFF) {
621 printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is hidden\n", slot, func);
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530622 return false;
623 }
624
625 return true;
626}
627
Subrata Banik3710e992021-09-30 16:59:09 +0530628bool is_cse_enabled(void)
629{
630 return is_cse_devfn_visible(PCH_DEVFN_CSE);
631}
632
Sridhar Siricilla2cc66912019-08-31 11:20:34 +0530633uint32_t me_read_config32(int offset)
634{
635 return pci_read_config32(PCH_DEV_CSE, offset);
636}
637
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530638static bool cse_is_global_reset_allowed(void)
639{
640 /*
641 * Allow sending GLOBAL_RESET command only if:
642 * - CSE's current working state is Normal and current operation mode is Normal.
643 * - (or) CSE's current working state is normal and current operation mode can
644 * be Soft Temp Disable or Security Override Mode if CSE's Firmware SKU is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530645 * Lite.
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530646 */
647 if (!cse_is_hfs1_cws_normal())
648 return false;
649
650 if (cse_is_hfs1_com_normal())
651 return true;
652
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530653 if (cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530654 if (cse_is_hfs1_com_soft_temp_disable() || cse_is_hfs1_com_secover_mei_msg())
655 return true;
656 }
657 return false;
658}
659
Sridhar Siricillad415c202019-08-31 14:54:57 +0530660/*
Subrata Banikf463dc02020-09-14 19:04:03 +0530661 * Sends GLOBAL_RESET_REQ cmd to CSE with reset type GLOBAL_RESET.
662 * Returns 0 on failure and 1 on success.
Sridhar Siricillad415c202019-08-31 14:54:57 +0530663 */
Subrata Banikf463dc02020-09-14 19:04:03 +0530664static int cse_request_reset(enum rst_req_type rst_type)
Sridhar Siricillad415c202019-08-31 14:54:57 +0530665{
666 int status;
667 struct mkhi_hdr reply;
668 struct reset_message {
669 struct mkhi_hdr hdr;
670 uint8_t req_origin;
671 uint8_t reset_type;
672 } __packed;
673 struct reset_message msg = {
674 .hdr = {
675 .group_id = MKHI_GROUP_ID_CBM,
Sridhar Siricillae202e672020-01-07 23:36:40 +0530676 .command = MKHI_CBM_GLOBAL_RESET_REQ,
Sridhar Siricillad415c202019-08-31 14:54:57 +0530677 },
678 .req_origin = GR_ORIGIN_BIOS_POST,
679 .reset_type = rst_type
680 };
681 size_t reply_size;
682
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530683 printk(BIOS_DEBUG, "HECI: Global Reset(Type:%d) Command\n", rst_type);
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530684
Sridhar Siricillac2a2d2b2020-02-27 17:16:13 +0530685 if (!(rst_type == GLOBAL_RESET || rst_type == CSE_RESET_ONLY)) {
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530686 printk(BIOS_ERR, "HECI: Unsupported reset type is requested\n");
687 return 0;
688 }
Sridhar Siricillad415c202019-08-31 14:54:57 +0530689
Subrata Banikf463dc02020-09-14 19:04:03 +0530690 if (!cse_is_global_reset_allowed() || !is_cse_enabled()) {
Sridhar Siricilla59c7cb7d2020-02-07 11:59:30 +0530691 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
692 return 0;
693 }
694
Sridhar Siricillad415c202019-08-31 14:54:57 +0530695 heci_reset();
696
697 reply_size = sizeof(reply);
698 memset(&reply, 0, reply_size);
699
Sridhar Siricillad415c202019-08-31 14:54:57 +0530700 if (rst_type == CSE_RESET_ONLY)
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530701 status = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530702 else
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530703 status = heci_send_receive(&msg, sizeof(msg), &reply, &reply_size,
704 HECI_MKHI_ADDR);
Sridhar Siricillad415c202019-08-31 14:54:57 +0530705
Sridhar Siricillaf2eb6872019-12-05 19:54:16 +0530706 printk(BIOS_DEBUG, "HECI: Global Reset %s!\n", status ? "success" : "failure");
707 return status;
Sridhar Siricillad415c202019-08-31 14:54:57 +0530708}
709
Subrata Banikf463dc02020-09-14 19:04:03 +0530710int cse_request_global_reset(void)
711{
712 return cse_request_reset(GLOBAL_RESET);
713}
714
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530715static bool cse_is_hmrfpo_enable_allowed(void)
716{
717 /*
718 * Allow sending HMRFPO ENABLE command only if:
719 * - CSE's current working state is Normal and current operation mode is Normal
720 * - (or) cse's current working state is normal and current operation mode is
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530721 * Soft Temp Disable if CSE's Firmware SKU is Lite
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530722 */
723 if (!cse_is_hfs1_cws_normal())
724 return false;
725
726 if (cse_is_hfs1_com_normal())
727 return true;
728
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530729 if (cse_is_hfs3_fw_sku_lite() && cse_is_hfs1_com_soft_temp_disable())
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530730 return true;
731
732 return false;
733}
734
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530735/* Sends HMRFPO Enable command to CSE */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530736int cse_hmrfpo_enable(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530737{
738 struct hmrfpo_enable_msg {
739 struct mkhi_hdr hdr;
740 uint32_t nonce[2];
741 } __packed;
742
743 /* HMRFPO Enable message */
744 struct hmrfpo_enable_msg msg = {
745 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530746 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530747 .command = MKHI_HMRFPO_ENABLE,
748 },
749 .nonce = {0},
750 };
751
752 /* HMRFPO Enable response */
753 struct hmrfpo_enable_resp {
754 struct mkhi_hdr hdr;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530755 /* Base addr for factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530756 uint32_t fct_base;
Sridhar Siricillae202e672020-01-07 23:36:40 +0530757 /* Length of factory data area, not relevant for client SKUs */
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530758 uint32_t fct_limit;
759 uint8_t status;
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530760 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530761 } __packed;
762
763 struct hmrfpo_enable_resp resp;
764 size_t resp_size = sizeof(struct hmrfpo_enable_resp);
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530765
Sridhar Siricilla49c25f22021-11-27 19:56:47 +0530766 if (cse_is_hfs1_com_secover_mei_msg()) {
767 printk(BIOS_DEBUG, "HECI: CSE is already in security override mode, "
768 "skip sending HMRFPO_ENABLE command to CSE\n");
769 return 1;
770 }
771
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530772 printk(BIOS_DEBUG, "HECI: Send HMRFPO Enable Command\n");
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530773
774 if (!cse_is_hmrfpo_enable_allowed()) {
775 printk(BIOS_ERR, "HECI: CSE does not meet required prerequisites\n");
776 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530777 }
778
779 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_enable_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530780 &resp, &resp_size, HECI_MKHI_ADDR))
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530781 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530782
783 if (resp.hdr.result) {
784 printk(BIOS_ERR, "HECI: Resp Failed:%d\n", resp.hdr.result);
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530785 return 0;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530786 }
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530787
Sridhar Siricillad16187e2019-11-27 16:02:47 +0530788 if (resp.status) {
789 printk(BIOS_ERR, "HECI: HMRFPO_Enable Failed (resp status: %d)\n", resp.status);
790 return 0;
791 }
792
793 return 1;
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530794}
795
796/*
797 * Sends HMRFPO Get Status command to CSE to get the HMRFPO status.
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530798 * The status can be DISABLED/LOCKED/ENABLED
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530799 */
Sridhar Siricillaff072e62019-11-27 14:55:16 +0530800int cse_hmrfpo_get_status(void)
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530801{
802 struct hmrfpo_get_status_msg {
803 struct mkhi_hdr hdr;
804 } __packed;
805
806 struct hmrfpo_get_status_resp {
807 struct mkhi_hdr hdr;
808 uint8_t status;
Sridhar Siricilla63be9182020-01-19 12:38:56 +0530809 uint8_t reserved[3];
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530810 } __packed;
811
812 struct hmrfpo_get_status_msg msg = {
813 .hdr = {
Sridhar Siricillae202e672020-01-07 23:36:40 +0530814 .group_id = MKHI_GROUP_ID_HMRFPO,
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530815 .command = MKHI_HMRFPO_GET_STATUS,
816 },
817 };
818 struct hmrfpo_get_status_resp resp;
819 size_t resp_size = sizeof(struct hmrfpo_get_status_resp);
820
821 printk(BIOS_INFO, "HECI: Sending Get HMRFPO Status Command\n");
822
Sridhar Siricilla206905c2020-02-06 18:48:22 +0530823 if (!cse_is_hfs1_cws_normal()) {
824 printk(BIOS_ERR, "HECI: CSE's current working state is not Normal\n");
825 return -1;
826 }
827
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530828 if (!heci_send_receive(&msg, sizeof(struct hmrfpo_get_status_msg),
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530829 &resp, &resp_size, HECI_MKHI_ADDR)) {
Sridhar Siricillae30a0e62019-08-31 16:12:21 +0530830 printk(BIOS_ERR, "HECI: HMRFPO send/receive fail\n");
831 return -1;
832 }
833
834 if (resp.hdr.result) {
835 printk(BIOS_ERR, "HECI: HMRFPO Resp Failed:%d\n",
836 resp.hdr.result);
837 return -1;
838 }
839
840 return resp.status;
841}
842
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530843void print_me_fw_version(void *unused)
844{
Johnny Lin72e76672021-10-09 12:35:35 +0800845 struct me_fw_ver_resp resp = {0};
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530846
847 /* Ignore if UART debugging is disabled */
848 if (!CONFIG(CONSOLE_SERIAL))
849 return;
850
Johnny Lin72e76672021-10-09 12:35:35 +0800851 if (get_me_fw_version(&resp) == CB_SUCCESS) {
852 printk(BIOS_DEBUG, "ME: Version: %d.%d.%d.%d\n", resp.code.major,
853 resp.code.minor, resp.code.hotfix, resp.code.build);
854 return;
855 }
856 printk(BIOS_DEBUG, "ME: Version: Unavailable\n");
857}
858
859enum cb_err get_me_fw_version(struct me_fw_ver_resp *resp)
860{
861 const struct mkhi_hdr fw_ver_msg = {
862 .group_id = MKHI_GROUP_ID_GEN,
863 .command = MKHI_GEN_GET_FW_VERSION,
864 };
865
866 if (resp == NULL) {
867 printk(BIOS_ERR, "%s failed, null pointer parameter\n", __func__);
868 return CB_ERR;
869 }
870 size_t resp_size = sizeof(*resp);
871
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200872 /* Ignore if CSE is disabled */
873 if (!is_cse_enabled())
Johnny Lin72e76672021-10-09 12:35:35 +0800874 return CB_ERR;
Wim Vervoorn8602fb72020-03-30 12:17:54 +0200875
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530876 /*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530877 * Ignore if ME Firmware SKU type is Lite since
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530878 * print_boot_partition_info() logs RO(BP1) and RW(BP2) versions.
879 */
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530880 if (cse_is_hfs3_fw_sku_lite())
Johnny Lin72e76672021-10-09 12:35:35 +0800881 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530882
883 /*
884 * Prerequisites:
885 * 1) HFSTS1 Current Working State is Normal
886 * 2) HFSTS1 Current Operation Mode is Normal
887 * 3) It's after DRAM INIT DONE message (taken care of by calling it
888 * during ramstage
889 */
890 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal())
Johnny Lin72e76672021-10-09 12:35:35 +0800891 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530892
893 heci_reset();
894
Johnny Lin72e76672021-10-09 12:35:35 +0800895 if (!heci_send_receive(&fw_ver_msg, sizeof(fw_ver_msg), resp, &resp_size,
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530896 HECI_MKHI_ADDR))
Johnny Lin72e76672021-10-09 12:35:35 +0800897 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530898
Johnny Lin72e76672021-10-09 12:35:35 +0800899 if (resp->hdr.result)
900 return CB_ERR;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530901
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530902
Johnny Lin72e76672021-10-09 12:35:35 +0800903 return CB_SUCCESS;
Sridhar Siricilla24a974a2020-02-19 14:41:36 +0530904}
905
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600906void cse_trigger_vboot_recovery(enum csme_failure_reason reason)
907{
908 printk(BIOS_DEBUG, "cse: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
909 "HFSTS3: 0x%x\n", me_read_config32(PCI_ME_HFSTS1),
910 me_read_config32(PCI_ME_HFSTS2), me_read_config32(PCI_ME_HFSTS3));
911
912 if (CONFIG(VBOOT)) {
913 struct vb2_context *ctx = vboot_get_context();
914 if (ctx == NULL)
915 goto failure;
916 vb2api_fail(ctx, VB2_RECOVERY_INTEL_CSE_LITE_SKU, reason);
917 vboot_save_data(ctx);
918 vboot_reboot();
919 }
920failure:
921 die("cse: Failed to trigger recovery mode(recovery subcode:%d)\n", reason);
922}
923
Subrata Banikc6e25522021-09-30 18:14:09 +0530924static bool disable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530925{
926 struct stopwatch sw;
Subrata Banikc6e25522021-09-30 18:14:09 +0530927 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530928 dev_idle_ctrl &= ~CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530929 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530930
Subrata Banik03aef282021-09-28 18:10:24 +0530931 stopwatch_init_usecs_expire(&sw, HECI_CIP_TIMEOUT_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530932 do {
Subrata Banikc6e25522021-09-30 18:14:09 +0530933 dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530934 if ((dev_idle_ctrl & CSE_DEV_CIP) == CSE_DEV_CIP)
935 return true;
Subrata Banik03aef282021-09-28 18:10:24 +0530936 udelay(HECI_DELAY_US);
Subrata Banika219edb2021-09-25 15:02:37 +0530937 } while (!stopwatch_expired(&sw));
938
939 return false;
940}
941
Subrata Banikc6e25522021-09-30 18:14:09 +0530942static void enable_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530943{
Subrata Banikc6e25522021-09-30 18:14:09 +0530944 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530945 dev_idle_ctrl |= CSE_DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530946 write_bar(dev, MMIO_CSE_DEVIDLE, dev_idle_ctrl);
Subrata Banika219edb2021-09-25 15:02:37 +0530947}
948
Subrata Banikc6e25522021-09-30 18:14:09 +0530949enum cse_device_state get_cse_device_state(unsigned int devfn)
Subrata Banika219edb2021-09-25 15:02:37 +0530950{
Subrata Banikc6e25522021-09-30 18:14:09 +0530951 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
952 uint32_t dev_idle_ctrl = read_bar(dev, MMIO_CSE_DEVIDLE);
Subrata Banika219edb2021-09-25 15:02:37 +0530953 if ((dev_idle_ctrl & CSE_DEV_IDLE) == CSE_DEV_IDLE)
954 return DEV_IDLE;
955
956 return DEV_ACTIVE;
957}
958
Subrata Banikc6e25522021-09-30 18:14:09 +0530959static enum cse_device_state ensure_cse_active(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530960{
Subrata Banikc6e25522021-09-30 18:14:09 +0530961 if (!disable_cse_idle(dev))
Subrata Banika219edb2021-09-25 15:02:37 +0530962 return DEV_IDLE;
Subrata Banikc6e25522021-09-30 18:14:09 +0530963 pci_or_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
Subrata Banika219edb2021-09-25 15:02:37 +0530964
965 return DEV_ACTIVE;
966}
967
Subrata Banikc6e25522021-09-30 18:14:09 +0530968static void ensure_cse_idle(pci_devfn_t dev)
Subrata Banika219edb2021-09-25 15:02:37 +0530969{
Subrata Banikc6e25522021-09-30 18:14:09 +0530970 enable_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +0530971
Subrata Banikc6e25522021-09-30 18:14:09 +0530972 pci_and_config32(dev, PCI_COMMAND, ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
Subrata Banika219edb2021-09-25 15:02:37 +0530973}
974
Subrata Banikc6e25522021-09-30 18:14:09 +0530975bool set_cse_device_state(unsigned int devfn, enum cse_device_state requested_state)
Subrata Banika219edb2021-09-25 15:02:37 +0530976{
Subrata Banikc6e25522021-09-30 18:14:09 +0530977 enum cse_device_state current_state = get_cse_device_state(devfn);
978 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
Subrata Banika219edb2021-09-25 15:02:37 +0530979
980 if (current_state == requested_state)
981 return true;
982
983 if (requested_state == DEV_ACTIVE)
Subrata Banikc6e25522021-09-30 18:14:09 +0530984 return ensure_cse_active(dev) == requested_state;
Subrata Banika219edb2021-09-25 15:02:37 +0530985 else
Subrata Banikc6e25522021-09-30 18:14:09 +0530986 ensure_cse_idle(dev);
Subrata Banika219edb2021-09-25 15:02:37 +0530987
988 return true;
989}
990
Subrata Banik526cc3e2022-01-31 21:55:51 +0530991void cse_set_to_d0i3(void)
992{
993 if (!is_cse_devfn_visible(PCH_DEVFN_CSE))
994 return;
995
996 set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE);
997}
998
999/* Function to set D0I3 for all HECI devices */
1000void heci_set_to_d0i3(void)
1001{
1002 for (int i = 0; i < CONFIG_MAX_HECI_DEVICES; i++) {
1003 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(PCH_DEV_SLOT_CSE), PCI_FUNC(i));
1004 if (!is_cse_devfn_visible(dev))
1005 continue;
1006
1007 set_cse_device_state(dev, DEV_IDLE);
1008 }
1009}
1010
Andrey Petrov04a72c42017-03-01 15:51:57 -08001011#if ENV_RAMSTAGE
1012
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001013/*
1014 * Disable the Intel (CS)Management Engine via HECI based on a cmos value
1015 * of `me_state`. A value of `0` will result in a (CS)ME state of `0` (working)
1016 * and value of `1` will result in a (CS)ME state of `3` (disabled).
1017 *
1018 * It isn't advised to use this in combination with me_cleaner.
1019 *
1020 * It is advisable to have a second cmos option called `me_state_counter`.
1021 * Whilst not essential, it avoid reboots loops if the (CS)ME fails to
1022 * change states after 3 attempts. Some versions of the (CS)ME need to be
1023 * reset 3 times.
1024 *
1025 * Ideal cmos values would be:
1026 *
1027 * # coreboot config options: cpu
1028 * 432 1 e 5 me_state
1029 * 440 4 h 0 me_state_counter
1030 *
1031 * #ID value text
1032 * 5 0 Enable
1033 * 5 1 Disable
1034 */
1035
1036static void me_reset_with_count(void)
1037{
1038 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter", UINT_MAX);
1039
1040 if (cmos_me_state_counter != UINT_MAX) {
1041 printk(BIOS_DEBUG, "CMOS: me_state_counter = %u\n", cmos_me_state_counter);
1042 /* Avoid boot loops by only trying a state change 3 times */
1043 if (cmos_me_state_counter < ME_DISABLE_ATTEMPTS) {
1044 cmos_me_state_counter++;
1045 set_uint_option("me_state_counter", cmos_me_state_counter);
1046 printk(BIOS_DEBUG, "ME: Reset attempt %u/%u.\n", cmos_me_state_counter,
1047 ME_DISABLE_ATTEMPTS);
1048 do_global_reset();
1049 } else {
1050 /*
1051 * If the (CS)ME fails to change states after 3 attempts, it will
1052 * likely need a cold boot, or recovering.
1053 */
Julius Wernere9665952022-01-21 17:06:20 -08001054 printk(BIOS_ERR, "Failed to change ME state in %u attempts!\n",
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001055 ME_DISABLE_ATTEMPTS);
1056
1057 }
1058 } else {
1059 printk(BIOS_DEBUG, "ME: Resetting");
1060 do_global_reset();
1061 }
1062}
1063
1064static void cse_set_state(struct device *dev)
1065{
1066
1067 /* (CS)ME Disable Command */
1068 struct me_disable_command {
1069 struct mkhi_hdr hdr;
1070 uint32_t rule_id;
1071 uint8_t rule_len;
1072 uint32_t rule_data;
1073 } __packed me_disable = {
1074 .hdr = {
1075 .group_id = MKHI_GROUP_ID_FWCAPS,
1076 .command = MKHI_SET_ME_DISABLE,
1077 },
1078 .rule_id = ME_DISABLE_RULE_ID,
1079 .rule_len = ME_DISABLE_RULE_LENGTH,
1080 .rule_data = ME_DISABLE_COMMAND,
1081 };
1082
1083 struct me_disable_reply {
1084 struct mkhi_hdr hdr;
1085 uint32_t rule_id;
1086 } __packed;
1087
1088 struct me_disable_reply disable_reply;
1089
1090 size_t disable_reply_size;
1091
1092 /* (CS)ME Enable Command */
1093 struct me_enable_command {
1094 struct mkhi_hdr hdr;
1095 } me_enable = {
1096 .hdr = {
1097 .group_id = MKHI_GROUP_ID_BUP_COMMON,
1098 .command = MKHI_SET_ME_ENABLE,
1099 },
1100 };
1101
1102 struct me_enable_reply {
1103 struct mkhi_hdr hdr;
1104 } __packed;
1105
1106 struct me_enable_reply enable_reply;
1107
1108 size_t enable_reply_size;
1109
1110 /* Function Start */
1111
1112 int send;
1113 int result;
1114 /*
1115 * Check if the CMOS value "me_state" exists, if it doesn't, then
1116 * don't do anything.
1117 */
1118 const unsigned int cmos_me_state = get_uint_option("me_state", UINT_MAX);
1119
1120 if (cmos_me_state == UINT_MAX)
1121 return;
1122
1123 printk(BIOS_DEBUG, "CMOS: me_state = %u\n", cmos_me_state);
1124
1125 /*
1126 * We only take action if the me_state doesn't match the CS(ME) working state
1127 */
1128
1129 const unsigned int soft_temp_disable = cse_is_hfs1_com_soft_temp_disable();
1130
1131 if (cmos_me_state && !soft_temp_disable) {
1132 /* me_state should be disabled, but it's enabled */
1133 printk(BIOS_DEBUG, "ME needs to be disabled.\n");
1134 send = heci_send_receive(&me_disable, sizeof(me_disable),
1135 &disable_reply, &disable_reply_size, HECI_MKHI_ADDR);
1136 result = disable_reply.hdr.result;
1137 } else if (!cmos_me_state && soft_temp_disable) {
1138 /* me_state should be enabled, but it's disabled */
1139 printk(BIOS_DEBUG, "ME needs to be enabled.\n");
1140 send = heci_send_receive(&me_enable, sizeof(me_enable),
1141 &enable_reply, &enable_reply_size, HECI_MKHI_ADDR);
1142 result = enable_reply.hdr.result;
1143 } else {
1144 printk(BIOS_DEBUG, "ME is %s.\n", cmos_me_state ? "disabled" : "enabled");
1145 unsigned int cmos_me_state_counter = get_uint_option("me_state_counter",
1146 UINT_MAX);
1147 /* set me_state_counter to 0 */
1148 if ((cmos_me_state_counter != UINT_MAX && cmos_me_state_counter != 0))
1149 set_uint_option("me_state_counter", 0);
1150 return;
1151 }
1152
1153 printk(BIOS_DEBUG, "HECI: ME state change send %s!\n",
1154 send ? "success" : "failure");
1155 printk(BIOS_DEBUG, "HECI: ME state change result %s!\n",
1156 result ? "success" : "failure");
1157
1158 /*
1159 * Reset if the result was successful, or if the send failed as some older
1160 * version of the Intel (CS)ME won't successfully receive the message unless reset
1161 * twice.
1162 */
1163 if (send || !result)
1164 me_reset_with_count();
1165}
1166
Andrey Petrov04a72c42017-03-01 15:51:57 -08001167static struct device_operations cse_ops = {
Subrata Banik38abbda2021-09-30 13:15:50 +05301168 .set_resources = pci_dev_set_resources,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001169 .read_resources = pci_dev_read_resources,
1170 .enable_resources = pci_dev_enable_resources,
1171 .init = pci_dev_init,
Subrata Banik6bbc91a2017-12-07 14:55:51 +05301172 .ops_pci = &pci_dev_ops_pci,
Sean Rhodes69ed3ed2021-04-30 16:38:17 +01001173 .enable = cse_set_state,
Andrey Petrov04a72c42017-03-01 15:51:57 -08001174};
1175
Hannah Williams63142152017-06-12 14:03:18 -07001176static const unsigned short pci_device_ids[] = {
1177 PCI_DEVICE_ID_INTEL_APL_CSE0,
1178 PCI_DEVICE_ID_INTEL_GLK_CSE0,
Andrey Petrov0405de92017-06-05 13:25:29 -07001179 PCI_DEVICE_ID_INTEL_CNL_CSE0,
Subrata Banikd0586d22017-11-27 13:28:41 +05301180 PCI_DEVICE_ID_INTEL_SKL_CSE0,
Maxim Polyakov571d07d2019-08-22 13:11:32 +03001181 PCI_DEVICE_ID_INTEL_LWB_CSE0,
1182 PCI_DEVICE_ID_INTEL_LWB_CSE0_SUPER,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +08001183 PCI_DEVICE_ID_INTEL_CNP_H_CSE0,
Aamir Bohra9eac0392018-06-30 12:07:04 +05301184 PCI_DEVICE_ID_INTEL_ICL_CSE0,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +05301185 PCI_DEVICE_ID_INTEL_CMP_CSE0,
Gaggery Tsai12a651c2019-12-05 11:23:20 -08001186 PCI_DEVICE_ID_INTEL_CMP_H_CSE0,
Ravi Sarawadi6b5bf402019-10-21 22:25:04 -07001187 PCI_DEVICE_ID_INTEL_TGL_CSE0,
Jeremy Soller191a8d72021-08-10 14:06:51 -06001188 PCI_DEVICE_ID_INTEL_TGL_H_CSE0,
Tan, Lean Sheng26136092020-01-20 19:13:56 -08001189 PCI_DEVICE_ID_INTEL_MCC_CSE0,
1190 PCI_DEVICE_ID_INTEL_MCC_CSE1,
1191 PCI_DEVICE_ID_INTEL_MCC_CSE2,
1192 PCI_DEVICE_ID_INTEL_MCC_CSE3,
Meera Ravindranath3f4af0d2020-02-12 16:01:22 +05301193 PCI_DEVICE_ID_INTEL_JSP_CSE0,
1194 PCI_DEVICE_ID_INTEL_JSP_CSE1,
1195 PCI_DEVICE_ID_INTEL_JSP_CSE2,
1196 PCI_DEVICE_ID_INTEL_JSP_CSE3,
Subrata Banikf672f7f2020-08-03 14:29:25 +05301197 PCI_DEVICE_ID_INTEL_ADP_P_CSE0,
1198 PCI_DEVICE_ID_INTEL_ADP_P_CSE1,
1199 PCI_DEVICE_ID_INTEL_ADP_P_CSE2,
1200 PCI_DEVICE_ID_INTEL_ADP_P_CSE3,
1201 PCI_DEVICE_ID_INTEL_ADP_S_CSE0,
1202 PCI_DEVICE_ID_INTEL_ADP_S_CSE1,
1203 PCI_DEVICE_ID_INTEL_ADP_S_CSE2,
1204 PCI_DEVICE_ID_INTEL_ADP_S_CSE3,
Varshit Pandyaf4d98fdd22021-01-17 18:39:29 +05301205 PCI_DEVICE_ID_INTEL_ADP_M_CSE0,
1206 PCI_DEVICE_ID_INTEL_ADP_M_CSE1,
1207 PCI_DEVICE_ID_INTEL_ADP_M_CSE2,
1208 PCI_DEVICE_ID_INTEL_ADP_M_CSE3,
Hannah Williams63142152017-06-12 14:03:18 -07001209 0,
1210};
1211
Andrey Petrov04a72c42017-03-01 15:51:57 -08001212static const struct pci_driver cse_driver __pci_driver = {
1213 .ops = &cse_ops,
1214 .vendor = PCI_VENDOR_ID_INTEL,
1215 /* SoC/chipset needs to provide PCI device ID */
Andrey Petrov0405de92017-06-05 13:25:29 -07001216 .devices = pci_device_ids
Andrey Petrov04a72c42017-03-01 15:51:57 -08001217};
1218
1219#endif