Skip to content

Commit

Permalink
linux: support initialization of the non-console uarts
Browse files Browse the repository at this point in the history
  • Loading branch information
Josua-SR committed Feb 13, 2025
1 parent 423dc1b commit 2487def
Showing 1 changed file with 172 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
From 05149af2173ec65df9f47fa9cc25d1393384a385 Mon Sep 17 00:00:00 2001
From: Josua Mayer <josua@solid-run.com>
Date: Thu, 13 Feb 2025 11:24:40 +0100
Subject: [PATCH] serial: pl011: support for dynamic configuration on lx2160a
soc

LX2160A pl011 uart can be (re-)configured at runtime.

Add suppporting code for reading the current platform clock to calculate
uart clock. set_termios is extended to reconfigure any non-console
ports.

This implementation is specific to lx2160 soc - a better implementation
will pull in the uart clock rate from a clock driver linked in
device-tree.

Signed-off-by: Josua Mayer <josua@solid-run.com>
---
drivers/tty/serial/amba-pl011.c | 108 +++++++++++++++++++++++++++++++-
1 file changed, 107 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 300a8bbb4b80..6424eb20d725 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -14,6 +14,8 @@
* not have an RI input, nor do they have DTR or RTS outputs. If
* required, these have to be supplied via some other means (eg, GPIO)
* and hooked into this driver.
+ *
+ * Modified to take into account actual lx2160a platform clock. SolidRun Ltd (Oct 2025).
*/

#include <linux/module.h>
@@ -55,6 +57,32 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)

+/*
+ * The uart clock is determined from the RCW data and the LX2160A reference manual
+ *
+ * Refer to the QorIQ LX2160A Reference Manual, 4.10 IP Logic Clock Distribution and Configuration to see:
+ * 1) Platform PLL is controlled by RCW[SYS_PLL_RAT]
+ * 2) Platform clock is Platform PLL / 2
+ * 3) UART is clocked by Platform clock / 4.
+ * Refer to the RM, 9.3.1.13 Reset Configuration Word Status Register 1 (RCWSR1) to obtain the SYS_PLL_RAT value.
+ *
+ */
+#define FSL_LX2160A_RCWSR1 0x01e00100
+#define FSL_LX2160A_RCWSR1_SYS_PLL_RAT_SHIFT 2
+#define FSL_LX2160A_RCWSR1_SYS_PLL_RAT_MASK 0x1f
+
+static int fsl_ch3_get_platform_pll(void)
+{
+ void __iomem *rcwsr1 = ioremap((phys_addr_t)FSL_LX2160A_RCWSR1, 4);
+ uint32_t val = ioread32(rcwsr1);
+ iounmap(rcwsr1);
+
+ val >>= FSL_LX2160A_RCWSR1_SYS_PLL_RAT_SHIFT;
+ val &= FSL_LX2160A_RCWSR1_SYS_PLL_RAT_MASK;
+ val *= 50000000;
+ return val;
+}
+
static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
[REG_DR] = UART01x_DR,
[REG_FR] = UART01x_FR,
@@ -2166,6 +2194,55 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
spin_unlock_irqrestore(&port->lock, flags);
}

+static int
+sbsa_uart_set_line_control(struct uart_amba_port *uap)
+{
+ unsigned int lcr;
+ /*
+ * Internal update of baud rate register require line
+ * control register write
+ */
+ lcr = UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN;
+ pl011_write(lcr, uap, REG_LCRH_RX);
+
+ return 0;
+}
+
+static int
+sbsa_uart_generic_setbrg(struct uart_amba_port *uap, int clock, int baudrate)
+{
+ unsigned int temp;
+ unsigned int divider;
+ unsigned int remainder;
+ unsigned int fraction;
+
+ /* Without a valid clock rate we cannot set up the baudrate. */
+ if (clock) {
+ /*
+ * Set baud rate
+ *
+ * IBRD = UART_CLK / (16 * BAUD_RATE)
+ * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) * / (16 * BAUD_RATE))
+ */
+ temp = 16 * baudrate;
+ divider = clock / temp;
+ remainder = clock % temp;
+ temp = (8 * remainder) / baudrate;
+ fraction = (temp >> 1) + (temp & 1);
+
+ /* Set baud rate */
+ pl011_write(fraction, uap, REG_FBRD);
+ pl011_write(divider, uap, REG_IBRD);
+ }
+
+ sbsa_uart_set_line_control(uap);
+ /* Finally, enable the UART */
+ pl011_write(UART01x_CR_UARTEN | UART011_CR_TXE |
+ UART011_CR_RXE | UART011_CR_RTS, uap, REG_CR);
+
+ return 0;
+}
+
static void
sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
@@ -2173,8 +2250,29 @@ sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
unsigned long flags;
+ unsigned int ibaud_rate, obaud_rate;

- tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
+ //printk(KERN_INFO "%s: port idx: %d, console idx: %d, port speed_in: %d, port speed_out: %d, fixed_baud: %d, port mapbase: 0x%lx\n",
+ // __func__, port->line, port->cons->index, termios->c_ispeed, termios->c_ospeed, uap->fixed_baud, port->mapbase);
+
+ if(port->line != port->cons->index) {
+ if (termios->c_ispeed == -1) {
+ termios->c_ispeed = 115200;
+ }
+ if (termios->c_ospeed == -1) {
+ termios->c_ospeed = 115200;
+ }
+ ibaud_rate = termios->c_ispeed;
+ obaud_rate = termios->c_ospeed;
+ }
+ else {
+ ibaud_rate = uap->fixed_baud;
+ obaud_rate = uap->fixed_baud;
+ printk(KERN_INFO "%s: This SBSA UART [port %d] is configured for a serial console, its config is fixed [speed %d]\n",
+ __func__, port->line, ibaud_rate);
+ }
+
+ tty_termios_encode_baud_rate(termios, ibaud_rate, obaud_rate);

/* The SBSA UART only supports 8n1 without hardware flow control. */
termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
@@ -2184,6 +2282,14 @@ sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
spin_lock_irqsave(&port->lock, flags);
uart_update_timeout(port, CS8, uap->fixed_baud);
pl011_setup_status_masks(port, termios);
+
+ // Configure SBSA UART only that are not used as a serial console by linux
+ if(port->line != port->cons->index) {
+ //printk(KERN_INFO "%s: This SBSA UART [port no %d] is being configured with this parameters [speed: %d, uart clk: %d]\n",
+ // __func__, port->line, ibaud_rate, fsl_ch3_get_platform_pll() / 4);
+ sbsa_uart_generic_setbrg(uap, fsl_ch3_get_platform_pll() / 4, ibaud_rate);
+ }
+
spin_unlock_irqrestore(&port->lock, flags);
}

--
2.43.0

0 comments on commit 2487def

Please sign in to comment.