mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/4] serial: amba-pl011: Add Tegra264 UART support
@ 2026-02-25  6:59 Kartik Rajput
  2026-02-25  6:59 ` [PATCH 1/4] serial: amba-pl011: Introduce skip_ibrd_fbrd vendor flag Kartik Rajput
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Kartik Rajput @ 2026-02-25  6:59 UTC (permalink / raw)
  To: linux, gregkh, jirislaby, mingo, tglx, linmq006, arnd,
	thierry.reding, jonathanh, linux-kernel, linux-serial
  Cc: Kartik Rajput

This series adds support for the NVIDIA Tegra264 UART controller, which
is derived from the AMBA PL011.

On Tegra264, the fractional baud rate divisor (FBRD) register is
broken. Configuring the baud rate using IBRD and FBRD may result in the
baud rate falling outside the required tolerance. Instead, the baud
rate is derived by setting the UART clock.

The following vendor flags are introduced:
 - skip_ibrd_fbrd: to skip IBRD/FBRD programming
 - set_uartclk_rate: to configure the baud rate by setting the UART
   clock rate

Additionally, some DMA controllers (e.g. Tegra GPCDMA) require transfer
lengths to satisfy the controller's copy_align constraint. The PL011
driver does not currently enforce this, which can result in rejected
transfers. The DMA alignment change aligns the TX DMA length down to
the required boundary, with any remaining bytes handled via the
existing PIO fallback.

Kartik Rajput (4):
  serial: amba-pl011: Introduce skip_ibrd_fbrd vendor flag
  serial: amba-pl011: Introduce set_uartclk_rate vendor flag
  serial: amba-pl011: Add Tegra264 UART support
  serial: amba-pl011: Respect DMA controller's copy_align requirement

 drivers/tty/serial/amba-pl011.c | 118 +++++++++++++++++++++++++-------
 1 file changed, 94 insertions(+), 24 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] serial: amba-pl011: Introduce skip_ibrd_fbrd vendor flag
  2026-02-25  6:59 [PATCH 0/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
@ 2026-02-25  6:59 ` Kartik Rajput
  2026-02-25  6:59 ` [PATCH 2/4] serial: amba-pl011: Introduce set_uartclk_rate " Kartik Rajput
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Kartik Rajput @ 2026-02-25  6:59 UTC (permalink / raw)
  To: linux, gregkh, jirislaby, mingo, tglx, linmq006, arnd,
	thierry.reding, jonathanh, linux-kernel, linux-serial
  Cc: Kartik Rajput

The NVIDIA Tegra264 UART has a broken fractional baud rate
divisor register. Using IBRD and FBRD may cause the baud rate
to fall outside the required tolerance.

Introduce the skip_ibrd_fbrd vendor flag to skip IBRD/FBRD
programming. When set, the baud rate is derived directly from the
UART clock rate using a fixed divisor.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 drivers/tty/serial/amba-pl011.c | 53 +++++++++++++++++++--------------
 1 file changed, 31 insertions(+), 22 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 7f17d288c807..79e1c937a600 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -114,6 +114,7 @@ struct vendor_data {
 	bool			cts_event_workaround;
 	bool			always_enabled;
 	bool			fixed_options;
+	bool			skip_ibrd_fbrd;
 
 	unsigned int (*get_fifosize)(struct amba_device *dev);
 };
@@ -2115,11 +2116,6 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 		uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
 #endif
 
-	if (baud > port->uartclk / 16)
-		quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
-	else
-		quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
-
 	switch (termios->c_cflag & CSIZE) {
 	case CS5:
 		lcr_h = UART01x_LCRH_WLEN_5;
@@ -2190,21 +2186,28 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 			old_cr &= ~ST_UART011_CR_OVSFACT;
 	}
 
-	/*
-	 * Workaround for the ST Micro oversampling variants to
-	 * increase the bitrate slightly, by lowering the divisor,
-	 * to avoid delayed sampling of start bit at high speeds,
-	 * else we see data corruption.
-	 */
-	if (uap->vendor->oversampling) {
-		if (baud >= 3000000 && baud < 3250000 && quot > 1)
-			quot -= 1;
-		else if (baud > 3250000 && quot > 2)
-			quot -= 2;
+	if (!uap->vendor->skip_ibrd_fbrd) {
+		if (baud > port->uartclk / 16)
+			quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
+		else
+			quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
+
+		/*
+		 * Workaround for the ST Micro oversampling variants to
+		 * increase the bitrate slightly, by lowering the divisor,
+		 * to avoid delayed sampling of start bit at high speeds,
+		 * else we see data corruption.
+		 */
+		if (uap->vendor->oversampling) {
+			if (baud >= 3000000 && baud < 3250000 && quot > 1)
+				quot -= 1;
+			else if (baud > 3250000 && quot > 2)
+				quot -= 2;
+		}
+		/* Set baud rate */
+		pl011_write(quot & 0x3f, uap, REG_FBRD);
+		pl011_write(quot >> 6, uap, REG_IBRD);
 	}
-	/* Set baud rate */
-	pl011_write(quot & 0x3f, uap, REG_FBRD);
-	pl011_write(quot >> 6, uap, REG_IBRD);
 
 	/*
 	 * ----------v----------v----------v----------v-----
@@ -2374,6 +2377,7 @@ static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
 				      int *parity, int *bits)
 {
 	unsigned int lcr_h, ibrd, fbrd;
+	unsigned int clkdiv;
 
 	if (!(pl011_read(uap, REG_CR) & UART01x_CR_UARTEN))
 		return;
@@ -2393,10 +2397,15 @@ static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
 	else
 		*bits = 8;
 
-	ibrd = pl011_read(uap, REG_IBRD);
-	fbrd = pl011_read(uap, REG_FBRD);
+	if (uap->vendor->skip_ibrd_fbrd) {
+		clkdiv = 64;
+	} else {
+		ibrd = pl011_read(uap, REG_IBRD);
+		fbrd = pl011_read(uap, REG_FBRD);
+		clkdiv = 64 * ibrd + fbrd;
+	}
 
-	*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
+	*baud = uap->port.uartclk * 4 / clkdiv;
 
 	if (uap->vendor->oversampling &&
 	    (pl011_read(uap, REG_CR) & ST_UART011_CR_OVSFACT))
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/4] serial: amba-pl011: Introduce set_uartclk_rate vendor flag
  2026-02-25  6:59 [PATCH 0/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
  2026-02-25  6:59 ` [PATCH 1/4] serial: amba-pl011: Introduce skip_ibrd_fbrd vendor flag Kartik Rajput
