diff options
-rw-r--r-- | chip/g/idle.c | 61 | ||||
-rw-r--r-- | chip/g/sps_tpm.c | 11 | ||||
-rw-r--r-- | include/system.h | 7 |
3 files changed, 73 insertions, 6 deletions
diff --git a/chip/g/idle.c b/chip/g/idle.c index 7319c6edb8..a141b80630 100644 --- a/chip/g/idle.c +++ b/chip/g/idle.c @@ -67,9 +67,29 @@ static void prepare_to_deep_sleep(void) /* Latch the pinmux values */ GREG32(PINMUX, HOLD) = 1; - /* Wake only from USB for now */ + /* + * Specify the PINMUX pads that can wake us. + * A1 is UART RX. Idle is high, so wake on low level + * A12 is SPS_CS_L. Also wake on low. + * HEY: Use something in gpio.inc to identify these! + */ + GREG32(PINMUX, EXITEN0) = + GC_PINMUX_EXITEN0_DIOA1_MASK | + GC_PINMUX_EXITEN0_DIOA12_MASK; + + GREG32(PINMUX, EXITEDGE0) = 0; /* level sensitive */ + + GREG32(PINMUX, EXITINV0) = /* low or falling */ + GC_PINMUX_EXITINV0_DIOA1_MASK | + GC_PINMUX_EXITINV0_DIOA12_MASK; + + /* Enable all possible internal wake sources */ GR_PMU_EXITPD_MASK = - GC_PMU_EXITPD_MASK_UTMI_SUSPEND_N_MASK; + GC_PMU_EXITPD_MASK_PIN_PD_EXIT_MASK | + GC_PMU_EXITPD_MASK_UTMI_SUSPEND_N_MASK | + GC_PMU_EXITPD_MASK_RDD0_PD_EXIT_TIMER_MASK | + GC_PMU_EXITPD_MASK_TIMELS0_PD_EXIT_TIMER0_MASK | + GC_PMU_EXITPD_MASK_TIMELS0_PD_EXIT_TIMER1_MASK; /* Clamp the USB pins and shut the PHY down. We have to do this in * three separate steps, or Bad Things happen. */ @@ -88,10 +108,23 @@ static void prepare_to_deep_sleep(void) GC_PMU_LOW_POWER_DIS_JTR_RC_MASK; } +/* The time in the future at which sleeping will be allowed. */ +static timestamp_t next_sleep_time; + +/* Update the future sleep time. */ +void delay_sleep_by(uint32_t us) +{ + timestamp_t tmp = get_time(); + + tmp.val += us; + if (tmp.val > next_sleep_time.val) + next_sleep_time = tmp; +} + /* Custom idle task, executed when no tasks are ready to be scheduled. */ void __idle(void) { - int sleep_ok; + int sleep_ok, sleep_delay_passed, prev_ok = 0; while (1) { @@ -102,8 +135,26 @@ void __idle(void) /* Anyone still busy? */ sleep_ok = DEEP_SLEEP_ALLOWED; - /* We're allowed to sleep now, so set it up. */ - if (sleep_ok) + /* + * We'll always wait a little bit before sleeping no matter + * what. This is more likely to let any console output finish + * than calling clock_refresh_console_in_use(), because that + * function is called BEFORE waking the console task, not after + * it runs. We can't call cflush() here because that wakes a + * task to do it and so we're not idle any more. + */ + if (sleep_ok && !prev_ok) + delay_sleep_by(200 * MSEC); + + prev_ok = sleep_ok; + sleep_delay_passed = timestamp_expired(next_sleep_time, 0); + + /* If it hasn't yet been long enough, check again when it is */ + if (!sleep_delay_passed) + timer_arm(next_sleep_time, TASK_ID_IDLE); + + /* We're allowed to deep sleep, so set it up. */ + if (sleep_ok && sleep_delay_passed) if (idle_action == IDLE_DEEP_SLEEP) prepare_to_deep_sleep(); /* Normal sleep is not yet implemented */ diff --git a/chip/g/sps_tpm.c b/chip/g/sps_tpm.c index 9d266056e6..8af3765642 100644 --- a/chip/g/sps_tpm.c +++ b/chip/g/sps_tpm.c @@ -7,6 +7,7 @@ #include "console.h" #include "hooks.h" #include "sps.h" +#include "system.h" #include "tpm_registers.h" #include "util.h" @@ -123,6 +124,9 @@ static void init_new_cycle(void) sps_tpm_state = SPS_TPM_STATE_RECEIVING_HEADER; rx_fifo_base = sps_rx_fifo_wrptr(); sps_tx_status(TPM_STALL_ASSERT); + /* We're just waiting for a new command, so we could sleep. */ + delay_sleep_by(1 * SECOND); + enable_sleep(SLEEP_MASK_SPI); } /* Extract R/W bit, register addresss, and data count from 4-byte header */ @@ -139,7 +143,9 @@ static int header_says_to_read(uint8_t *data, uint32_t *reg, uint32_t *count) /* actual RX FIFO handler (runs in interrupt context) */ static void process_rx_data(uint8_t *data, size_t data_size) { - /* We're collecting incoming bytes ... */ + /* We're receiving some bytes, so don't sleep */ + disable_sleep(SLEEP_MASK_SPI); + if ((rxbuf_count + data_size) > RXBUF_MAX) { CPRINTS("TPM SPI input overflow: %d + %d > %d in state %d", rxbuf_count, data_size, RXBUF_MAX, sps_tpm_state); @@ -266,6 +272,9 @@ static void sps_tpm_disable(void) { sps_tpm_state = SPS_TPM_STATE_PONDERING; sps_unregister_rx_handler(); + /* We don't care anymore, so we can sleep whenever */ + delay_sleep_by(0); + enable_sleep(SLEEP_MASK_SPI); } static int command_sps_tpm(int argc, char **argv) diff --git a/include/system.h b/include/system.h index 67a867f39e..220e0790e7 100644 --- a/include/system.h +++ b/include/system.h @@ -369,6 +369,13 @@ static inline void disable_sleep(uint32_t mask) } /** + * Postpone sleeping for at least this long, regardless of sleep_mask. + * + * @param Amount of time to postpone sleeping + */ +void delay_sleep_by(uint32_t us); + +/** * Use hibernate module to set up an RTC interrupt at a given * time from now * |