xref: /optee_os/core/drivers/sifive_uart.c (revision 298fa2dbcfbd65cc2470a01993878e92ae69d9f4)
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