1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
8 #include <debug_uart.h>
14 #include <linux/compiler.h>
17 DECLARE_GLOBAL_DATA_PTR;
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
35 struct sifive_uart_platdata {
38 struct uart_sifive *regs;
41 /* Set up the baud rate in gd struct */
42 static void _sifive_serial_setbrg(struct uart_sifive *regs,
43 unsigned long clock, unsigned long baud)
45 writel((u32)((clock / baud) - 1), ®s->div);
48 static void _sifive_serial_init(struct uart_sifive *regs)
50 writel(UART_TXCTRL_TXEN, ®s->txctrl);
51 writel(UART_RXCTRL_RXEN, ®s->rxctrl);
55 static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
57 if (readl(®s->txfifo) & UART_TXFIFO_FULL)
60 writel(c, ®s->txfifo);
65 static int _sifive_serial_getc(struct uart_sifive *regs)
67 int ch = readl(®s->rxfifo);
69 if (ch & UART_RXFIFO_EMPTY)
71 ch &= UART_RXFIFO_DATA;
73 return (!ch) ? -EAGAIN : ch;
76 static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
80 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
82 err = clk_get_by_index(dev, 0, &clk);
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");
93 platdata->clock = dev_read_u32_default(dev, "clock-frequency", 0);
94 if (!platdata->clock) {
95 debug("SiFive UART clock not defined\n");
99 _sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
104 static int sifive_serial_probe(struct udevice *dev)
106 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
108 /* No need to reinitialize the UART after relocation */
109 if (gd->flags & GD_FLG_RELOC)
112 platdata->saved_input_char = 0;
113 _sifive_serial_init(platdata->regs);
118 static int sifive_serial_getc(struct udevice *dev)
121 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
122 struct uart_sifive *regs = platdata->regs;
124 if (platdata->saved_input_char > 0) {
125 c = platdata->saved_input_char;
126 platdata->saved_input_char = 0;
130 while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
135 static int sifive_serial_putc(struct udevice *dev, const char ch)
138 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
140 while ((rc = _sifive_serial_putc(platdata->regs, ch)) == -EAGAIN) ;
145 static int sifive_serial_pending(struct udevice *dev, bool input)
147 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
148 struct uart_sifive *regs = platdata->regs;
151 if (platdata->saved_input_char > 0)
153 platdata->saved_input_char = _sifive_serial_getc(regs);
154 return (platdata->saved_input_char > 0) ? 1 : 0;
156 return !!(readl(®s->txfifo) & UART_TXFIFO_FULL);
160 static int sifive_serial_ofdata_to_platdata(struct udevice *dev)
162 struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
164 platdata->regs = (struct uart_sifive *)dev_read_addr(dev);
165 if (IS_ERR(platdata->regs))
166 return PTR_ERR(platdata->regs);
171 static 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,
178 static const struct udevice_id sifive_serial_ids[] = {
179 { .compatible = "sifive,uart0" },
183 U_BOOT_DRIVER(serial_sifive) = {
184 .name = "serial_sifive",
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,
193 #ifdef CONFIG_DEBUG_UART_SIFIVE
194 static inline void _debug_uart_init(void)
196 struct uart_sifive *regs =
197 (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
199 _sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
201 _sifive_serial_init(regs);
204 static inline void _debug_uart_putc(int ch)
206 struct uart_sifive *regs =
207 (struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
209 while (_sifive_serial_putc(regs, ch) == -EAGAIN)