@ 2026-02-25  6:59 ` Kartik Rajput
  2026-02-25  6:59 ` [PATCH 3/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
  2026-02-25  6:59 ` [PATCH 4/4] serial: amba-pl011: Respect DMA controller's copy_align requirement Kartik Rajput
  3 siblings, 0 replies; 5+ messages in thread
From: Kartik Rajput @ 2026-02-25  6:59 UTC (permalink / raw)
  To: linux, gregkh, jirislaby, mingo, tglx, linmq006, arnd,
	thierry.reding, jonathanh, linux-kernel, linux-serial
  Cc: Kartik Rajput

The NVIDIA Tegra264 UART relies on configuring the UART clock rate
directly to program the desired baud rate.

Introduce the set_uartclk_rate vendor flag. When set, the driver
uses clk_set_rate() to program the UART clock to the desired baud
rate and clk_round_rate() to determine the maximum supported baud
rate.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 drivers/tty/serial/amba-pl011.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 79e1c937a600..ad06dc4cdf6e 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -115,6 +115,7 @@ struct vendor_data {
 	bool			always_enabled;
 	bool			fixed_options;
 	bool			skip_ibrd_fbrd;
+	bool			set_uartclk_rate;
 
 	unsigned int (*get_fifosize)(struct amba_device *dev);
 };
@@ -2096,6 +2097,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
 	unsigned int baud, quot, clkdiv;
+	unsigned int max_baud;
 	unsigned int bits;
 
 	if (uap->vendor->oversampling)
@@ -2103,11 +2105,34 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 	else
 		clkdiv = 16;
 
+	max_baud = port->uartclk / clkdiv;
+
+	if (uap->vendor->set_uartclk_rate) {
+		long max_clkrate = clk_round_rate(uap->clk, UINT_MAX);
+
+		/*
+		 * Clock is reprogrammable - determine max baud from the clock's
+		 * maximum rate, not the current uartclk.
+		 */
+		if (max_clkrate > 0)
+			max_baud = max_clkrate / clkdiv;
+	}
+
 	/*
 	 * Ask the core to calculate the divisor for us.
 	 */
-	baud = uart_get_baud_rate(port, termios, old, 0,
-				  port->uartclk / clkdiv);
+	baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
+
+	if (uap->vendor->set_uartclk_rate) {
+		int err;
+
+		err = clk_set_rate(uap->clk, baud * clkdiv);
+		if (err) {
+			dev_err(port->dev, "Failed to set clock rate: %d\n", err);
+			return;
+		}
+	}
+
 #ifdef CONFIG_DMA_ENGINE
 	/*
 	 * Adjust RX DMA polling rate with baud rate if not specified.
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/4] serial: amba-pl011: Add Tegra264 UART support
  2026-02-25  6:59 [PATCH 0/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
  2026-02-25  6:59 ` [PATCH 1/4] serial: amba-pl011: Introduce skip_ibrd_fbrd vendor flag Kartik Rajput
  2026-02-25  6:59 ` [PATCH 2/4] serial: amba-pl011: Introduce set_uartclk_rate " Kartik Rajput
@ 2026-02-25  6:59 ` Kartik Rajput
  2026-02-25  6:59 ` [PATCH 4/4] serial: amba-pl011: Respect DMA controller's copy_align requirement Kartik Rajput
  3 siblings, 0 replies; 5+ messages in thread
From: Kartik Rajput @ 2026-02-25  6:59 UTC (permalink / raw)
  To: linux, gregkh, jirislaby, mingo, tglx, linmq006, arnd,
	thierry.reding, jonathanh, linux-kernel, linux-serial
  Cc: Kartik Rajput

Add support for the NVIDIA Tegra264 UART controller, which is derived
from the AMBA PL011 design.

On Tegra264, the fractional baud rate divisor (FBRD) register is broken.
Using IBRD alone may not achieve the required baud rate
tolerance. Enable the skip_ibrd_fbrd and set_uartclk_rate flags for
the NVIDIA variant.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 drivers/tty/serial/amba-pl011.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index ad06dc4cdf6e..7f8deb30650a 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -218,6 +218,28 @@ static struct vendor_data vendor_st = {
 	.get_fifosize		= get_fifosize_st,
 };
 
+static unsigned int get_fifosize_nvidia(struct amba_device *dev)
+{
+	return 32;
+}
+
+static struct vendor_data vendor_nvidia = {
+	.reg_offset		= pl011_std_offsets,
+	.ifls			= UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8,
+	.fr_busy		= UART01x_FR_BUSY,
+	.fr_dsr			= UART01x_FR_DSR,
+	.fr_cts			= UART01x_FR_CTS,
+	.fr_ri			= UART011_FR_RI,
+	.oversampling		= false,
+	.dma_threshold		= false,
+	.cts_event_workaround	= false,
+	.always_enabled		= false,
+	.fixed_options		= false,
+	.skip_ibrd_fbrd		= true,
+	.set_uartclk_rate	= true,
+	.get_fifosize		= get_fifosize_nvidia,
+};
+
 /* Deals with DMA transactions */
 
 struct pl011_dmabuf {
@@ -3115,6 +3137,11 @@ static const struct amba_id pl011_ids[] = {
 		.mask	= 0x00ffffff,
 		.data	= &vendor_st,
 	},
+	{
+		.id	= 0x0006b011,
+		.mask	= 0x000fffff,
+		.data	= &vendor_nvidia,
+	},
 	{ 0, 0 },
 };
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/4] serial: amba-pl011: Respect DMA controller's copy_align requirement
  2026-02-25  6:59 [PATCH 0/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
                   ` (2 preceding siblings ...)
  2026-02-25  6:59 ` [PATCH 3/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
@ 2026-02-25  6:59 ` Kartik Rajput
  3 siblings, 0 replies; 5+ messages in thread
From: Kartik Rajput @ 2026-02-25  6:59 UTC (permalink / raw)
  To: linux, gregkh, jirislaby, mingo, tglx, linmq006, arnd,
	thierry.reding, jonathanh, linux-kernel, linux-serial
  Cc: Kartik Rajput

Some DMA controllers require transfer lengths to be aligned to a
specific boundary. For example, the Tegra GPC DMA requires 4-byte
(word) aligned transfers and will reject unaligned lengths.

Align the TX DMA buffer length down to the DMA controller's copy_align
boundary before submitting the transfer. Any remaining unaligned bytes
will be transmitted via PIO on subsequent calls, which is the existing
fallback behavior when DMA is not used.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 drivers/tty/serial/amba-pl011.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 7f8deb30650a..98e434b0c30a 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -649,6 +649,15 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
 		count = PL011_DMA_BUFFER_SIZE;
 
 	count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count);
+
+	/*
+	 * Align the TX buffer length to the DMA controller's copy_align
+	 * requirements. Some DMA controllers (e.g., Tegra GPC DMA) require
+	 * word-aligned transfers. Unaligned bytes will be sent via PIO.
+	 */
+	if (chan->device->copy_align)
+		count = ALIGN_DOWN(count, 1 << chan->device->copy_align);
+
 	dmatx->len = count;
 	dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
 				    DMA_TO_DEVICE);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-02-25  6:59 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-25  6:59 [PATCH 0/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
2026-02-25  6:59 ` [PATCH 1/4] serial: amba-pl011: Introduce skip_ibrd_fbrd vendor flag Kartik Rajput
2026-02-25  6:59 ` [PATCH 2/4] serial: amba-pl011: Introduce set_uartclk_rate " Kartik Rajput
2026-02-25  6:59 ` [PATCH 3/4] serial: amba-pl011: Add Tegra264 UART support Kartik Rajput
2026-02-25  6:59 ` [PATCH 4/4] serial: amba-pl011: Respect DMA controller's copy_align requirement Kartik Rajput

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®