summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/g/idle.c61
-rw-r--r--chip/g/sps_tpm.c11
-rw-r--r--include/system.h7
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
*