aboutsummaryrefslogtreecommitdiffstats
path: root/package/boot/uboot-mediatek/patches/002-0010-serial-mtk-add-support-for-using-dynamic-baud-clock-.patch
blob: d2f28f2bc9f7a00611c5c1aca246f54517db4322 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
From d19ad7515a7ef4ee58b5c6606ee9f74c94f28932 Mon Sep 17 00:00:00 2001
From: Weijie Gao <weijie.gao@mediatek.com>
Date: Wed, 31 Aug 2022 19:04:32 +0800
Subject: [PATCH 10/32] serial: mtk: add support for using dynamic baud clock
 souce

The baud clock on some platform may change due to assigned-clock-parent
set in DT. In current flow the baud clock is only retrieved during probe
stage. If the parent of the source clock changes after probe stage, the
setbrg will set wrong baudrate.

To get the right clock rate, this patch records the baud clk struct to the
driver's priv, and changes the driver's flow to get the clock rate before
calling _mtk_serial_setbrg().

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
---
 drivers/serial/serial_mtk.c | 80 ++++++++++++++++++++++---------------
 1 file changed, 47 insertions(+), 33 deletions(-)

--- a/drivers/serial/serial_mtk.c
+++ b/drivers/serial/serial_mtk.c
@@ -10,6 +10,7 @@
 #include <common.h>
 #include <div64.h>
 #include <dm.h>
+#include <dm/device_compat.h>
 #include <errno.h>
 #include <log.h>
 #include <serial.h>
