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