blob: c142ccdf3d57bb376496b88da95fc67570b9a1ec [file] [log] [blame]
Anup Patel4b1d68f2018-12-15 11:35:15 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
4 */
5
Anup Patel4b1d68f2018-12-15 11:35:15 +05306#include <common.h>
Jagan Teki9ee724f2019-05-08 19:56:16 +05307#include <clk.h>
Anup Patel4b1d68f2018-12-15 11:35:15 +05308#include <debug_uart.h>
9#include <dm.h>
10#include <errno.h>
11#include <fdtdec.h>
12#include <watchdog.h>
13#include <asm/io.h>
14#include <linux/compiler.h>
15#include <serial.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
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
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -070025/* IP register */
26#define UART_IP_RXWM 0x2
27
Anup Patel4b1d68f2018-12-15 11:35:15 +053028struct uart_sifive {
29 u32 txfifo;
30 u32 rxfifo;
31 u32 txctrl;
32 u32 rxctrl;
33 u32 ie;
34 u32 ip;
35 u32 div;
36};
37
38struct sifive_uart_platdata {
Atish Patrabc922d42019-02-25 08:15:02 +000039 unsigned long clock;
Anup Patel4b1d68f2018-12-15 11:35:15 +053040 struct uart_sifive *regs;
41};
42
Atish Patrabc922d42019-02-25 08:15:02 +000043/**
44 * Find minimum divisor divides in_freq to max_target_hz;
45 * Based on uart driver n SiFive FSBL.
46 *
47 * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
48 * The nearest integer solution requires rounding up as to not exceed
49 * max_target_hz.
50 * div = ceil(f_in / f_baud) - 1
51 * = floor((f_in - 1 + f_baud) / f_baud) - 1
52 * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
53 * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
54 */
55static inline unsigned int uart_min_clk_divisor(unsigned long in_freq,
56 unsigned long max_target_hz)
57{
58 unsigned long quotient =
59 (in_freq + max_target_hz - 1) / (max_target_hz);
60 /* Avoid underflow */
61 if (quotient == 0)
62 return 0;
63 else
64 return quotient - 1;
65}
66
Anup Patel4b1d68f2018-12-15 11:35:15 +053067/* Set up the baud rate in gd struct */
68static void _sifive_serial_setbrg(struct uart_sifive *regs,
69 unsigned long clock, unsigned long baud)
70{
Atish Patrabc922d42019-02-25 08:15:02 +000071 writel((uart_min_clk_divisor(clock, baud)), &regs->div);
Anup Patel4b1d68f2018-12-15 11:35:15 +053072}
73
74static void _sifive_serial_init(struct uart_sifive *regs)
75{
76 writel(UART_TXCTRL_TXEN, &regs->txctrl);
77 writel(UART_RXCTRL_RXEN, &regs->rxctrl);
78 writel(0, &regs->ie);
79}
80
81static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
82{
83 if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
84 return -EAGAIN;
85
86 writel(c, &regs->txfifo);
87
88 return 0;
89}
90
91static int _sifive_serial_getc(struct uart_sifive *regs)
92{
93 int ch = readl(&regs->rxfifo);
94
95 if (ch & UART_RXFIFO_EMPTY)
96 return -EAGAIN;
97 ch &= UART_RXFIFO_DATA;
98
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -070099 return ch;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530100}
101
102static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
103{
Atish Patra574fa692019-02-25 08:15:08 +0000104 int ret;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530105 struct clk clk;
106 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
Atish Patra574fa692019-02-25 08:15:08 +0000107 u32 clock = 0;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530108
Atish Patra574fa692019-02-25 08:15:08 +0000109 ret = clk_get_by_index(dev, 0, &clk);
110 if (IS_ERR_VALUE(ret)) {
Anup Patel4b1d68f2018-12-15 11:35:15 +0530111 debug("SiFive UART failed to get clock\n");
Atish Patra574fa692019-02-25 08:15:08 +0000112 ret = dev_read_u32(dev, "clock-frequency", &clock);
113 if (IS_ERR_VALUE(ret)) {
114 debug("SiFive UART clock not defined\n");
115 return 0;
116 }
117 } else {
118 clock = clk_get_rate(&clk);
119 if (IS_ERR_VALUE(clock)) {
120 debug("SiFive UART clock get rate failed\n");
121 return 0;
122 }
Anup Patel4b1d68f2018-12-15 11:35:15 +0530123 }
Atish Patra574fa692019-02-25 08:15:08 +0000124 platdata->clock = clock;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530125 _sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
126
127 return 0;
128}
129
130static int sifive_serial_probe(struct udevice *dev)
131{
132 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
133
134 /* No need to reinitialize the UART after relocation */
135 if (gd->flags & GD_FLG_RELOC)
136 return 0;
137
Anup Patel4b1d68f2018-12-15 11:35:15 +0530138 _sifive_serial_init(platdata->regs);
139
140 return 0;
141}
142
143static int sifive_serial_getc(struct udevice *dev)
144{
145 int c;
146 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
147 struct uart_sifive *regs = platdata->regs;
148
Anup Patel4b1d68f2018-12-15 11:35:15 +0530149 while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
150
151 return c;
152}
153
154static int sifive_serial_putc(struct udevice *dev, const char ch)
155{
156 int rc;
157 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
158
159 while ((rc = _sifive_serial_putc(platdata->regs, ch)) == -EAGAIN) ;
160
161 return rc;
162}
163
164static int sifive_serial_pending(struct udevice *dev, bool input)
165{
166 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
167 struct uart_sifive *regs = platdata->regs;
168
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -0700169 if (input)
170 return (readl(&regs->ip) & UART_IP_RXWM);
171 else
Anup Patel4b1d68f2018-12-15 11:35:15 +0530172 return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530173}
174
175static int sifive_serial_ofdata_to_platdata(struct udevice *dev)
176{
177 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
178
179 platdata->regs = (struct uart_sifive *)dev_read_addr(dev);
180 if (IS_ERR(platdata->regs))
181 return PTR_ERR(platdata->regs);
182
183 return 0;
184}
185
186static const struct dm_serial_ops sifive_serial_ops = {
187 .putc = sifive_serial_putc,
188 .getc = sifive_serial_getc,
189 .pending = sifive_serial_pending,
190 .setbrg = sifive_serial_setbrg,
191};
192
193static const struct udevice_id sifive_serial_ids[] = {
194 { .compatible = "sifive,uart0" },
195 { }
196};
197
198U_BOOT_DRIVER(serial_sifive) = {
199 .name = "serial_sifive",
200 .id = UCLASS_SERIAL,
201 .of_match = sifive_serial_ids,
202 .ofdata_to_platdata = sifive_serial_ofdata_to_platdata,
203 .platdata_auto_alloc_size = sizeof(struct sifive_uart_platdata),
204 .probe = sifive_serial_probe,
205 .ops = &sifive_serial_ops,
206};
207
208#ifdef CONFIG_DEBUG_UART_SIFIVE
209static inline void _debug_uart_init(void)
210{
211 struct uart_sifive *regs =
212 (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
213
214 _sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
215 CONFIG_BAUDRATE);
216 _sifive_serial_init(regs);
217}
218
219static inline void _debug_uart_putc(int ch)
220{
221 struct uart_sifive *regs =
222 (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
223
224 while (_sifive_serial_putc(regs, ch) == -EAGAIN)
225 WATCHDOG_RESET();
226}
227
228DEBUG_UART_FUNCS
229
230#endif