From 2487def6bc9e1b2f30d21346d2427427021f6939 Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Thu, 13 Feb 2025 11:31:23 +0100 Subject: [PATCH] linux: support initialization of the non-console uarts --- ...port-for-dynamic-configuration-on-lx.patch | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 patches/linux/0027-serial-pl011-support-for-dynamic-configuration-on-lx.patch diff --git a/patches/linux/0027-serial-pl011-support-for-dynamic-configuration-on-lx.patch b/patches/linux/0027-serial-pl011-support-for-dynamic-configuration-on-lx.patch new file mode 100644 index 0000000..75e3dfe --- /dev/null +++ b/patches/linux/0027-serial-pl011-support-for-dynamic-configuration-on-lx.patch @@ -0,0 +1,172 @@ +From 05149af2173ec65df9f47fa9cc25d1393384a385 Mon Sep 17 00:00:00 2001 +From: Josua Mayer +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 +--- + 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 +@@ -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 +