kernel-6.6/0602-serial-8250_dw-verify-clock-rate-in-dw8250_set_termi.patch
Mikhail Novosyolov 754cb78a80 begin kernel 6.6
2024-02-22 15:51:17 +03:00

72 lines
2.9 KiB
Diff

From ba89e7e17e6bec3d1e2b49e9a632ff7fe28c4cc0 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@basealt.ru>
Date: Tue, 11 Jan 2022 15:49:19 +0400
Subject: [PATCH 602/631] serial: 8250_dw: verify clock rate in
dw8250_set_termios
Refuse to change the clock rate if clk_round_rate() returns
a rate which is way too off (i.e. by more than 1/16 from the one
necessary for a given baud rate). In particular this happens if
the requested rate is below the minimum supported by the clock.
Fixes the UART console on Baikal-M SoC. Without this patch the
console gets garbled immediately after loading the driver.
dw8250_set_termios tries to configure the baud rate (115200),
and calls clk_round_rate to figure out the supported rate closest
to 1843200 Hz (which is 115200 * 16). However the (SoC-specific)
clock driver returns 4705882 Hz. This frequency is way too off,
hence after setting it the console gets garbled.
On Baikal-M Linux has no direct control over (most) clocks.
The registers of CMU (clock management unit) are accessible
only from the secure world, therefore clocks are managed by
the firmware (ARM-TF). Linux' driver, clk-baikal, is a shim which
calls into firmware. And that 4705882 Hz is exactly what
the firmware returns.
According to 8250_dw maintainer (Andy Shevchenko) the correct
way to fix the problem is to
1) use DLAB for the baud rate and fixed clock rate,
2) fix the firmware
Neither of these advices can be applied in practice. For one,
both methods require replacing the DTB, which is embedded into
the firmware. Updating firmware is possible only for some types
of (Baikal-M) based boards, and requires special hardware (JTAG
programmer) and skills.
Therfore the only practical way to address the issue is to adjust
the kernel (with this ugly patch).
Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru>
Co-developed-by: Vadim V. Vlasov <vadim.vlasov@elpitech.ru>
X-DONTUPSTREAM
X-feature-Baikal-M
---
drivers/tty/serial/8250/8250_dw.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a1f2259cc9a9..d2c3fb10185e 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -352,14 +352,15 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
const struct ktermios *old)
{
- unsigned long newrate = tty_termios_baud_rate(termios) * 16;
+ unsigned long baud = tty_termios_baud_rate(termios);
+ unsigned long newrate = baud * 16;
struct dw8250_data *d = to_dw8250_data(p->private_data);
long rate;
int ret;
clk_disable_unprepare(d->clk);
rate = clk_round_rate(d->clk, newrate);
- if (rate > 0) {
+ if (rate > 0 && rate >= baud * 15 && rate <= baud * 17) {
/*
* Note that any clock-notifer worker will block in
* serial8250_update_uartclk() until we are done.
--
2.40.1