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
|
From d8bde59186dafdea5bbe8d29d3a6ae7cac98e9d0 Mon Sep 17 00:00:00 2001
From: Weijie Gao <weijie.gao@mediatek.com>
Date: Mon, 25 Jan 2021 11:19:08 +0800
Subject: [PATCH 11/21] serial: serial-mtk: rewrite the setbrg function
Currently the setbrg logic of serial-mtk is messy, and should be rewritten.
Also an option is added to make it possible to use highspeed=3 mode for all
bauds.
The new logic is:
1. If baud clock > 12MHz
a) If baud <= 115200, highspeed=0 mode will be used (ns16550 compatible)
b) If baud <= 576000, highspeed=2 mode will be used
c) any baud > 576000, highspeed=3 mode will be used
2. If baud clock <= 12MHz
Always uses highspeed=3 mode
a) If baud <= 115200, calculates the divisor using DIV_ROUND_CLOSEST
b) any baud > 115200, the same as 1. c)
Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
---
drivers/serial/serial_mtk.c | 74 +++++++++++++++++--------------------
1 file changed, 33 insertions(+), 41 deletions(-)
--- a/drivers/serial/serial_mtk.c
+++ b/drivers/serial/serial_mtk.c
@@ -73,74 +73,64 @@ struct mtk_serial_regs {
struct mtk_serial_priv {
struct mtk_serial_regs __iomem *regs;
u32 clock;
+ bool force_highspeed;
};
static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
{
- bool support_clk12m_baud115200;
- u32 quot, samplecount, realbaud;
+ u32 quot, realbaud, samplecount = 1;
- if ((baud <= 115200) && (priv->clock == 12000000))
- support_clk12m_baud115200 = true;
- else
- support_clk12m_baud115200 = false;
+ /* Special case for low baud clock */
+ if ((baud <= 115200) && (priv->clock == 12000000)) {
+ writel(3, &priv->regs->highspeed);
+
+ quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
+ if (quot == 0)
+ quot = 1;
+
+ samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
+
+ realbaud = priv->clock / samplecount / quot;
+ if ((realbaud > BAUD_ALLOW_MAX(baud)) ||
+ (realbaud < BAUD_ALLOW_MIX(baud))) {
+ pr_info("baud %d can't be handled\n", baud);
+ }
+
+ goto set_baud;
+ }
+
+ if (priv->force_highspeed)
+ goto use_hs3;
if (baud <= 115200) {
writel(0, &priv->regs->highspeed);
quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
-
- if (support_clk12m_baud115200) {
- writel(3, &priv->regs->highspeed);
- quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
- if (quot == 0)
- quot = 1;
-
- samplecount = DIV_ROUND_CLOSEST(priv->clock,
- quot * baud);
- if (samplecount != 0) {
- realbaud = priv->clock / samplecount / quot;
- if ((realbaud > BAUD_ALLOW_MAX(baud)) ||
- (realbaud < BAUD_ALLOW_MIX(baud))) {
- pr_info("baud %d can't be handled\n",
- baud);
- }
- } else {
- pr_info("samplecount is 0\n");
- }
- }
} else if (baud <= 576000) {
writel(2, &priv->regs->highspeed);
/* Set to next lower baudrate supported */
if ((baud == 500000) || (baud == 576000))
baud = 460800;
+
quot = DIV_ROUND_UP(priv->clock, 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);
}
+set_baud:
/* set divisor */
writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr);
writel(quot & 0xff, &priv->regs->dll);
writel((quot >> 8) & 0xff, &priv->regs->dlm);
writel(UART_LCR_WLS_8, &priv->regs->lcr);
- if (baud > 460800) {
- u32 tmp;
-
- tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
- writel(tmp - 1, &priv->regs->sample_count);
- writel((tmp - 2) >> 1, &priv->regs->sample_point);
- } else {
- writel(0, &priv->regs->sample_count);
- writel(0xff, &priv->regs->sample_point);
- }
-
- if (support_clk12m_baud115200) {
- writel(samplecount - 1, &priv->regs->sample_count);
- writel((samplecount - 2) >> 1, &priv->regs->sample_point);
- }
+ /* set highspeed mode sample count & point */
+ writel(samplecount - 1, &priv->regs->sample_count);
+ writel((samplecount - 2) >> 1, &priv->regs->sample_point);
}
static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch)
@@ -248,6 +238,8 @@ static int mtk_serial_of_to_plat(struct
return -EINVAL;
}
+ priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed");
+
return 0;
}
|