blob: 341728a690fd292f71b7da0dfe859599bce2d7f7 [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
6#include <clk.h>
7#include <common.h>
8#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
25struct uart_sifive {
26 u32 txfifo;
27 u32 rxfifo;
28 u32 txctrl;
29 u32 rxctrl;
30 u32 ie;
31 u32 ip;
32 u32 div;
33};
34
35struct sifive_uart_platdata {
36 unsigned int clock;
37 int saved_input_char;
38 struct uart_sifive *regs;
39};
40
41/* Set up the baud rate in gd struct */
42static void _sifive_serial_setbrg(struct uart_sifive *regs,
43 unsigned long clock, unsigned long baud)
44{
45 writel((u32)((clock / baud) - 1), &regs->div);
46}
47
48static void _sifive_serial_init(struct uart_sifive *regs)
49{
50 writel(UART_TXCTRL_TXEN, &regs->txctrl);
51 writel(UART_RXCTRL_RXEN, &regs->rxctrl);
52 writel(0, &regs->ie);
53}
54
55static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
56{
57 if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
58 return -EAGAIN;
59
60 writel(c, &regs->txfifo);
61
62 return 0;
63}
64
65static int _sifive_serial_getc(struct uart_sifive *regs)
66{
67 int ch = readl(&regs->rxfifo);
68
69 if (ch & UART_RXFIFO_EMPTY)
70 return -EAGAIN;
71 ch &= UART_RXFIFO_DATA;
72
73 return (!ch) ? -EAGAIN : ch;
74}
75
76static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
77{
78 int err;
79 struct clk clk;
80 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
81
82 err = clk_get_by_index(dev, 0, &clk);
83 if (!err) {
84 err = clk_get_rate(&clk);
85 if (!IS_ERR_VALUE(err))
86 platdata->clock = err;
87 } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
88 debug("SiFive UART failed to get clock\n");
89 return err;
90 }
91
92 if (!platdata->clock)
93 platdata->clock = dev_read_u32_default(dev, "clock-frequency", 0);
94 if (!platdata->clock) {
95 debug("SiFive UART clock not defined\n");
96 return -EINVAL;
97 }
98
99 _sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
100
101 return 0;
102}
103
104static int sifive_serial_probe(struct udevice *dev)
105{
106 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
107
108 /* No need to reinitialize the UART after relocation */
109 if (gd->flags & GD_FLG_RELOC)
110 return 0;
111
112 platdata->saved_input_char = 0;
113 _sifive_serial_init(platdata->regs);
114
115 return 0;
116}
117
118static int sifive_serial_getc(struct udevice *dev)
119{
120 int c;
121 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
122 struct uart_sifive *regs = platdata->regs;
123
124 if (platdata->saved_input_char > 0) {
125 c = platdata->saved_input_char;
126 platdata->saved_input_char = 0;
127 return c;
128 }
129
130 while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
131
132 return c;
133}
134
135static int sifive_serial_putc(struct udevice *dev, const char ch)
136{
137 int rc;
138 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
139
140 while ((rc = _sifive_serial_putc(platdata->regs, ch)) == -EAGAIN) ;
141
142 return rc;
143}
144
145static int sifive_serial_pending(struct udevice *dev, bool input)
146{
147 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
148 struct uart_sifive *regs = platdata->regs;
149
150 if (input) {
151 if (platdata->saved_input_char > 0)
152 return 1;
153 platdata->saved_input_char = _sifive_serial_getc(regs);
154 return (platdata->saved_input_char > 0) ? 1 : 0;
155 } else {
156 return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
157 }
158}
159
160static int sifive_serial_ofdata_to_platdata(struct udevice *dev)
161{
162 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
163
164 platdata->regs = (struct uart_sifive *)dev_read_addr(dev);
165 if (IS_ERR(platdata->regs))
166 return PTR_ERR(platdata->regs);
167
168 return 0;
169}
170
171static const struct dm_serial_ops sifive_serial_ops = {
172 .putc = sifive_serial_putc,
173 .getc = sifive_serial_getc,
174 .pending = sifive_serial_pending,
175 .setbrg = sifive_serial_setbrg,
176};
177
178static const struct udevice_id sifive_serial_ids[] = {
179 { .compatible = "sifive,uart0" },
180 { }
181};
182
183U_BOOT_DRIVER(serial_sifive) = {
184 .name = "serial_sifive",
185 .id = UCLASS_SERIAL,
186 .of_match = sifive_serial_ids,
187 .ofdata_to_platdata = sifive_serial_ofdata_to_platdata,
188 .platdata_auto_alloc_size = sizeof(struct sifive_uart_platdata),
189 .probe = sifive_serial_probe,
190 .ops = &sifive_serial_ops,
191};
192
193#ifdef CONFIG_DEBUG_UART_SIFIVE
194static inline void _debug_uart_init(void)
195{
196 struct uart_sifive *regs =
197 (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
198
199 _sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
200 CONFIG_BAUDRATE);
201 _sifive_serial_init(regs);
202}
203
204static inline void _debug_uart_putc(int ch)
205{
206 struct uart_sifive *regs =
207 (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
208
209 while (_sifive_serial_putc(regs, ch) == -EAGAIN)
210 WATCHDOG_RESET();
211}
212
213DEBUG_UART_FUNCS
214
215#endif