From 6e15d3f91aa698798578d39a6d9e292fcc5c577f Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Fri, 23 May 2025 17:25:55 +0800 Subject: serial: mediatek: fix register names and offsets Fix UART register names and offsets according to the programming guide to allow implementing some enhanced features. Signed-off-by: Weijie Gao --- drivers/serial/serial_mtk.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c index becf9317076..9d379f2e899 100644 --- a/drivers/serial/serial_mtk.c +++ b/drivers/serial/serial_mtk.c @@ -30,16 +30,23 @@ struct mtk_serial_regs { u32 mcr; u32 lsr; u32 msr; - u32 spr; - u32 mdr1; + u32 scr; + u32 autobaud_en; u32 highspeed; u32 sample_count; u32 sample_point; + u32 autobaud_reg; + u32 ratefix_ad; + u32 autobaud_sample; + u32 guard; + u32 escape_dat; + u32 escape_en; + u32 sleep_en; + u32 dma_en; + u32 rxtri_ad; u32 fracdiv_l; u32 fracdiv_m; - u32 escape_en; - u32 guard; - u32 rx_sel; + u32 fcr_rd; }; #define thr rbr -- cgit v1.3.1 From 6952209ef220138189dd261d06441e1b2d50e994 Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Fri, 23 May 2025 17:26:02 +0800 Subject: serial: mediatek: enable baudrate accuracy compensation The high-speed UART from MediaTek supports baudrate accuracy compensation when using high-speed mode 3. This is done by calculating the first digit of the fraction part of sample count value. The fraction value will be then used as the reference to insert 0 to 10 sample cycle(s) to one frame (assume that frame format is 8n1, i.e. 10 bits per frame). The fracdiv_[l/m] registers are used to determine whether a bit in one frame should be inserted with one sample cycle. With typical 40MHz source clock, the actual baudrates with/without accuracy compensation are: Ideal w/o compensation w/ compensation ======== ================ =============== 9600 9603 9600 115200 114942 115207 921600 930232 921659 3000000 3076923 3007519 Signed-off-by: Weijie Gao --- drivers/serial/serial_mtk.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c index 9d379f2e899..01cc415efdd 100644 --- a/drivers/serial/serial_mtk.c +++ b/drivers/serial/serial_mtk.c @@ -99,10 +99,18 @@ struct mtk_serial_priv { bool upstream_highspeed_logic; }; +static const unsigned short fraction_l_mapping[] = { + 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF +}; + +static const unsigned short fraction_m_mapping[] = { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 +}; + static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud, uint clk_rate) { - u32 quot, realbaud, samplecount = 1; + u32 quot, realbaud, samplecount = 1, fraction, frac_l = 0, frac_m = 0; /* Special case for low baud clock */ if (baud <= 115200 && clk_rate == 12000000) { @@ -147,7 +155,13 @@ use_hs3: writel(3, &priv->regs->highspeed); quot = DIV_ROUND_UP(clk_rate, 256 * baud); - samplecount = DIV_ROUND_CLOSEST(clk_rate, quot * baud); + samplecount = clk_rate / (quot * baud); + + fraction = ((clk_rate * 100) / quot / baud) % 100; + fraction = DIV_ROUND_CLOSEST(fraction, 10); + + frac_l = fraction_l_mapping[fraction]; + frac_m = fraction_m_mapping[fraction]; } set_baud: @@ -159,7 +173,11 @@ set_baud: /* set highspeed mode sample count & point */ writel(samplecount - 1, &priv->regs->sample_count); - writel((samplecount - 2) >> 1, &priv->regs->sample_point); + writel((samplecount >> 1) - 1, &priv->regs->sample_point); + + /* set baudrate fraction compensation */ + writel(frac_l, &priv->regs->fracdiv_l); + writel(frac_m, &priv->regs->fracdiv_m); } static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch) -- cgit v1.3.1