-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
linux: support initialization of the non-console uarts
- Loading branch information
Showing
1 changed file
with
172 additions
and
0 deletions.
There are no files selected for viewing
172 changes: 172 additions & 0 deletions
172
patches/linux/0027-serial-pl011-support-for-dynamic-configuration-on-lx.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|