summaryrefslogtreecommitdiff
path: root/chip/mec1322/uart.c
diff options
context:
space:
mode:
authorKyoung Kim <kyoung.il.kim@intel.com>2015-03-23 18:18:36 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-07-17 18:09:55 +0000
commit0e53f9d425e9a5bdad084b231438b7ec87432f3a (patch)
tree43c25ac86f19de0c0d1f812c2052b4e61fbbb456 /chip/mec1322/uart.c
parent2e9ab7cbe48934deab914d96feb9141fdae95197 (diff)
downloadchrome-ec-0e53f9d425e9a5bdad084b231438b7ec87432f3a.tar.gz
mec1322: heavysleep in idle task and console deepsleep
Implemented mec1322's heavysleep in idle task to reduce further EC power down on S3. MEC1322 needs sleep-enabled for all blocks to acheive max power down including UART. Real heavysleep will be effective only when console/uart is not active. To enable this commit, board-specific commit is required. For example, check commit, "Enabling heavysleep idle task at S3". Test: 1. Put device into S3 mode by typing 'powerd_dbus_suspend" in Linux shell. 2. wait at least 1 min till EC console sleeps 3. measure EC power. Since idle task is continuously scheduled, EC will enters/exits to/from heavy sleep mode frequently in S3 and power consumption will be changed dynamically. For acurate power measurement, high-sampling-rate measurement system might be required and using DMM might not give accurate number. BUG=None TEST=Tested on evt1p0/evt1p7/DVT BRANCH=None Change-Id: I435ca347cab2f4d51cefeee802c3bf30fb393fa1 Signed-off-by: Kyoung Kim <kyoung.il.kim@intel.com> Reviewed-on: https://chromium-review.googlesource.com/283603 Reviewed-by: Alec Berg <alecaberg@chromium.org> Tested-by: Alec Berg <alecaberg@chromium.org> Commit-Queue: Alec Berg <alecaberg@chromium.org>
Diffstat (limited to 'chip/mec1322/uart.c')
-rw-r--r--chip/mec1322/uart.c79
1 files changed, 77 insertions, 2 deletions
diff --git a/chip/mec1322/uart.c b/chip/mec1322/uart.c
index fe47ee262d..3fdb156188 100644
--- a/chip/mec1322/uart.c
+++ b/chip/mec1322/uart.c
@@ -32,6 +32,9 @@ void uart_tx_start(void)
if (MEC1322_UART_IER & (1 << 1))
return;
+ /* Do not allow deep sleep while transmit in progress */
+ disable_sleep(SLEEP_MASK_UART);
+
/*
* Re-enable the transmit interrupt, then forcibly trigger the
* interrupt. This works around a hardware problem with the
@@ -45,12 +48,15 @@ void uart_tx_start(void)
void uart_tx_stop(void)
{
MEC1322_UART_IER &= ~(1 << 1);
+
+ /* Re-allow deep sleep */
+ enable_sleep(SLEEP_MASK_UART);
}
void uart_tx_flush(void)
{
/* Wait for transmit FIFO empty */
- while (!(MEC1322_UART_LSR & (1 << 5)))
+ while (!(MEC1322_UART_LSR & MEC1322_LSR_TX_EMPTY))
;
}
@@ -60,7 +66,13 @@ int uart_tx_ready(void)
* We have no indication of free space in transmit FIFO. To work around
* this, we check transmit FIFO empty bit every 16 characters written.
*/
- return tx_fifo_used != 0 || MEC1322_UART_LSR & (1 << 5);
+ return tx_fifo_used != 0 || (MEC1322_UART_LSR & MEC1322_LSR_TX_EMPTY);
+}
+
+int uart_tx_in_progress(void)
+{
+ /* return 0: FIFO is empty, 1: FIFO NOT Empty */
+ return !(MEC1322_UART_LSR & MEC1322_LSR_TX_EMPTY);
}
int uart_rx_available(void)
@@ -156,3 +168,66 @@ void uart_init(void)
init_done = 1;
}
+
+#ifdef CONFIG_LOW_POWER_IDLE
+void uart_enter_dsleep(void)
+{
+ const struct gpio_info g = gpio_list[GPIO_UART0_RX];
+
+ /* Disable the UART interrupt. */
+ task_disable_irq(MEC1322_IRQ_UART); /* NVIC interrupt for UART=13 */
+
+ /*
+ * Set the UART0 RX pin to be a GPIO-162(fixed pin) interrupt
+ * with the flags defined in the gpio.inc file.
+ */
+ gpio_set_flags_by_mask(g.port, g.mask, g.flags);
+ gpio_set_alternate_function(g.port, g.mask, -1);
+
+ /* power-down/de-activate UART0 */
+ MEC1322_UART_ACT &= ~(1 << 0);
+
+ /* Clear pending interrupts on GPIO_UART0_RX(GPIO162, girq=8, bit=18) */
+ MEC1322_INT_SOURCE(8) = (1<<18);
+
+ /* Enable GPIO interrupts on the UART0 RX pin. */
+ gpio_enable_interrupt(GPIO_UART0_RX);
+}
+
+
+void uart_exit_dsleep(void)
+{
+ /*
+ * If the UART0 RX GPIO interrupt has not fired, then no edge has been
+ * detected. Disable the GPIO interrupt so that switching the pin over
+ * to a UART pin doesn't inadvertently cause a GPIO edge interrupt.
+ * Note: we can't disable this interrupt if it has already fired
+ * because then the IRQ will not run at all.
+ */
+ if (!((1 << 18) & MEC1322_INT_SOURCE(8))) /* if edge interrupt */
+ gpio_disable_interrupt(GPIO_UART0_RX);
+
+ /* Configure UART0 pins for use in UART peripheral. */
+ gpio_config_module(MODULE_UART, 1);
+
+ /* Clear pending interrupts on UART peripheral and enable interrupts. */
+ uart_clear_rx_fifo(0);
+ task_enable_irq(MEC1322_IRQ_UART); /* NVIC interrupt for UART = 13 */
+
+ /* power-up/activate UART0 */
+ MEC1322_UART_ACT |= (1 << 0);
+}
+
+void uart_deepsleep_interrupt(enum gpio_signal signal)
+{
+ /*
+ * Activity seen on UART RX pin while UART was disabled for deep sleep.
+ * The console won't see that character because the UART is disabled,
+ * so we need to inform the clock module of UART activity ourselves.
+ */
+ clock_refresh_console_in_use();
+
+ /* Disable interrupts on UART0 RX pin to avoid repeated interrupts. */
+ gpio_disable_interrupt(GPIO_UART0_RX);
+}
+#endif /* CONFIG_LOW_POWER_IDLE */