123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- /*
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2022 StarFive Technology Co., Ltd.
- *
- * Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
- */
- #include <sbi/riscv_io.h>
- #include <sbi/sbi_console.h>
- #include <sbi_utils/serial/cadence-uart.h>
- /* clang-format off */
- #define UART_REG_CTRL 0x00
- #define UART_REG_MODE 0x04
- #define UART_REG_IDR 0x0C
- #define UART_REG_BRGR 0x18
- #define UART_REG_CSR 0x2C
- #define UART_REG_RFIFO_TFIFO 0x30
- #define UART_REG_BDIVR 0x34
- #define UART_CTRL_RXRES 0x00000001
- #define UART_CTRL_TXRES 0x00000002
- #define UART_CTRL_RXEN 0x00000004
- #define UART_CTRL_RXDIS 0x00000008
- #define UART_CTRL_TXEN 0x00000010
- #define UART_CTRL_TXDIS 0x00000020
- #define UART_MODE_PAR_NONE 0x00000020 /* No parity set */
- #define UART_BRGR_CD_CLKDIVISOR 0x00000001 /* baud_sample = sel_clk */
- #define UART_CSR_REMPTY 0x00000002
- #define UART_CSR_TFUL 0x00000010
- /* clang-format on */
- static volatile void *uart_base;
- static u32 uart_in_freq;
- static u32 uart_baudrate;
- /*
- * Find minimum divisor divides in_freq to max_target_hz;
- * Based on SiFive UART driver (sifive-uart.c)
- */
- static inline unsigned int uart_min_clk_divisor(uint64_t in_freq,
- uint64_t max_target_hz)
- {
- uint64_t quotient = (in_freq + max_target_hz - 1) / (max_target_hz);
- /* Avoid underflow */
- if (quotient == 0)
- return 0;
- else
- return quotient - 1;
- }
- static u32 get_reg(u32 offset)
- {
- return readl(uart_base + offset);
- }
- static void set_reg(u32 offset, u32 val)
- {
- writel(val, uart_base + offset);
- }
- static void cadence_uart_putc(char ch)
- {
- while (get_reg(UART_REG_CSR) & UART_CSR_TFUL)
- ;
- set_reg(UART_REG_RFIFO_TFIFO, ch);
- }
- static int cadence_uart_getc(void)
- {
- u32 ret = get_reg(UART_REG_CSR);
- if (!(ret & UART_CSR_REMPTY))
- return get_reg(UART_REG_RFIFO_TFIFO);
- return -1;
- }
- static struct sbi_console_device cadence_console = {
- .name = "cadence_uart",
- .console_putc = cadence_uart_putc,
- .console_getc = cadence_uart_getc
- };
- int cadence_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
- {
- uart_base = (volatile void *)base;
- uart_in_freq = in_freq;
- uart_baudrate = baudrate;
- /* Disable interrupts */
- set_reg(UART_REG_IDR, 0xFFFFFFFF);
- /* Disable TX RX */
- set_reg(UART_REG_CTRL, UART_CTRL_TXDIS | UART_CTRL_RXDIS);
- /* Configure baudrate */
- if (in_freq && baudrate) {
- set_reg(UART_REG_BRGR, UART_BRGR_CD_CLKDIVISOR);
- set_reg(UART_REG_BDIVR,
- uart_min_clk_divisor(in_freq, baudrate));
- }
- /* Software reset TX RX data path and enable TX RX */
- set_reg(UART_REG_CTRL, UART_CTRL_TXRES | UART_CTRL_RXRES
- | UART_CTRL_TXEN | UART_CTRL_RXEN);
- /*
- * Set:
- * 1 stop bit, bits[07:06] = 0x00,
- * no parity set, bits[05:03] = 0x100,
- * 8 bits character length, bits[02:01] = 0x00,
- * sel_clk = uart_clk, bit[0] = 0x0
- */
- set_reg(UART_REG_MODE, UART_MODE_PAR_NONE);
- sbi_console_set_device(&cadence_console);
- return 0;
- }
|