From 7f78c555647699d82826dae434f099a78d673d8a Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sun, 26 Jun 2022 22:10:52 -0500 Subject: [PATCH 1/4] lfw: restore RW firmware access by using the right pin mux The alternate function table for LFW on the hx20 contained a few incorrect values that resulted in LFW being unable to read from flash, which disabled the use of the RW (and in some cases the RO) firmware image. 1. SHD_IO0 is function 1 on the MEC152x, not function 2. 2. SHD_IO2 and SHD_IO3 were not included in the alternate function table. The alternate function table from hx20/gpio.inc is correct, but it is missing the SPI alternate for SHD_GLK/GPIO_0056. In the future, we may want to move to model where hx20/gpio.inc includes hx20/lfw/gpio.inc and common pin configurations are shared. --- board/hx20/lfw/gpio.inc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/board/hx20/lfw/gpio.inc b/board/hx20/lfw/gpio.inc index f4142d3c29..cabf346f97 100644 --- a/board/hx20/lfw/gpio.inc +++ b/board/hx20/lfw/gpio.inc @@ -31,13 +31,15 @@ ALTERNATE(PIN_MASK(2, 0x30), 1, MODULE_UART, 0) * MEC1701H SHD SPI is connected to QMSPI controller. * QMSPI drives chip select. SHD_CS0#(GPIO_0055) must be set * to alternate function 2 and GPIO_ODR_HIGH. - * GPIO_0055 Function 2, Bank 1 bit[13] */ +/* GPIO_0055 Function 2, Bank 1 bit[13] */ ALTERNATE(PIN_MASK(1, 0x2000), 2, MODULE_SPI_FLASH, GPIO_ODR_HIGH) /* SHD_CLK - GPIO_0056 Function 2, Bank 1 bit[14] */ ALTERNATE(PIN_MASK(1, 0x4000), 2, MODULE_SPI_FLASH, 0) -/* MOSI(SHD_IO0) - GPIO_0223 Function 2, Bank 4 bit[19] */ +/* MOSI(SHD_IO0) - GPIO_0223 Function 1, Bank 4 bit[19] */ /* MISO(SHD_IO1) - GPIO_0224 Function 2, Bank 4 bit[20] */ -ALTERNATE(PIN_MASK(4, 0x180000), 2, MODULE_SPI_FLASH, 0) - - +/* nWP(SHD_IO2) - GPIO_0227 Function 1, Bank 4 bit[23] */ +ALTERNATE(PIN_MASK(4, 0x880000), 1, MODULE_SPI_FLASH, 0) +ALTERNATE(PIN_MASK(4, 0x100000), 2, MODULE_SPI_FLASH, 0) +/* nHOLD(SHD_IO3) - GPIO_0016 Function 2, Bank 0 bit[14] */ +ALTERNATE(PIN_MASK(0, 0x4000), 2, MODULE_SPI_FLASH, 0) From 4ed29834fb62cd6c0fb8ec6555ce7db8f90781f8 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sat, 30 Jul 2022 15:15:35 -0500 Subject: [PATCH 2/4] Remember whether we cut power to ourselves, and re-check during boot On the hx20 (and presumably hx30,) a design issue prevents us from hibernating the EC properly. Therefore, every time we bring the machine down we cut power instead of hibernating. That results in the next boot being a complete reset. There is code in lfw that checks whether the current boot is due to a watchdog reset or a power-on reset and if it is, clears the image type back to EC_IMAGE_UNKNOWN. Due to that design issue, the hx20 EC is *always* in POR/VTR or WDT on startup. By storing whether the last shutdown was graceful/intended and checking it before resetting the image type, we can work around this issue. --- board/hx20/board.c | 2 ++ chip/mchp/lfw/ec_lfw.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/board/hx20/board.c b/board/hx20/board.c index d91ef42799..c29e86e378 100644 --- a/board/hx20/board.c +++ b/board/hx20/board.c @@ -421,6 +421,8 @@ static void board_power_off_deferred(void) charger_psys_enable(0); charge_gate_onoff(0); + MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX) |= 0x80; + /* Disable interrupts */ interrupt_disable(); for (i = 0; i < MCHP_IRQ_MAX; ++i) { diff --git a/chip/mchp/lfw/ec_lfw.c b/chip/mchp/lfw/ec_lfw.c index 61cfc293fe..8b2e429fb3 100644 --- a/chip/mchp/lfw/ec_lfw.c +++ b/chip/mchp/lfw/ec_lfw.c @@ -338,14 +338,26 @@ void system_init(void) uint32_t wdt_sts = MCHP_VBAT_STS & MCHP_VBAT_STS_ANY_RST; uint32_t rst_sts = MCHP_PCR_PWR_RST_STS & MCHP_PWR_RST_STS_VTR; + /* + * **HX20**: We can't hibernate the EC without also keeping + * 5v3v ALW on, so we cut power entirely. Unfortunately, + * that means that one of rst_sts or wdt_sts will always be + * on... and that precludes the use of the RW firmware. + * However, if we store a bit in IMAGETYPE to indicate that + * we cut power to ourselves, we can use it at the next boot + * to determine whether this poweroff was EC-origin or not. + */ + bool wacked = (MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX) & 0x80) != 0; trace12(0, LFW, 0, "VBAT_STS = 0x%08x PCR_PWR_RST_STS = 0x%08x", wdt_sts, rst_sts); - if (rst_sts || wdt_sts) + if ((rst_sts || wdt_sts) && !wacked) MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX) = EC_IMAGE_UNKNOWN; + + MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX) &= 0x7F; } enum ec_image system_get_image_copy(void) From c187ce17648b4538be37615520d58ab6adfd333a Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sat, 30 Jul 2022 15:19:14 -0500 Subject: [PATCH 3/4] Make sure we fire SHUTDOWN_COMPLETE hooks when the AP goes down This ensures that the hook in common/system.c that triggers an "at-shutdown" reboot from RO to RW fires. Without this, `ectool reboot_ec RW at-shutdown` doesn't work. --- board/hx20/power_sequence.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/board/hx20/power_sequence.c b/board/hx20/power_sequence.c index 530d4025b5..540ca47ee7 100644 --- a/board/hx20/power_sequence.c +++ b/board/hx20/power_sequence.c @@ -559,6 +559,10 @@ enum power_state power_handle_state(enum power_state state) gpio_set_level(GPIO_SYSON, 0); hook_notify(HOOK_CHIPSET_SHUTDOWN); cypd_set_power_active(POWER_S5); + + /* Call hooks after we remove power rails */ + hook_notify(HOOK_CHIPSET_SHUTDOWN_COMPLETE); + power_s5_up = 0; return POWER_S5; break; From e6e1190cf9779472c8e55c93f5fc18146d8de232 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sun, 22 Jan 2023 23:00:31 -0600 Subject: [PATCH 4/4] mchp/lfw: make sure we keep the EC on for long operations Over the past six months with this patch set, I've observed one troubling behavior: the laptop would not always boot when it was powered completely off (with the EC off as well) and I clicked the power button. It turns out that the power buttons control VCI_IN[01] and that the VBAT-powered control interface is configured to drive GPIO250 as VCI_OUT based on the status of those inputs. Now, GPIO250 is also known as EC_ON on hx20/30: it controls whether 3VL_EC is on. The MEC1521 manual recommends the following example of using VCI_OUT on a "mobile platform" (abbreviated): 1. A coin cell battery is installed, powering VBAT 2. The power button on VCI_IN0# is pushed causing VCI_OUT to be asserted, powering the VTR rail 3. The EC reconfigures VCI so that firmware controls the VCI_OUT pin. Now, the EC is doing this over in vci_task (hx20/hx30), which is long after LFW has started and jumped to main firmware. The problem is, restoring access to RO and RW images in the prior three commits causes us to try to read from flash on startup. Reading from flash is slightly slower, so we extend the period of time between step 2 and 3 where 3VL_EC is only driven by VCI_IN0#. When the user releases the power button during that window, 3VL_EC is cut and the EC shuts down. This patch fixes the issue by asserting firmware control of VCI_OUT as early as is safe in lfw. --- board/hx20/lfw/gpio.inc | 2 ++ board/hx30/lfw/gpio.inc | 2 ++ chip/mchp/lfw/ec_lfw.c | 10 ++++++++++ 3 files changed, 14 insertions(+) diff --git a/board/hx20/lfw/gpio.inc b/board/hx20/lfw/gpio.inc index cabf346f97..a62b0c685c 100644 --- a/board/hx20/lfw/gpio.inc +++ b/board/hx20/lfw/gpio.inc @@ -15,6 +15,8 @@ */ GPIO(QMSPI_CS0, PIN(055), GPIO_ODR_HIGH) +/* We need to take control of this away from VCI */ +GPIO(EC_ON, PIN(0250), GPIO_OUT_HIGH) /* keep +3VL_EC to power on */ /* Alternate functions GPIO definition */ diff --git a/board/hx30/lfw/gpio.inc b/board/hx30/lfw/gpio.inc index f4142d3c29..fc7440cb23 100644 --- a/board/hx30/lfw/gpio.inc +++ b/board/hx30/lfw/gpio.inc @@ -15,6 +15,8 @@ */ GPIO(QMSPI_CS0, PIN(055), GPIO_ODR_HIGH) +/* We need to take control of this away from VCI */ +GPIO(EC_ON, PIN(0250), GPIO_OUT_HIGH) /* keep +3VL_EC to power on */ /* Alternate functions GPIO definition */ diff --git a/chip/mchp/lfw/ec_lfw.c b/chip/mchp/lfw/ec_lfw.c index 8b2e429fb3..334338daa3 100644 --- a/chip/mchp/lfw/ec_lfw.c +++ b/chip/mchp/lfw/ec_lfw.c @@ -422,6 +422,16 @@ void lfw_main(void) uart_init(); system_init(); + /* + * We need to switch control of VCI_OUT (aliased as EC_ON) away from + * VCI_INx to keep the machine powered even after the user releases the + * power button. This ensures that we can stay on long enough to read + * from SPI flash. + */ + gpio_reset(GPIO_EC_ON); + MCHP_VCI_REGISTER |= MCHP_VCI_REGISTER_FW_CNTRL; + MCHP_VCI_REGISTER |= MCHP_VCI_REGISTER_FW_EXT; + spi_enable(CONFIG_SPI_FLASH_PORT, 1); uart_puts("littlefw ");