diff options
author | Tzung-Bi Shih <tzungbi@chromium.org> | 2021-06-24 17:17:39 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-06-25 03:42:30 +0000 |
commit | b409fd3b5ac6a82b6851f2e9af49761ee2d4766c (patch) | |
tree | 780a069f10a57222362a209abee19b27b7de9076 /chip/mt_scp/rv32i_common/uart.c | |
parent | cf92cf3c6c4135b511c8f7f6bc83036167b7c735 (diff) | |
download | chrome-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.c | 171 |
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 |