@@ -70,27 +71,37 @@ struct mtk_serial_regs {
 #define BAUD_ALLOW_MAX(baud)	((baud) + (baud) * 3 / 100)
 #define BAUD_ALLOW_MIX(baud)	((baud) - (baud) * 3 / 100)
 
+/* struct mtk_serial_priv -	Structure holding all information used by the
+ *				driver
+ * @regs:			Register base of the serial port
+ * @clk:			The baud clock device
+ * @fixed_clk_rate:		Fallback fixed baud clock rate if baud clock
+ *				device is not specified
+ * @force_highspeed:		Force using high-speed mode
+ */
 struct mtk_serial_priv {
 	struct mtk_serial_regs __iomem *regs;
-	u32 clock;
+	struct clk clk;
+	u32 fixed_clk_rate;
 	bool force_highspeed;
 };
 
-static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
+static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud,
+			       uint clk_rate)
 {
 	u32 quot, realbaud, samplecount = 1;
 
 	/* Special case for low baud clock */
-	if (baud <= 115200 && priv->clock <= 12000000) {
+	if (baud <= 115200 && clk_rate == 12000000) {
 		writel(3, &priv->regs->highspeed);
 
-		quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
+		quot = DIV_ROUND_CLOSEST(clk_rate, 256 * baud);
 		if (quot == 0)
 			quot = 1;
 
-		samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
+		samplecount = DIV_ROUND_CLOSEST(clk_rate, quot * baud);
 
-		realbaud = priv->clock / samplecount / quot;
+		realbaud = clk_rate / samplecount / quot;
 		if (realbaud > BAUD_ALLOW_MAX(baud) ||
 		    realbaud < BAUD_ALLOW_MIX(baud)) {
 			pr_info("baud %d can't be handled\n", baud);
@@ -104,7 +115,7 @@ static void _mtk_serial_setbrg(struct mt
 
 	if (baud <= 115200) {
 		writel(0, &priv->regs->highspeed);
-		quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
+		quot = DIV_ROUND_CLOSEST(clk_rate, 16 * baud);
 	} else if (baud <= 576000) {
 		writel(2, &priv->regs->highspeed);
 
@@ -112,13 +123,13 @@ static void _mtk_serial_setbrg(struct mt
 		if ((baud == 500000) || (baud == 576000))
 			baud = 460800;
 
-		quot = DIV_ROUND_UP(priv->clock, 4 * baud);
+		quot = DIV_ROUND_UP(clk_rate, 4 * baud);
 	} else {
 use_hs3:
 		writel(3, &priv->regs->highspeed);
 
-		quot = DIV_ROUND_UP(priv->clock, 256 * baud);
-		samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
+		quot = DIV_ROUND_UP(clk_rate, 256 * baud);
+		samplecount = DIV_ROUND_CLOSEST(clk_rate, quot * baud);
 	}
 
 set_baud:
@@ -167,8 +178,13 @@ static int _mtk_serial_pending(struct mt
 static int mtk_serial_setbrg(struct udevice *dev, int baudrate)
 {
 	struct mtk_serial_priv *priv = dev_get_priv(dev);
+	u32 clk_rate;
+
+	clk_rate = clk_get_rate(&priv->clk);
+	if (IS_ERR_VALUE(clk_rate) || clk_rate == 0)
+		clk_rate = priv->fixed_clk_rate;
 
-	_mtk_serial_setbrg(priv, baudrate);
+	_mtk_serial_setbrg(priv, baudrate, clk_rate);
 
 	return 0;
 }
@@ -211,7 +227,6 @@ static int mtk_serial_of_to_plat(struct
 {
 	struct mtk_serial_priv *priv = dev_get_priv(dev);
 	fdt_addr_t addr;
-	struct clk clk;
 	int err;
 
 	addr = dev_read_addr(dev);
@@ -220,22 +235,19 @@ static int mtk_serial_of_to_plat(struct
 
 	priv->regs = map_physmem(addr, 0, MAP_NOCACHE);
 
-	err = clk_get_by_index(dev, 0, &clk);
-	if (!err) {
-		err = clk_get_rate(&clk);
-		if (!IS_ERR_VALUE(err))
-			priv->clock = err;
-	} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
-		debug("mtk_serial: failed to get clock\n");
-		return err;
-	}
-
-	if (!priv->clock)
-		priv->clock = dev_read_u32_default(dev, "clock-frequency", 0);
-
-	if (!priv->clock) {
-		debug("mtk_serial: clock not defined\n");
-		return -EINVAL;
+	err = clk_get_by_index(dev, 0, &priv->clk);
+	if (err) {
+		err = dev_read_u32(dev, "clock-frequency", &priv->fixed_clk_rate);
+		if (err) {
+			dev_err(dev, "baud clock not defined\n");
+			return -EINVAL;
+		}
+	} else {
+		err = clk_get_rate(&priv->clk);
+		if (IS_ERR_VALUE(err)) {
+			dev_err(dev, "invalid baud clock\n");
+			return -EINVAL;
+		}
 	}
 
 	priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed");
@@ -273,7 +285,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #define DECLARE_HSUART_PRIV(port) \
 	static struct mtk_serial_priv mtk_hsuart##port = { \
 	.regs = (struct mtk_serial_regs *)CONFIG_SYS_NS16550_COM##port, \
-	.clock = CONFIG_SYS_NS16550_CLK \
+	.fixed_clk_rate = CONFIG_SYS_NS16550_CLK \
 };
 
 #define DECLARE_HSUART_FUNCTIONS(port) \
@@ -282,12 +294,14 @@ DECLARE_GLOBAL_DATA_PTR;
 		writel(0, &mtk_hsuart##port.regs->ier); \
 		writel(UART_MCRVAL, &mtk_hsuart##port.regs->mcr); \
 		writel(UART_FCRVAL, &mtk_hsuart##port.regs->fcr); \
-		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
+		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate, \
+				   mtk_hsuart##port.fixed_clk_rate); \
 		return 0 ; \
 	} \
 	static void mtk_serial##port##_setbrg(void) \
 	{ \
-		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
+		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate, \
+				   mtk_hsuart##port.fixed_clk_rate); \
 	} \
 	static int mtk_serial##port##_getc(void) \
 	{ \
@@ -427,13 +441,13 @@ static inline void _debug_uart_init(void
 	struct mtk_serial_priv priv;
 
 	priv.regs = (void *) CONFIG_VAL(DEBUG_UART_BASE);
-	priv.clock = CONFIG_DEBUG_UART_CLOCK;
+	priv.fixed_clk_rate = CONFIG_DEBUG_UART_CLOCK;
 
 	writel(0, &priv.regs->ier);
 	writel(UART_MCRVAL, &priv.regs->mcr);
 	writel(UART_FCRVAL, &priv.regs->fcr);
 
-	_mtk_serial_setbrg(&priv, CONFIG_BAUDRATE);
+	_mtk_serial_setbrg(&priv, CONFIG_BAUDRATE, priv.fixed_clk_rate);
 }
 
 static inline void _debug_uart_putc(int ch)