blob: c449f3fd02d90a72c945ec357270f042206e6b81 [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>
Simon Glass3ba929a2020-10-30 21:38:53 -060014#include <asm/global_data.h>
Anup Patel4b1d68f2018-12-15 11:35:15 +053015#include <asm/io.h>
16#include <linux/compiler.h>
17#include <serial.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Anup Patel4b1d68f2018-12-15 11:35:15 +053019
20DECLARE_GLOBAL_DATA_PTR;
21
22#define UART_TXFIFO_FULL 0x80000000
23#define UART_RXFIFO_EMPTY 0x80000000
24#define UART_RXFIFO_DATA 0x000000ff
25#define UART_TXCTRL_TXEN 0x1
26#define UART_RXCTRL_RXEN 0x1
27
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -070028/* IP register */
29#define UART_IP_RXWM 0x2
30
Anup Patel4b1d68f2018-12-15 11:35:15 +053031struct uart_sifive {
32 u32 txfifo;
33 u32 rxfifo;
34 u32 txctrl;
35 u32 rxctrl;
36 u32 ie;
37 u32 ip;
38 u32 div;
39};
40
Simon Glassb75b15b2020-12-03 16:55:23 -070041struct sifive_uart_plat {
Atish Patrabc922d42019-02-25 08:15:02 +000042 unsigned long clock;
Anup Patel4b1d68f2018-12-15 11:35:15 +053043 struct uart_sifive *regs;
44};
45
Atish Patrabc922d42019-02-25 08:15:02 +000046/**
47 * Find minimum divisor divides in_freq to max_target_hz;
48 * Based on uart driver n SiFive FSBL.
49 *
50 * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
51 * The nearest integer solution requires rounding up as to not exceed
52 * max_target_hz.
53 * div = ceil(f_in / f_baud) - 1
54 * = floor((f_in - 1 + f_baud) / f_baud) - 1
55 * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
56 * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
57 */
58static inline unsigned int uart_min_clk_divisor(unsigned long in_freq,
59 unsigned long max_target_hz)
60{
61 unsigned long quotient =
62 (in_freq + max_target_hz - 1) / (max_target_hz);
63 /* Avoid underflow */
64 if (quotient == 0)
65 return 0;
66 else
67 return quotient - 1;
68}
69
Anup Patel4b1d68f2018-12-15 11:35:15 +053070/* Set up the baud rate in gd struct */
71static void _sifive_serial_setbrg(struct uart_sifive *regs,
72 unsigned long clock, unsigned long baud)
73{
Atish Patrabc922d42019-02-25 08:15:02 +000074 writel((uart_min_clk_divisor(clock, baud)), &regs->div);
Anup Patel4b1d68f2018-12-15 11:35:15 +053075}
76
77static void _sifive_serial_init(struct uart_sifive *regs)
78{
79 writel(UART_TXCTRL_TXEN, &regs->txctrl);
80 writel(UART_RXCTRL_RXEN, &regs->rxctrl);
81 writel(0, &regs->ie);
82}
83
84static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
85{
86 if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
87 return -EAGAIN;
88
89 writel(c, &regs->txfifo);
90
91 return 0;
92}
93
94static int _sifive_serial_getc(struct uart_sifive *regs)
95{
96 int ch = readl(&regs->rxfifo);
97
98 if (ch & UART_RXFIFO_EMPTY)
99 return -EAGAIN;
100 ch &= UART_RXFIFO_DATA;
101
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -0700102 return ch;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530103}
104
105static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
106{
Atish Patra574fa692019-02-25 08:15:08 +0000107 int ret;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530108 struct clk clk;
Simon Glassb75b15b2020-12-03 16:55:23 -0700109 struct sifive_uart_plat *plat = dev_get_plat(dev);
Atish Patra574fa692019-02-25 08:15:08 +0000110 u32 clock = 0;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530111
Atish Patra574fa692019-02-25 08:15:08 +0000112 ret = clk_get_by_index(dev, 0, &clk);
113 if (IS_ERR_VALUE(ret)) {
Anup Patel4b1d68f2018-12-15 11:35:15 +0530114 debug("SiFive UART failed to get clock\n");
Atish Patra574fa692019-02-25 08:15:08 +0000115 ret = dev_read_u32(dev, "clock-frequency", &clock);
116 if (IS_ERR_VALUE(ret)) {
117 debug("SiFive UART clock not defined\n");
118 return 0;
119 }
120 } else {
121 clock = clk_get_rate(&clk);
122 if (IS_ERR_VALUE(clock)) {
123 debug("SiFive UART clock get rate failed\n");
124 return 0;
125 }
Anup Patel4b1d68f2018-12-15 11:35:15 +0530126 }
Simon Glass71fa5b42020-12-03 16:55:18 -0700127 plat->clock = clock;
128 _sifive_serial_setbrg(plat->regs, plat->clock, baudrate);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530129
130 return 0;
131}
132
133static int sifive_serial_probe(struct udevice *dev)
134{
Simon Glassb75b15b2020-12-03 16:55:23 -0700135 struct sifive_uart_plat *plat = dev_get_plat(dev);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530136
137 /* No need to reinitialize the UART after relocation */
138 if (gd->flags & GD_FLG_RELOC)
139 return 0;
140
Simon Glass71fa5b42020-12-03 16:55:18 -0700141 _sifive_serial_init(plat->regs);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530142
143 return 0;
144}
145
146static int sifive_serial_getc(struct udevice *dev)
147{
148 int c;
Simon Glassb75b15b2020-12-03 16:55:23 -0700149 struct sifive_uart_plat *plat = dev_get_plat(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700150 struct uart_sifive *regs = plat->regs;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530151
Anup Patel4b1d68f2018-12-15 11:35:15 +0530152 while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
153
154 return c;
155}
156
157static int sifive_serial_putc(struct udevice *dev, const char ch)
158{
159 int rc;
Simon Glassb75b15b2020-12-03 16:55:23 -0700160 struct sifive_uart_plat *plat = dev_get_plat(dev);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530161
Simon Glass71fa5b42020-12-03 16:55:18 -0700162 while ((rc = _sifive_serial_putc(plat->regs, ch)) == -EAGAIN) ;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530163
164 return rc;
165}
166
167static int sifive_serial_pending(struct udevice *dev, bool input)
168{
Simon Glassb75b15b2020-12-03 16:55:23 -0700169 struct sifive_uart_plat *plat = dev_get_plat(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700170 struct uart_sifive *regs = plat->regs;
Anup Patel4b1d68f2018-12-15 11:35:15 +0530171
Sagar Shrikant Kadam024d0602019-07-09 05:23:44 -0700172 if (input)
173 return (readl(&regs->ip) & UART_IP_RXWM);
174 else
Anup Patel4b1d68f2018-12-15 11:35:15 +0530175 return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530176}
177
Simon Glassaad29ae2020-12-03 16:55:21 -0700178static int sifive_serial_of_to_plat(struct udevice *dev)
Anup Patel4b1d68f2018-12-15 11:35:15 +0530179{
Simon Glassb75b15b2020-12-03 16:55:23 -0700180 struct sifive_uart_plat *plat = dev_get_plat(dev);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530181
Bin Mengb934fd22021-01-31 20:36:00 +0800182 plat->regs = (struct uart_sifive *)(uintptr_t)dev_read_addr(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700183 if (IS_ERR(plat->regs))
184 return PTR_ERR(plat->regs);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530185
186 return 0;
187}
188
189static const struct dm_serial_ops sifive_serial_ops = {
190 .putc = sifive_serial_putc,
191 .getc = sifive_serial_getc,
192 .pending = sifive_serial_pending,
193 .setbrg = sifive_serial_setbrg,
194};
195
196static const struct udevice_id sifive_serial_ids[] = {
197 { .compatible = "sifive,uart0" },
198 { }
199};
200
201U_BOOT_DRIVER(serial_sifive) = {
202 .name = "serial_sifive",
203 .id = UCLASS_SERIAL,
204 .of_match = sifive_serial_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700205 .of_to_plat = sifive_serial_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700206 .plat_auto = sizeof(struct sifive_uart_plat),
Anup Patel4b1d68f2018-12-15 11:35:15 +0530207 .probe = sifive_serial_probe,
208 .ops = &sifive_serial_ops,
209};
210
211#ifdef CONFIG_DEBUG_UART_SIFIVE
212static inline void _debug_uart_init(void)
213{
214 struct uart_sifive *regs =
Pali Rohár8864b352022-05-27 22:15:24 +0200215 (struct uart_sifive *)CONFIG_VAL(DEBUG_UART_BASE);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530216
217 _sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
218 CONFIG_BAUDRATE);
219 _sifive_serial_init(regs);
220}
221
222static inline void _debug_uart_putc(int ch)
223{
224 struct uart_sifive *regs =
Pali Rohár8864b352022-05-27 22:15:24 +0200225 (struct uart_sifive *)CONFIG_VAL(DEBUG_UART_BASE);
Anup Patel4b1d68f2018-12-15 11:35:15 +0530226
227 while (_sifive_serial_putc(regs, ch) == -EAGAIN)
Stefan Roese80877fa2022-09-02 14:10:46 +0200228 schedule();
Anup Patel4b1d68f2018-12-15 11:35:15 +0530229}
230
231DEBUG_UART_FUNCS
232
233#endif