diff options
-rw-r--r-- | board/cr50/board.c | 157 | ||||
-rw-r--r-- | board/cr50/board.h | 2 | ||||
-rw-r--r-- | board/cr50/gpio.inc | 3 | ||||
-rw-r--r-- | common/tpm_registers.c | 25 | ||||
-rw-r--r-- | include/tpm_registers.h | 7 |
5 files changed, 108 insertions, 86 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c index 01d9a0d5a9..3597014071 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -79,6 +79,9 @@ uint32_t nvmem_user_sizes[NVMEM_NUM_USERS] = { NVMEM_CR50_SIZE }; +static int device_state_changed(enum device_type device, + enum device_state state); + /* Board specific configuration settings */ static uint32_t board_properties; static uint8_t reboot_request_posted; @@ -312,7 +315,6 @@ static void init_pmu(void) void pmu_wakeup_interrupt(void) { int exiten, wakeup_src; - int wake_on_low; delay_sleep_by(1 * MSEC); @@ -337,18 +339,7 @@ void pmu_wakeup_interrupt(void) * Delay sleep long enough for a SPI slave transaction to start * or for the system to be reset. */ - delay_sleep_by(20 * SECOND); - - /* - * If sys_rst_l or plt_rst_l (if signal is present) is - * configured to wake on low and the signal is low, then call - * tpm_rst_asserted - */ - wake_on_low = board_use_plt_rst() ? - GREAD_FIELD(PINMUX, EXITINV0, DIOM3) : - GREAD_FIELD(PINMUX, EXITINV0, DIOM0); - if (!gpio_get_level(GPIO_TPM_RST_L) && wake_on_low) - tpm_rst_asserted(GPIO_TPM_RST_L); + delay_sleep_by(5 * SECOND); } /* Trigger timer0 interrupt */ @@ -376,17 +367,9 @@ void board_configure_deep_sleep_wakepins(void) GWRITE_FIELD(PINMUX, DIOB5_CTL, IE, 0); /* - * DIOA3 is GPIO_DETECT_AP which is used to detect if the AP is in S0. - * If the AP is in s0, cr50 should not be in deep sleep so wake up. - */ - GWRITE_FIELD(PINMUX, EXITEDGE0, DIOA3, 1); /* edge sensitive */ - GWRITE_FIELD(PINMUX, EXITINV0, DIOA3, 0); /* wake on high */ - GWRITE_FIELD(PINMUX, EXITEN0, DIOA3, 1); /* GPIO_DETECT_AP */ - - /* - * Whether it is a short pulse or long one waking on the rising edge is - * fine because the goal of the system reset signal is to reset the TPM - * and after resuming from deep sleep the TPM will be reset. Cr50 + * Whether it is a short pulse or long one waking on the high level is + * fine because the goal of the system reset signal is to reset the + * TPM and after resuming from deep sleep the TPM will be reset. Cr50 * doesn't need to read the low value and then reset. */ if (board_use_plt_rst()) { @@ -396,12 +379,25 @@ void board_configure_deep_sleep_wakepins(void) */ /* Disable plt_rst_l as a wake pin */ GWRITE_FIELD(PINMUX, EXITEN0, DIOM3, 0); - /* Reconfigure and reenable it. */ - GWRITE_FIELD(PINMUX, EXITEDGE0, DIOM3, 1); /* edge sensitive */ + /* + * Reconfigure it to be level sensitive so that we are + * guaranteed to wake up if the level turns up, no need to + * worry about missing the rising edge. + */ + GWRITE_FIELD(PINMUX, EXITEDGE0, DIOM3, 0); GWRITE_FIELD(PINMUX, EXITINV0, DIOM3, 0); /* wake on high */ /* enable powerdown exit */ GWRITE_FIELD(PINMUX, EXITEN0, DIOM3, 1); } else { + /* + * DIOA3 is GPIO_DETECT_AP which is used to detect if the AP + * is in S0. If the AP is in s0, cr50 should not be in deep + * sleep so wake up. + */ + GWRITE_FIELD(PINMUX, EXITEDGE0, DIOA3, 0); /* level sensitive */ + GWRITE_FIELD(PINMUX, EXITINV0, DIOA3, 0); /* wake on high */ + GWRITE_FIELD(PINMUX, EXITEN0, DIOA3, 1); + /* Configure cr50 to resume on the rising edge of sys_rst_l */ /* Disable sys_rst_l as a wake pin */ GWRITE_FIELD(PINMUX, EXITEN0, DIOM0, 0); @@ -439,32 +435,49 @@ static void configure_board_specific_gpios(void) * board type. This signal is used to monitor AP resets and reset the * TPM. * + * Also configure these pins to be wake triggers on the rising edge, + * this will apply to regular sleep only, entering deep sleep would + * reconfigure this. + * * plt_rst_l is on diom3, and sys_rst_l is on diom0. */ if (board_use_plt_rst()) { + /* Use plt_rst_l for device detect purposes. */ + device_states[DEVICE_AP].detect = GPIO_TPM_RST_L; + /* Use plt_rst_l as the tpm reset signal. */ GWRITE(PINMUX, GPIO1_GPIO0_SEL, GC_PINMUX_DIOM3_SEL); + + /* No interrupts from AP UART TX state change are needed. */ + gpio_disable_interrupt(GPIO_DETECT_AP); + /* Enbale the input */ GWRITE_FIELD(PINMUX, DIOM3_CTL, IE, 1); - /* Set power down for the equivalent of DIO_WAKE_FALLING */ /* Set to be edge sensitive */ GWRITE_FIELD(PINMUX, EXITEDGE0, DIOM3, 1); - /* Select failling edge polarity */ - GWRITE_FIELD(PINMUX, EXITINV0, DIOM3, 1); + /* Select rising edge polarity */ + GWRITE_FIELD(PINMUX, EXITINV0, DIOM3, 0); /* Enable powerdown exit on DIOM3 */ GWRITE_FIELD(PINMUX, EXITEN0, DIOM3, 1); } else { + /* Use AP UART TX for device detect purposes. */ + device_states[DEVICE_AP].detect = GPIO_DETECT_AP; + /* Use sys_rst_l as the tpm reset signal. */ GWRITE(PINMUX, GPIO1_GPIO0_SEL, GC_PINMUX_DIOM0_SEL); /* Enbale the input */ GWRITE_FIELD(PINMUX, DIOM0_CTL, IE, 1); - /* Set power down for the equivalent of DIO_WAKE_FALLING */ + /* Use AP UART TX as the DETECT AP signal. */ + GWRITE(PINMUX, GPIO1_GPIO1_SEL, GC_PINMUX_DIOA3_SEL); + /* Enbale the input */ + GWRITE_FIELD(PINMUX, DIOA3_CTL, IE, 1); + /* Set to be edge sensitive */ GWRITE_FIELD(PINMUX, EXITEDGE0, DIOM0, 1); - /* Select failling edge polarity */ - GWRITE_FIELD(PINMUX, EXITINV0, DIOM0, 1); + /* Select rising edge polarity */ + GWRITE_FIELD(PINMUX, EXITINV0, DIOM0, 0); /* Enable powerdown exit on DIOM0 */ GWRITE_FIELD(PINMUX, EXITEN0, DIOM0, 1); } @@ -576,31 +589,33 @@ int flash_regions_to_enable(struct g_flash_region *regions, return 3; } -/* This is the interrupt handler to react to TPM_RST_L */ -void tpm_rst_asserted(enum gpio_signal signal) +static void deferred_tpm_rst_isr(void) { - /* - * Cr50 drives SYS_RST_L in certain scenarios, in those cases - * this signal's assertion should be ignored here. - */ - CPRINTS("%s from %d", __func__, signal); - if (usb_spi_update_in_progress() || - tpm_is_resetting()) { - CPRINTS("%s ignored", __func__); - return; - } + ccprintf("%T %s\n", __func__); - if (reboot_request_posted) { - /* - * Reset TPM and wait to completion to make sure nvmem is - * committed before reboot. - */ - tpm_reset_request(1, 0); - system_reset(SYSTEM_RESET_HARD); /* This will never return. */ - } else { + if (board_use_plt_rst() && + device_state_changed(DEVICE_AP, DEVICE_STATE_ON)) + hook_notify(HOOK_CHIPSET_RESUME); + + if (!reboot_request_posted) { /* Reset TPM, no need to wait for completion. */ tpm_reset_request(0, 0); + return; } + + /* + * Reset TPM and wait to completion to make sure nvmem is + * committed before reboot. + */ + tpm_reset_request(1, 0); + system_reset(SYSTEM_RESET_HARD); /* This will never return. */ +} +DECLARE_DEFERRED(deferred_tpm_rst_isr); + +/* This is the interrupt handler to react to TPM_RST_L */ +void tpm_rst_deasserted(enum gpio_signal signal) +{ + hook_call_deferred(&deferred_tpm_rst_isr_data, 0); } void assert_sys_rst(void) @@ -656,13 +671,9 @@ int is_ec_rst_asserted(void) } static int device_state_changed(enum device_type device, - enum device_state state) + enum device_state state) { - /* - * We've determined the device state, so cancel any deferred callbacks. - */ hook_call_deferred(device_states[device].deferred, -1); - return device_set_state(device, state); } @@ -752,7 +763,6 @@ struct device_config device_states[] = { }, [DEVICE_AP] = { .deferred = &ap_deferred_data, - .detect = GPIO_DETECT_AP, .name = "AP" }, [DEVICE_EC] = { @@ -784,7 +794,7 @@ void device_state_on(enum gpio_signal signal) gpio_disable_interrupt(signal); switch (signal) { - case GPIO_DETECT_AP: + case GPIO_DETECT_AP: /* Would happen only on non plt_rst_l devices. */ if (device_state_changed(DEVICE_AP, DEVICE_STATE_ON)) hook_notify(HOOK_CHIPSET_RESUME); break; @@ -796,7 +806,7 @@ void device_state_on(enum gpio_signal signal) servo_attached(); break; default: - CPRINTS("Device not supported"); + CPRINTS("Device %d not supported", signal); return; } } @@ -810,21 +820,28 @@ void board_update_device_state(enum device_type device) * If the device is currently on set its state immediately. If it * thinks the device is powered off debounce the signal. */ - if (gpio_get_level(device_states[device].detect)) + if (gpio_get_level(device_states[device].detect)) { + if (device_get_state(device) == DEVICE_STATE_ON) + return; device_state_on(device_states[device].detect); - else { + } else { + if (device_get_state(device) == DEVICE_STATE_OFF) + return; device_set_state(device, DEVICE_STATE_UNKNOWN); - - gpio_enable_interrupt(device_states[device].detect); + if ((device != DEVICE_AP) || !board_use_plt_rst()) + gpio_enable_interrupt(device_states[device].detect); /* - * The signal is low now, but the detect signals are on UART RX - * which may be receiving something. Wait long enough for an - * entire data chunk to be sent to declare that the device is - * off. If the detect signal remains low for 100us then the - * signal is low because the device is off. + * The signal is low now, but this could be just an AP UART + * transmitting or PLT_RST_L pulsing. Let's wait long enough + * to debounce in both cases, pickng duration slightly shorter + * than the device polling iterval. + * + * Interrupts from the appropriate source (platform dependent) + * will cancel the deferred function if the signal is + * deasserted within the deferral interval. */ - hook_call_deferred(device_states[device].deferred, 100); + hook_call_deferred(device_states[device].deferred, 900 * MSEC); } } diff --git a/board/cr50/board.h b/board/cr50/board.h index c5d11a196f..bc48b31d26 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -157,7 +157,7 @@ enum usb_spi { void board_configure_deep_sleep_wakepins(void); /* Interrupt handler */ -void tpm_rst_asserted(enum gpio_signal signal); +void tpm_rst_deasserted(enum gpio_signal signal); void device_state_on(enum gpio_signal signal); void post_reboot_request(void); diff --git a/board/cr50/gpio.inc b/board/cr50/gpio.inc index f7fbcc3f51..f2ac78ae1d 100644 --- a/board/cr50/gpio.inc +++ b/board/cr50/gpio.inc @@ -55,7 +55,7 @@ * two internal GPIOs to the same pad if sys_rst_l is also being used to detect * system resets. */ -GPIO_INT(TPM_RST_L, PIN(1, 0), GPIO_INT_FALLING, tpm_rst_asserted) +GPIO_INT(TPM_RST_L, PIN(1, 0), GPIO_INT_RISING, tpm_rst_deasserted) GPIO_INT(DETECT_AP, PIN(1, 1), GPIO_INT_HIGH, device_state_on) GPIO_INT(DETECT_EC, PIN(1, 2), GPIO_INT_HIGH, device_state_on) GPIO_INT(DETECT_SERVO, PIN(1, 3), GPIO_INT_HIGH | GPIO_PULL_DOWN, @@ -145,7 +145,6 @@ PINMUX(FUNC(UART2_RX), B6, DIO_INPUT) /* EC console */ * driving the cr50 uart TX at the same time as servo is driving those pins may * damage both servo and cr50. */ -PINMUX(GPIO(DETECT_AP), A3, DIO_INPUT) PINMUX(GPIO(DETECT_EC), B6, DIO_INPUT) PINMUX(GPIO(DETECT_SERVO), B5, DIO_INPUT) diff --git a/common/tpm_registers.c b/common/tpm_registers.c index e5258df420..e2e286136f 100644 --- a/common/tpm_registers.c +++ b/common/tpm_registers.c @@ -11,6 +11,7 @@ #include "byteorder.h" #include "console.h" +#include "device_state.h" #include "extension.h" #include "link_defs.h" #include "nvmem.h" @@ -697,11 +698,6 @@ int tpm_reset_request(int wait_until_done, int wipe_nvmem_first) return EC_ERROR_TIMEOUT; } -int tpm_is_resetting(void) -{ - return reset_in_progress; -} - /* * A timeout hook to reinstate NVMEM commits soon after reset. * @@ -787,13 +783,30 @@ static void tpm_reset_now(int wipe_first) void tpm_task(void) { + uint32_t evt; + + /* + * Just in case there is a resume from deep sleep where AP is not out + * of reset, let's not proceed until AP is actually up. + */ + while (device_get_state(DEVICE_AP) != DEVICE_STATE_ON) { + /* + * The only event we should expect at this point would be the + * reset request. + */ + evt = task_wait_event(-1); + if (evt & TPM_EVENT_RESET) + break; + + cprints(CC_TASK, "%s: unexpected event %x\n", __func__, evt); + } + tpm_reset_now(0); while (1) { uint8_t *response; unsigned response_size; uint32_t command_code; struct tpm_cmd_header *tpmh; - uint32_t evt; /* Wait for the next command event */ evt = task_wait_event(-1); diff --git a/include/tpm_registers.h b/include/tpm_registers.h index 293a0a99ac..9d5fba4cf5 100644 --- a/include/tpm_registers.h +++ b/include/tpm_registers.h @@ -43,13 +43,6 @@ void tpm_register_interface(interface_restart_func interface_restart); int tpm_reset_request(int wait_until_done, int wipe_nvmem_first); /* - * Return true if the TPM is being reset. Usually this helps to avoid - * unnecessary extra reset early at startup time, when TPM could be busy - * installing endorsement certificates. - */ -int tpm_is_resetting(void); - -/* * This structure describes the header of all commands and responses sent and * received over TPM FIFO. * |