1*298fa2dbSYu-Chien Peter Lin // SPDX-License-Identifier: BSD-2-Clause
2*298fa2dbSYu-Chien Peter Lin /*
3*298fa2dbSYu-Chien Peter Lin * Copyright (c) 2025 SiFive, Inc
4*298fa2dbSYu-Chien Peter Lin */
5*298fa2dbSYu-Chien Peter Lin
6*298fa2dbSYu-Chien Peter Lin #include <drivers/sifive_uart.h>
7*298fa2dbSYu-Chien Peter Lin #include <io.h>
8*298fa2dbSYu-Chien Peter Lin
9*298fa2dbSYu-Chien Peter Lin /* SiFive UART register defines */
10*298fa2dbSYu-Chien Peter Lin #define UART_REG_TXFIFO 0x0
11*298fa2dbSYu-Chien Peter Lin #define UART_REG_RXFIFO 0x4
12*298fa2dbSYu-Chien Peter Lin #define UART_REG_TXCTRL 0x8
13*298fa2dbSYu-Chien Peter Lin #define UART_REG_RXCTRL 0xC
14*298fa2dbSYu-Chien Peter Lin #define UART_REG_IE 0x10
15*298fa2dbSYu-Chien Peter Lin #define UART_REG_IP 0x14
16*298fa2dbSYu-Chien Peter Lin #define UART_REG_DIV 0x18
17*298fa2dbSYu-Chien Peter Lin
18*298fa2dbSYu-Chien Peter Lin /* SiFive UART status register bits */
19*298fa2dbSYu-Chien Peter Lin #define UART_TXFIFO_FULL 0x80000000
20*298fa2dbSYu-Chien Peter Lin #define UART_RXFIFO_EMPTY 0x80000000
21*298fa2dbSYu-Chien Peter Lin #define UART_RXFIFO_DATA 0x000000FF
22*298fa2dbSYu-Chien Peter Lin #define UART_TXCTRL_TXEN 0x1
23*298fa2dbSYu-Chien Peter Lin #define UART_RXCTRL_RXEN 0x1
24*298fa2dbSYu-Chien Peter Lin
chip_to_base(struct serial_chip * chip)25*298fa2dbSYu-Chien Peter Lin static vaddr_t chip_to_base(struct serial_chip *chip)
26*298fa2dbSYu-Chien Peter Lin {
27*298fa2dbSYu-Chien Peter Lin struct sifive_uart_data *pd =
28*298fa2dbSYu-Chien Peter Lin container_of(chip, struct sifive_uart_data, chip);
29*298fa2dbSYu-Chien Peter Lin
30*298fa2dbSYu-Chien Peter Lin return io_pa_or_va(&pd->base, SIFIVE_UART_REG_SIZE);
31*298fa2dbSYu-Chien Peter Lin }
32*298fa2dbSYu-Chien Peter Lin
sifive_uart_flush(struct serial_chip * chip)33*298fa2dbSYu-Chien Peter Lin static void sifive_uart_flush(struct serial_chip *chip)
34*298fa2dbSYu-Chien Peter Lin {
35*298fa2dbSYu-Chien Peter Lin vaddr_t base = chip_to_base(chip);
36*298fa2dbSYu-Chien Peter Lin
37*298fa2dbSYu-Chien Peter Lin while (io_read32(base + UART_REG_TXFIFO) & UART_TXFIFO_FULL) {
38*298fa2dbSYu-Chien Peter Lin /* Wait until transmit FIFO is not full */
39*298fa2dbSYu-Chien Peter Lin ;
40*298fa2dbSYu-Chien Peter Lin }
41*298fa2dbSYu-Chien Peter Lin }
42*298fa2dbSYu-Chien Peter Lin
sifive_uart_have_rx_data(struct serial_chip * chip)43*298fa2dbSYu-Chien Peter Lin static bool sifive_uart_have_rx_data(struct serial_chip *chip)
44*298fa2dbSYu-Chien Peter Lin {
45*298fa2dbSYu-Chien Peter Lin vaddr_t base = chip_to_base(chip);
46*298fa2dbSYu-Chien Peter Lin
47*298fa2dbSYu-Chien Peter Lin return !(io_read32(base + UART_REG_RXFIFO) & UART_RXFIFO_EMPTY);
48*298fa2dbSYu-Chien Peter Lin }
49*298fa2dbSYu-Chien Peter Lin
sifive_uart_getchar(struct serial_chip * chip)50*298fa2dbSYu-Chien Peter Lin static int sifive_uart_getchar(struct serial_chip *chip)
51*298fa2dbSYu-Chien Peter Lin {
52*298fa2dbSYu-Chien Peter Lin vaddr_t base = chip_to_base(chip);
53*298fa2dbSYu-Chien Peter Lin
54*298fa2dbSYu-Chien Peter Lin while (!sifive_uart_have_rx_data(chip)) {
55*298fa2dbSYu-Chien Peter Lin /* Wait until data is available in the receive FIFO */
56*298fa2dbSYu-Chien Peter Lin ;
57*298fa2dbSYu-Chien Peter Lin }
58*298fa2dbSYu-Chien Peter Lin return io_read32(base + UART_REG_RXFIFO) & UART_RXFIFO_DATA;
59*298fa2dbSYu-Chien Peter Lin }
60*298fa2dbSYu-Chien Peter Lin
sifive_uart_putc(struct serial_chip * chip,int ch)61*298fa2dbSYu-Chien Peter Lin static void sifive_uart_putc(struct serial_chip *chip, int ch)
62*298fa2dbSYu-Chien Peter Lin {
63*298fa2dbSYu-Chien Peter Lin vaddr_t base = chip_to_base(chip);
64*298fa2dbSYu-Chien Peter Lin
65*298fa2dbSYu-Chien Peter Lin sifive_uart_flush(chip);
66*298fa2dbSYu-Chien Peter Lin
67*298fa2dbSYu-Chien Peter Lin /* Write out character to transmit FIFO */
68*298fa2dbSYu-Chien Peter Lin io_write32(base + UART_REG_TXFIFO, ch);
69*298fa2dbSYu-Chien Peter Lin }
70*298fa2dbSYu-Chien Peter Lin
71*298fa2dbSYu-Chien Peter Lin static const struct serial_ops sifive_uart_ops = {
72*298fa2dbSYu-Chien Peter Lin .flush = sifive_uart_flush,
73*298fa2dbSYu-Chien Peter Lin .getchar = sifive_uart_getchar,
74*298fa2dbSYu-Chien Peter Lin .have_rx_data = sifive_uart_have_rx_data,
75*298fa2dbSYu-Chien Peter Lin .putc = sifive_uart_putc,
76*298fa2dbSYu-Chien Peter Lin };
77*298fa2dbSYu-Chien Peter Lin
sifive_uart_init(struct sifive_uart_data * pd,paddr_t base,uint32_t uart_clk,uint32_t baud_rate)78*298fa2dbSYu-Chien Peter Lin void sifive_uart_init(struct sifive_uart_data *pd, paddr_t base,
79*298fa2dbSYu-Chien Peter Lin uint32_t uart_clk, uint32_t baud_rate)
80*298fa2dbSYu-Chien Peter Lin {
81*298fa2dbSYu-Chien Peter Lin uint32_t divisor = 0;
82*298fa2dbSYu-Chien Peter Lin
83*298fa2dbSYu-Chien Peter Lin pd->base.pa = base;
84*298fa2dbSYu-Chien Peter Lin pd->chip.ops = &sifive_uart_ops;
85*298fa2dbSYu-Chien Peter Lin
86*298fa2dbSYu-Chien Peter Lin /* Configure baudrate */
87*298fa2dbSYu-Chien Peter Lin if (uart_clk && baud_rate) {
88*298fa2dbSYu-Chien Peter Lin divisor = (uart_clk + baud_rate - 1) / baud_rate - 1;
89*298fa2dbSYu-Chien Peter Lin io_write32(base + UART_REG_DIV, divisor);
90*298fa2dbSYu-Chien Peter Lin }
91*298fa2dbSYu-Chien Peter Lin
92*298fa2dbSYu-Chien Peter Lin /* Disable interrupts */
93*298fa2dbSYu-Chien Peter Lin io_write32(base + UART_REG_IE, 0);
94*298fa2dbSYu-Chien Peter Lin
95*298fa2dbSYu-Chien Peter Lin /* Enable TX */
96*298fa2dbSYu-Chien Peter Lin io_write32(base + UART_REG_TXCTRL, UART_TXCTRL_TXEN);
97*298fa2dbSYu-Chien Peter Lin
98*298fa2dbSYu-Chien Peter Lin /* Enable RX */
99*298fa2dbSYu-Chien Peter Lin io_write32(base + UART_REG_RXCTRL, UART_RXCTRL_RXEN);
100*298fa2dbSYu-Chien Peter Lin }
101