summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCHLin <CHLIN56@nuvoton.com>2019-07-16 17:12:43 +0800
committerCommit Bot <commit-bot@chromium.org>2019-07-23 13:49:25 +0000
commit3fb2394b245c9d98e631443eff70f97758413f3e (patch)
tree85c0e6d647f460572b23ad7b1dd6428b5a3a4c04
parent0ae8c5584d3648c76bd8e8fca0a27ae20d1bb761 (diff)
downloadchrome-ec-3fb2394b245c9d98e631443eff70f97758413f3e.tar.gz
npcx7: UART: wait for Tx empty before enabling deep-sleep
In the original firmware (in the uart_buffering.c), it clears the SLEEP_MASK_UART immediately after it pushes all characters from its Tx buffer to UART's FIFO without checking the status of transmission. It may break the transmission because EC goes to deep sleep before UART TX (FIFO or shift register) becomes empty. This CL fixes it by: (1) Don't clear SLEEP_MASK_UART immediately when uart_tx_stop is called. (2) Enable the NXMIP (No Transmit in Progress) interrupt. (3) Clear SLEEP_MASK_UART in the UART interrupt handler when NXMIP is set. This fix only needs to apply to NPCX7 chips which have UART FIFO support. BRANCH=none BUG=b:137143640 TEST=No error for "make buildall" TEST=run 10 iterations of uart_stress_tester on yorp with command: ./util/uart_stress_tester.py /dev/ttyUSB2 -t 360; make sure no character lost in each iteration as below: ... INFO | UartSerial| /dev/ttyUSB2 | Detected as EC UART INFO | UartSerial| EC | Ready to test INFO | ChargenTest | Ports are ready to test INFO | ChargenTest | Test starts INFO | UartSerial| EC | Test thread starts INFO | UartSerial| EC | Test thread is done INFO | UartSerial| EC | 0 char lost / 4147200 (0.0 %) INFO | ChargenTest | PASS: lost 0 character(s) from the test INFO | ChargenTest | Test is done Change-Id: I97b1f572e8b9ebdb5102aa3e98ae2963d768b5b3 Signed-off-by: CHLin <CHLIN56@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1703944 Tested-by: CH Lin <chlin56@nuvoton.com> Reviewed-by: Namyoon Woo <namyoon@chromium.org> Reviewed-by: Aseda Aboagye <aaboagye@chromium.org> Commit-Queue: CH Lin <chlin56@nuvoton.com>
-rw-r--r--chip/npcx/registers.h2
-rw-r--r--chip/npcx/uart.c12
-rw-r--r--chip/npcx/uartn.c25
-rw-r--r--chip/npcx/uartn.h2
4 files changed, 39 insertions, 2 deletions
diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h
index d31800f841..3a63f6ccb7 100644
--- a/chip/npcx/registers.h
+++ b/chip/npcx/registers.h
@@ -326,7 +326,7 @@
#define NPCX_UFTCTL_TEMPTY_LVL_SEL FIELD(0, 5)
#define NPCX_UFTCTL_TEMPTY_LVL_EN 5
#define NPCX_UFTCTL_TEMPTY_EN 6
-#define NPCX_UFTCTL_NXIMPEN 7
+#define NPCX_UFTCTL_NXMIPEN 7
#define NPCX_UFRCTL_RFULL_LVL_SEL FIELD(0, 5)
#define NPCX_UFRCTL_RFULL_LVL_EN 5
diff --git a/chip/npcx/uart.c b/chip/npcx/uart.c
index a83de311ef..1e4d88f789 100644
--- a/chip/npcx/uart.c
+++ b/chip/npcx/uart.c
@@ -123,10 +123,14 @@ void uart_tx_start(void)
void uart_tx_stop(void)
{
+#ifdef NPCX_UART_FIFO_SUPPORT
+ uartn_tx_stop(CONSOLE_UART, 0);
+#else
uint8_t sleep_ena;
sleep_ena = (pad == UART_DEFAULT_PAD) ? 1 : 0;
uartn_tx_stop(CONSOLE_UART, sleep_ena);
+#endif
}
void uart_tx_flush(void)
@@ -196,6 +200,14 @@ void uart_ec_interrupt(void)
return;
}
#endif
+#ifdef NPCX_UART_FIFO_SUPPORT
+ if (!uartn_tx_in_progress(CONSOLE_UART)) {
+ if (uart_buffer_empty()) {
+ uartn_enable_tx_complete_int(CONSOLE_UART, 0);
+ enable_sleep(SLEEP_MASK_UART);
+ }
+ }
+#endif
/* Default pad. */
/* Read input FIFO until empty, then fill output FIFO */
diff --git a/chip/npcx/uartn.c b/chip/npcx/uartn.c
index 692e75419f..2269e11e7c 100644
--- a/chip/npcx/uartn.c
+++ b/chip/npcx/uartn.c
@@ -28,6 +28,13 @@
/* True if the Tx FIFO is not completely full */
#define NPCX_UART_TX_IS_READY(n) \
(!(GET_FIELD(NPCX_UFTSTS(n), NPCX_UFTSTS_TEMPTY_LVL) == 0))
+
+/* Enable UART Tx "not" in transmission interrupt */
+#define NPCX_UART_TX_NXMIP_INT_EN(n) \
+ (SET_BIT(NPCX_UFTCTL(n), NPCX_UFTCTL_NXMIPEN))
+/* Disable UART Tx "not" in transmission interrupt */
+#define NPCX_UART_TX_NXMIP_INT_DIS(n) \
+ (CLEAR_BIT(NPCX_UFTCTL(n), NPCX_UFTCTL_NXMIPEN))
/*
* True if Tx is in progress
* (i.e. FIFO is not empty or last byte in TSFT (Transmit Shift register)
@@ -114,6 +121,13 @@ void uartn_tx_start(uint8_t uart_num)
/* Do not allow deep sleep while transmit in progress */
disable_sleep(SLEEP_MASK_UART);
+#ifdef NPCX_UART_FIFO_SUPPORT
+ /*
+ * For FIFO mode, enable the NXMIP interrupt. This generates an
+ * interrupt when Tx (both FIFO and shift register) is empty
+ */
+ NPCX_UART_TX_NXMIP_INT_EN(uart_num);
+#else
/*
* Re-enable the transmit interrupt, then forcibly trigger the
* interrupt. This works around a hardware problem with the
@@ -121,10 +135,19 @@ void uartn_tx_start(uint8_t uart_num)
* threshold is _crossed_, not just met.
*/
NPCX_UART_TX_EMPTY_INT_EN(uart_num);
+#endif
task_trigger_irq(uart_cfg[uart_num].irq);
}
+#ifdef NPCX_UART_FIFO_SUPPORT
+void uartn_enable_tx_complete_int(uint8_t uart_num, uint8_t enable)
+{
+ enable ? NPCX_UART_TX_NXMIP_INT_EN(uart_num) :
+ NPCX_UART_TX_NXMIP_INT_DIS(uart_num);
+}
+#endif
+
void uartn_tx_stop(uint8_t uart_num, uint8_t sleep_ena)
{
/* Disable TX interrupt */
@@ -190,7 +213,7 @@ static void uartn_set_fifo_mode(uint8_t uart_num)
/* Disable all Tx interrupts */
NPCX_UFTCTL(uart_num) &= ~(BIT(NPCX_UFTCTL_TEMPTY_LVL_EN) |
BIT(NPCX_UFTCTL_TEMPTY_EN) |
- BIT(NPCX_UFTCTL_NXIMPEN));
+ BIT(NPCX_UFTCTL_NXMIPEN));
}
#endif
diff --git a/chip/npcx/uartn.h b/chip/npcx/uartn.h
index fc5c2599d0..e5326f72b8 100644
--- a/chip/npcx/uartn.h
+++ b/chip/npcx/uartn.h
@@ -60,4 +60,6 @@ void uartn_clear_rx_fifo(int channel);
void uartn_rx_int_en(uint8_t uart_num);
/* Enable the UART Wake-up */
void uartn_wui_en(uint8_t uart_num);
+/* Enable/disable Tx NXMIP (No Transmit In Progress) interrupt */
+void uartn_enable_tx_complete_int(uint8_t uart_num, uint8_t enable);
#endif /* __CROS_EC_UARTN_H */