blob: 97bf20c967ad87ce5bbd100652a9503f74e15155 [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
Anup Patel4b1d68f2018-12-15 11:35:15 +05306#include <common.h>
Jagan Teki9ee724f2019-05-08 19:56:16 +05307#include <clk.h>
Anup Patel4b1d68f2018-12-15 11:35:15 +05308#include <debug_uart.h>
9#include <dm.h>
10#include <errno.h>
11#include <fdtdec.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Anup Patel4b1d68f2018-12-15 11:35:15 +053013#include <watchdog.h>
14#include <asm/io.h>
15#include <linux/compiler.h>
16#include <serial.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Anup Patel4b1d68f2018-12-15 11:35:15 +053018
19DECLARE_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
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -070027/* IP register */
28#define UART_IP_RXWM 0x2
29
Anup Patel4b1d68f2018-12-15 11:35:15 +053030struct 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
Simon Glassb75b15b2020-12-03 16:55:23 -070040struct sifive_uart_plat {
Atish Patrabc922d42019-02-25 08:15:02 +000041 unsigned long clock;
Anup Patel4b1d68f2018-12-15 11:35:15 +053042 struct uart_sifive *regs;
43};
44
Atish Patrabc922d42019-02-25 08:15:02 +000045/**
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 */
57static 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
Anup Patel4b1d68f2018-12-15 11:35:15 +053069/* Set up the baud rate in gd struct */
70static void _sifive_serial_setbrg(struct uart_sifive *regs,
71 unsigned long clock, unsigned long baud)
72{
Atish Patrabc922d42019-02-25 08:15:02 +000073 writel((uart_min_clk_divisor(clock, baud)), &regs->div);
Anup Patel4b1d68f2018-12-15 11:35:15 +053074}
75
76static 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
83static 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
93static 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
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -0700101 return ch;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530102}
103
104static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
105{
Atish Patra574fa692019-02-25 08:15:08 +0000106 int ret;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530107 struct clk clk;
Simon Glassb75b15b2020-12-03 16:55:23 -0700108 struct sifive_uart_plat *plat = dev_get_plat(dev);
Atish Patra574fa692019-02-25 08:15:08 +0000109 u32 clock = 0;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530110
Atish Patra574fa692019-02-25 08:15:08 +0000111 ret = clk_get_by_index(dev, 0, &clk);
112 if (IS_ERR_VALUE(ret)) {
Anup Patel4b1d68f2018-12-15 11:35:15 +0530113 debug("SiFive UART failed to get clock\n");
Atish Patra574fa692019-02-25 08:15:08 +0000114 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 }
Anup Patel4b1d68f2018-12-15 11:35:15 +0530125 }
Simon Glass71fa5b42020-12-03 16:55:18 -0700126 plat->clock = clock;
127 _sifive_serial_setbrg(plat->regs, plat->clock, baudrate);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530128
129 return 0;
130}
131
132static int sifive_serial_probe(struct udevice *dev)
133{
Simon Glassb75b15b2020-12-03 16:55:23 -0700134 struct sifive_uart_plat *plat = dev_get_plat(dev);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530135
136 /* No need to reinitialize the UART after relocation */
137 if (gd->flags & GD_FLG_RELOC)
138 return 0;
139
Simon Glass71fa5b42020-12-03 16:55:18 -0700140 _sifive_serial_init(plat->regs);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530141
142 return 0;
143}
144
145static int sifive_serial_getc(struct udevice *dev)
146{
147 int c;
Simon Glassb75b15b2020-12-03 16:55:23 -0700148 struct sifive_uart_plat *plat = dev_get_plat(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700149 struct uart_sifive *regs = plat->regs;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530150
Anup Patel4b1d68f2018-12-15 11:35:15 +0530151 while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
152
153 return c;
154}
155
156static int sifive_serial_putc(struct udevice *dev, const char ch)
157{
158 int rc;
Simon Glassb75b15b2020-12-03 16:55:23 -0700159 struct sifive_uart_plat *plat = dev_get_plat(dev);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530160
Simon Glass71fa5b42020-12-03 16:55:18 -0700161 while ((rc = _sifive_serial_putc(plat->regs, ch)) == -EAGAIN) ;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530162
163 return rc;
164}
165
166static int sifive_serial_pending(struct udevice *dev, bool input)
167{
Simon Glassb75b15b2020-12-03 16:55:23 -0700168 struct sifive_uart_plat *plat = dev_get_plat(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700169 struct uart_sifive *regs = plat->regs;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530170
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -0700171 if (input)
172 return (readl(&regs->ip) & UART_IP_RXWM);
173 else
Anup Patel4b1d68f2018-12-15 11:35:15 +0530174 return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530175}
176
Simon Glassaad29ae2020-12-03 16:55:21 -0700177static int sifive_serial_of_to_plat(struct udevice *dev)
Anup Patel4b1d68f2018-12-15 11:35:15 +0530178{
Simon Glassb75b15b2020-12-03 16:55:23 -0700179 struct sifive_uart_plat *plat = dev_get_plat(dev);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530180
Bin Mengb934fd22021-01-31 20:36:00 +0800181 plat->regs = (struct uart_sifive *)(uintptr_t)dev_read_addr(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700182 if (IS_ERR(plat->regs))
183 return PTR_ERR(plat->regs);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530184
185 return 0;
186}
187
188static 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
195static const struct udevice_id sifive_serial_ids[] = {
196 { .compatible = "sifive,uart0" },
197 { }
198};
199
200U_BOOT_DRIVER(serial_sifive) = {
201 .name = "serial_sifive",
202 .id = UCLASS_SERIAL,
203 .of_match = sifive_serial_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700204 .of_to_plat = sifive_serial_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700205 .plat_auto = sizeof(struct sifive_uart_plat),
Anup Patel4b1d68f2018-12-15 11:35:15 +0530206 .probe = sifive_serial_probe,
207 .ops = &sifive_serial_ops,
208};
209
210#ifdef CONFIG_DEBUG_UART_SIFIVE
211static 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
221static 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
230DEBUG_UART_FUNCS
231
232#endif