blob: 815a0cfb05c9280605190bf53a4f90ec7a289966 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +02002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +02004#include <boot/coreboot_tables.h>
5#include <console/uart.h>
6#include <types.h>
7
8/*
9 * This is a driver for SiFive's own UART, documented in the FU540 manual:
10 * https://www.sifive.com/documentation/chips/freedom-u540-c000-manual/
11 */
12
13struct sifive_uart_registers {
14 uint32_t txdata; /* Transmit data register */
15 uint32_t rxdata; /* Receive data register */
16 uint32_t txctrl; /* Transmit control register */
17 uint32_t rxctrl; /* Receive control register */
18 uint32_t ie; /* UART interrupt enable */
19 uint32_t ip; /* UART interrupt pending */
20 uint32_t div; /* Baud rate divisor */
21} __packed;
22
23#define TXDATA_FULL BIT(31)
24#define RXDATA_EMPTY BIT(31)
25#define TXCTRL_TXEN BIT(0)
26#define TXCTRL_NSTOP_SHIFT 1
27#define TXCTRL_NSTOP(x) (((x)-1) << TXCTRL_NSTOP_SHIFT)
28#define TXCTRL_TXCNT_SHIFT 16
29#define TXCTRL_TXCNT(x) ((x) << TXCTRL_TXCNT_SHIFT)
30#define RXCTRL_RXEN BIT(0)
31#define RXCTRL_RXCNT_SHIFT 16
32#define RXCTRL_RXCNT(x) ((x) << RXCTRL_RXCNT_SHIFT)
33#define IP_TXWM BIT(0)
34#define IP_RXWM BIT(1)
35
Philipp Hug75244002018-07-07 21:34:31 +020036static void sifive_uart_init(struct sifive_uart_registers *regs, int div)
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +020037{
Philipp Hug75244002018-07-07 21:34:31 +020038 /* Configure the divisor */
39 write32(&regs->div, div);
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +020040
41 /* Enable transmission, one stop bit, transmit watermark at 1 */
42 write32(&regs->txctrl, TXCTRL_TXEN|TXCTRL_NSTOP(1)|TXCTRL_TXCNT(1));
43
44 /* Enable reception, receive watermark at 0 */
45 write32(&regs->rxctrl, RXCTRL_RXEN|RXCTRL_RXCNT(0));
46}
47
Felix Helde3a12472020-09-11 15:47:09 +020048void uart_init(unsigned int idx)
Philipp Hug75244002018-07-07 21:34:31 +020049{
Maximilian Brunea2eca492024-01-14 20:06:10 +060050 /*
51 * according to FU540/FU740 manual:
52 * f_baud = f_in / (div + 1)
53 * <=>
54 * div = (f_in / f_baud) - 1
55 */
56 unsigned int div = uart_baudrate_divisor(get_uart_baudrate(), uart_platform_refclk(),
57 uart_input_clock_divider());
58 div -= 1;
59
Philipp Hug75244002018-07-07 21:34:31 +020060 sifive_uart_init(uart_platform_baseptr(idx), div);
61}
62
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +020063static bool uart_can_tx(struct sifive_uart_registers *regs)
64{
65 return !(read32(&regs->txdata) & TXDATA_FULL);
66}
67
Felix Helde3a12472020-09-11 15:47:09 +020068void uart_tx_byte(unsigned int idx, unsigned char data)
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +020069{
70 struct sifive_uart_registers *regs = uart_platform_baseptr(idx);
71
72 while (!uart_can_tx(regs))
73 ; /* TODO: implement a timeout */
74
75 write32(&regs->txdata, data);
76}
77
Felix Helde3a12472020-09-11 15:47:09 +020078void uart_tx_flush(unsigned int idx)
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +020079{
80 struct sifive_uart_registers *regs = uart_platform_baseptr(idx);
81 uint32_t ip;
82
83 /* Use the TX watermark bit to find out if the TX FIFO is empty */
84 do {
85 ip = read32(&regs->ip);
86 } while (!(ip & IP_TXWM));
87}
88
Felix Helde3a12472020-09-11 15:47:09 +020089unsigned char uart_rx_byte(unsigned int idx)
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +020090{
91 struct sifive_uart_registers *regs = uart_platform_baseptr(idx);
92 uint32_t rxdata;
93
94 do {
95 rxdata = read32(&regs->rxdata);
96 } while (rxdata & RXDATA_EMPTY);
97
98 return rxdata & 0xff;
99}
100
101unsigned int uart_input_clock_divider(void)
102{
103 /*
104 * The SiFive UART handles oversampling internally. The divided clock
105 * is the baud clock.
106 */
107 return 1;
108}
109
Arthur Heymans9948c522022-10-24 14:37:40 +0200110enum cb_err fill_lb_serial(struct lb_serial *serial)
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +0200111{
Arthur Heymans9948c522022-10-24 14:37:40 +0200112 return CB_ERR;
Jonathan Neuschäfer894e3a92018-04-19 16:23:54 +0200113 /* TODO */
114}