1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
4 */
5
6#include <common.h>
7#include <clk.h>
8#include <debug_uart.h>
9#include <dm.h>
10#include <errno.h>
11#include <fdtdec.h>
12#include <log.h>
13#include <watchdog.h>
14#include <asm/global_data.h>
15#include <asm/io.h>
16#include <linux/compiler.h>
17#include <serial.h>
18#include <linux/err.h>
19
20DECLARE_GLOBAL_DATA_PTR;
21
22#define UART_TXFIFO_FULL	0x80000000
23#define UART_RXFIFO_EMPTY	0x80000000
24#define UART_RXFIFO_DATA	0x000000ff
25#define UART_TXCTRL_TXEN	0x1
26#define UART_RXCTRL_RXEN	0x1
27
28/* IP register */
29#define UART_IP_RXWM            0x2
30
31struct uart_sifive {
32	u32 txfifo;
33	u32 rxfifo;
34	u32 txctrl;
35	u32 rxctrl;
36	u32 ie;
37	u32 ip;
38	u32 div;
39};
40
41struct sifive_uart_plat {
42	unsigned long clock;
43	struct uart_sifive *regs;
44};
45
46/**
47 * Find minimum divisor divides in_freq to max_target_hz;
48 * Based on uart driver n SiFive FSBL.
49 *
50 * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
51 * The nearest integer solution requires rounding up as to not exceed
52 * max_target_hz.
53 * div  = ceil(f_in / f_baud) - 1
54 *	= floor((f_in - 1 + f_baud) / f_baud) - 1
55 * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
56 * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
57 */
58static inline unsigned int uart_min_clk_divisor(unsigned long in_freq,
59						unsigned long max_target_hz)
60{
61	unsigned long quotient =
62			(in_freq + max_target_hz - 1) / (max_target_hz);
63	/* Avoid underflow */
64	if (quotient == 0)
65		return 0;
66	else
67		return quotient - 1;
68}
69
70/* Set up the baud rate in gd struct */
71static void _sifive_serial_setbrg(struct uart_sifive *regs,
72				  unsigned long clock, unsigned long baud)
73{
74	writel((uart_min_clk_divisor(clock, baud)), &regs->div);
75}
76
77static void _sifive_serial_init(struct uart_sifive *regs)
78{
79	writel(UART_TXCTRL_TXEN, &regs->txctrl);
80	writel(UART_RXCTRL_RXEN, &regs->rxctrl);
81	writel(0, &regs->ie);
82}
83
84static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
85{
86	if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
87		return -EAGAIN;
88
89	writel(c, &regs->txfifo);
90
91	return 0;
92}
93
94static int _sifive_serial_getc(struct uart_sifive *regs)
95{
96	int ch = readl(&regs->rxfifo);
97
98	if (ch & UART_RXFIFO_EMPTY)
99		return -EAGAIN;
100	ch &= UART_RXFIFO_DATA;
101
102	return ch;
103}
104
105static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
106{
107	int ret;
108	struct clk clk;
109	struct sifive_uart_plat *plat = dev_get_plat(dev);
110	u32 clock = 0;
111
112	ret = clk_get_by_index(dev, 0, &clk);
113	if (IS_ERR_VALUE(ret)) {
114		debug("SiFive UART failed to get clock\n");
115		ret = dev_read_u32(dev, "clock-frequency", &clock);
116		if (IS_ERR_VALUE(ret)) {
117			debug("SiFive UART clock not defined\n");
118			return 0;
119		}
120	} else {
121		clock = clk_get_rate(&clk);
122		if (IS_ERR_VALUE(clock)) {
123			debug("SiFive UART clock get rate failed\n");
124			return 0;
125		}
126	}
127	plat->clock = clock;
128	_sifive_serial_setbrg(plat->regs, plat->clock, baudrate);
129
130	return 0;
131}
132
133static int sifive_serial_probe(struct udevice *dev)
134{
135	struct sifive_uart_plat *plat = dev_get_plat(dev);
136
137	/* No need to reinitialize the UART after relocation */
138	if (gd->flags & GD_FLG_RELOC)
139		return 0;
140
141	_sifive_serial_init(plat->regs);
142
143	return 0;
144}
145
146static int sifive_serial_getc(struct udevice *dev)
147{
148	int c;
149	struct sifive_uart_plat *plat = dev_get_plat(dev);
150	struct uart_sifive *regs = plat->regs;
151
152	while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
153
154	return c;
155}
156
157static int sifive_serial_putc(struct udevice *dev, const char ch)
158{
159	int rc;
160	struct sifive_uart_plat *plat = dev_get_plat(dev);
161
162	while ((rc = _sifive_serial_putc(plat->regs, ch)) == -EAGAIN) ;
163
164	return rc;
165}
166
167static int sifive_serial_pending(struct udevice *dev, bool input)
168{
169	struct sifive_uart_plat *plat = dev_get_plat(dev);
170	struct uart_sifive *regs = plat->regs;
171
172	if (input)
173		return (readl(&regs->ip) & UART_IP_RXWM);
174	else
175		return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
176}
177
178static int sifive_serial_of_to_plat(struct udevice *dev)
179{
180	struct sifive_uart_plat *plat = dev_get_plat(dev);
181
182	plat->regs = (struct uart_sifive *)(uintptr_t)dev_read_addr(dev);
183	if (IS_ERR(plat->regs))
184		return PTR_ERR(plat->regs);
185
186	return 0;
187}
188
189static const struct dm_serial_ops sifive_serial_ops = {
190	.putc = sifive_serial_putc,
191	.getc = sifive_serial_getc,
192	.pending = sifive_serial_pending,
193	.setbrg = sifive_serial_setbrg,
194};
195
196static const struct udevice_id sifive_serial_ids[] = {
197	{ .compatible = "sifive,uart0" },
198	{ }
199};
200
201U_BOOT_DRIVER(serial_sifive) = {
202	.name	= "serial_sifive",
203	.id	= UCLASS_SERIAL,
204	.of_match = sifive_serial_ids,
205	.of_to_plat = sifive_serial_of_to_plat,
206	.plat_auto	= sizeof(struct sifive_uart_plat),
207	.probe = sifive_serial_probe,
208	.ops	= &sifive_serial_ops,
209};
210
211#ifdef CONFIG_DEBUG_UART_SIFIVE
212static inline void _debug_uart_init(void)
213{
214	struct uart_sifive *regs =
215			(struct uart_sifive *)CONFIG_VAL(DEBUG_UART_BASE);
216
217	_sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
218			      CONFIG_BAUDRATE);
219	_sifive_serial_init(regs);
220}
221
222static inline void _debug_uart_putc(int ch)
223{
224	struct uart_sifive *regs =
225			(struct uart_sifive *)CONFIG_VAL(DEBUG_UART_BASE);
226
227	while (_sifive_serial_putc(regs, ch) == -EAGAIN)
228		schedule();
229}
230
231DEBUG_UART_FUNCS
232
233#endif
234