* [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 related [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 related [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 related [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 related [flat|nested] 5+ messages in thread