summaryrefslogtreecommitdiff
path: root/chip/mt_scp/rv32i_common/uart.c
diff options
context:
space:
mode:
authorTzung-Bi Shih <tzungbi@chromium.org>2021-06-24 17:17:39 +0800
committerCommit Bot <commit-bot@chromium.org>2021-06-25 03:42:30 +0000
commitb409fd3b5ac6a82b6851f2e9af49761ee2d4766c (patch)
tree780a069f10a57222362a209abee19b27b7de9076 /chip/mt_scp/rv32i_common/uart.c
parentcf92cf3c6c4135b511c8f7f6bc83036167b7c735 (diff)
downloadchrome-ec-b409fd3b5ac6a82b6851f2e9af49761ee2d4766c.tar.gz
chip/mt_scp: move rv32i specific to common folder
BRANCH=none BUG=b:191835814 TEST=make BOARD=asurada_scp && make BOARD=cherry_scp && make BOARD=kukui_scp Signed-off-by: Tzung-Bi Shih <tzungbi@chromium.org> Change-Id: I35e9fd5f7d3e83d35d09a093be09b194c821f63e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2985060 Reviewed-by: Eric Yilun Lin <yllin@google.com>
Diffstat (limited to 'chip/mt_scp/rv32i_common/uart.c')
-rw-r--r--chip/mt_scp/rv32i_common/uart.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/chip/mt_scp/rv32i_common/uart.c b/chip/mt_scp/rv32i_common/uart.c
new file mode 100644
index 0000000000..2479bb8711
--- /dev/null
+++ b/chip/mt_scp/rv32i_common/uart.c
@@ -0,0 +1,171 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* SCP UART module */
+
+#include "csr.h"
+#include "system.h"
+#include "uart.h"
+#include "uart_regs.h"
+#include "util.h"
+
+/*
+ * UARTN == 0, SCP UART0
+ * UARTN == 1, SCP UART1
+ * UARTN == 2, AP UART1
+ */
+#define UARTN CONFIG_UART_CONSOLE
+#define UART_IDLE_WAIT_US 500
+#define UART_INTC_GROUP 12
+
+static uint8_t init_done, tx_started;
+
+void uart_init(void)
+{
+ const uint32_t baud_rate = CONFIG_UART_BAUD_RATE;
+ const uint32_t uart_clock = 26000000;
+ const uint32_t div = DIV_ROUND_NEAREST(uart_clock, baud_rate * 16);
+
+#if UARTN == 0
+ SCP_UART_CK_SEL |= UART0_CK_SEL_VAL(UART_CK_SEL_ULPOSC);
+ SCP_SET_CLK_CG |= CG_UART0_MCLK | CG_UART0_BCLK | CG_UART0_RST;
+
+ /* set AP GPIO164 and GPIO165 to alt func 3 */
+ AP_GPIO_MODE20_CLR = 0x00770000;
+ AP_GPIO_MODE20_SET = 0x00330000;
+#elif UARTN == 1
+ SCP_UART_CK_SEL |= UART1_CK_SEL_VAL(UART_CK_SEL_ULPOSC);
+ SCP_SET_CLK_CG |= CG_UART1_MCLK | CG_UART1_BCLK | CG_UART1_RST;
+#endif
+
+ /* Clear FIFO */
+ UART_FCR(UARTN) = UART_FCR_ENABLE_FIFO
+ | UART_FCR_CLEAR_RCVR
+ | UART_FCR_CLEAR_XMIT;
+ /* Line control: parity none, 8 bit, 1 stop bit */
+ UART_LCR(UARTN) = UART_LCR_WLEN8;
+ /* For baud rate <= 115200 */
+ UART_HIGHSPEED(UARTN) = 0;
+
+ /* DLAB start */
+ UART_LCR(UARTN) |= UART_LCR_DLAB;
+ UART_DLL(UARTN) = div & 0xff;
+ UART_DLH(UARTN) = (div >> 8) & 0xff;
+ UART_LCR(UARTN) &= ~UART_LCR_DLAB;
+ /* DLAB end */
+
+ /* Enable received data interrupt */
+ UART_IER(UARTN) |= UART_IER_RDI;
+
+#if (UARTN < SCP_UART_COUNT)
+ task_enable_irq(UART_TX_IRQ(UARTN));
+ task_enable_irq(UART_RX_IRQ(UARTN));
+#endif
+
+ init_done = 1;
+}
+
+int uart_init_done(void)
+{
+ return init_done;
+}
+
+void uart_tx_flush(void)
+{
+ while (!(UART_LSR(UARTN) & UART_LSR_TEMT))
+ ;
+}
+
+int uart_tx_ready(void)
+{
+ return UART_LSR(UARTN) & UART_LSR_THRE;
+}
+
+int uart_rx_available(void)
+{
+ return UART_LSR(UARTN) & UART_LSR_DR;
+}
+
+void uart_write_char(char c)
+{
+ while (!uart_tx_ready())
+ ;
+
+ UART_THR(UARTN) = c;
+}
+
+int uart_read_char(void)
+{
+ return UART_RBR(UARTN);
+}
+
+void uart_tx_start(void)
+{
+ tx_started = 1;
+ if (UART_IER(UARTN) & UART_IER_THRI)
+ return;
+ disable_sleep(SLEEP_MASK_UART);
+ UART_IER(UARTN) |= UART_IER_THRI;
+}
+
+void uart_tx_stop(void)
+{
+ /*
+ * Workaround for b/157541273.
+ * Don't unset the THRI flag unless we are in the UART ISR.
+ *
+ * Note:
+ * MICAUSE denotes current INTC group number.
+ */
+ if (in_interrupt_context() &&
+ read_csr(CSR_VIC_MICAUSE) != UART_INTC_GROUP)
+ return;
+
+ tx_started = 0;
+ UART_IER(UARTN) &= ~UART_IER_THRI;
+ enable_sleep(SLEEP_MASK_UART);
+}
+
+static void uart_process(void)
+{
+ uart_process_input();
+ uart_process_output();
+}
+
+#if (UARTN < SCP_UART_COUNT)
+static void uart_irq_handler(void)
+{
+ extern volatile int ec_int;
+
+ switch (ec_int) {
+ case UART_TX_IRQ(UARTN):
+ uart_process();
+ task_clear_pending_irq(ec_int);
+ break;
+ case UART_RX_IRQ(UARTN):
+ uart_process();
+ SCP_CORE0_INTC_UART_RX_IRQ(UARTN) = BIT(0);
+ asm volatile ("fence.i" ::: "memory");
+ task_clear_pending_irq(ec_int);
+ break;
+ }
+}
+DECLARE_IRQ(UART_INTC_GROUP, uart_irq_handler, 0);
+#else
+
+#ifndef HAS_TASK_APUART
+#error "APUART task hasn't defined in ec.tasklist."
+#endif
+
+void uart_task(void)
+{
+ while (1) {
+ if (uart_rx_available() || tx_started)
+ uart_process();
+ else
+ task_wait_event(UART_IDLE_WAIT_US);
+ }
+}
+#endif