summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCHLin <CHLIN56@nuvoton.com>2019-07-16 17:12:43 +0800
committerCommit Bot <commit-bot@chromium.org>2019-09-03 18:02:37 +0000
commitf3a3d893a581dc0c23dac210d836f54d6ddab337 (patch)
tree8d688b6c26a502a8ee67a21471b18902f5be73b6
parent6be1fbf61c9fab536ec19ff6f574009811b76a4c (diff)
downloadchrome-ec-f3a3d893a581dc0c23dac210d836f54d6ddab337.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> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1782399 Tested-by: Karthikeyan Ramasubramanian <kramasub@chromium.org> Reviewed-by: Karthikeyan Ramasubramanian <kramasub@chromium.org> Commit-Queue: Karthikeyan Ramasubramanian <kramasub@chromium.org>
-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 6a5c1a22dc..c5367663f5 100644
--- a/chip/npcx/registers.h
+++ b/chip/npcx/registers.h
@@ -325,7 +325,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 40d3ee391f..494bcfd151 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 d7d46e849f..5a414c3202 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) &= ~((1 << NPCX_UFTCTL_TEMPTY_LVL_EN) |
(1 << NPCX_UFTCTL_TEMPTY_EN) |
- (1 << NPCX_UFTCTL_NXIMPEN));
+ (1 << 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 */