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