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