c142ccdf3d57bb376496b88da95fc67570b9a1ec
[oweals/u-boot.git] / drivers / serial / serial_sifive.c
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 <watchdog.h>
13 #include <asm/io.h>
14 #include <linux/compiler.h>
15 #include <serial.h>
16
17 DECLARE_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
25 /* IP register */
26 #define UART_IP_RXWM            0x2
27
28 struct 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
38 struct sifive_uart_platdata {
39         unsigned long clock;
40         struct uart_sifive *regs;
41 };
42
43 /**
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  */
55 static 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
67 /* Set up the baud rate in gd struct */
68 static void _sifive_serial_setbrg(struct uart_sifive *regs,
69                                   unsigned long clock, unsigned long baud)
70 {
71         writel((uart_min_clk_divisor(clock, baud)), &regs->div);
72 }
73
74 static 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
81 static 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
91 static 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
99         return ch;
100 }
101
102 static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
103 {
104         int ret;
105         struct clk clk;
106         struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
107         u32 clock = 0;
108
109         ret = clk_get_by_index(dev, 0, &clk);
110         if (IS_ERR_VALUE(ret)) {
111                 debug("SiFive UART failed to get clock\n");
112                 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                 }
123         }
124         platdata->clock = clock;
125         _sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
126
127         return 0;
128 }
129
130 static 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
138         _sifive_serial_init(platdata->regs);
139
140         return 0;
141 }
142
143 static 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
149         while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
150
151         return c;
152 }
153
154 static 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
164 static 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
169         if (input)
170                 return (readl(&regs->ip) & UART_IP_RXWM);
171         else
172                 return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
173 }
174
175 static 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
186 static 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
193 static const struct udevice_id sifive_serial_ids[] = {
194         { .compatible = "sifive,uart0" },
195         { }
196 };
197
198 U_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
209 static 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
219 static 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
228 DEBUG_UART_FUNCS
229
230 #endif