* [PATCH v7 01/12] serial: 8250_dw: select port setup through platform data
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
@ 2026-11-03 21:39 ` James Hilliard
2026-11-03 21:43 ` sashiko-bot
2026-11-03 21:39 ` [PATCH v7 02/12] serial: 8250: widen RX trigger byte counts to 16 bits James Hilliard
` (10 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:39 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
Select feature discovery and DMA attachment through a platform-data setup
callback. The generic callback probes the optional registers and attaches
DMA when a FIFO size is available. Integrations with a fixed configuration
can supply their own setup before the port is registered. Allow setup to
return an error so integrations can reject invalid configuration before
registration.
Replace skip_autocfg with the Octeon setup selection. Octeon is a 64-bit
platform and continues to skip optional-register probing while preserving
its existing conditional DMA attachment. Select the DMA setup helper
directly for this integration. Keep generic setup for devices without
matched platform data as well.
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 41 ++++++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 9cbe076463e0..a546cf2de7b6 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -64,6 +64,7 @@ struct dw8250_platform_data {
u8 usr_reg;
u32 cpr_value;
unsigned int quirks;
+ int (*setup)(struct uart_port *p);
};
struct dw8250_data {
@@ -76,7 +77,6 @@ struct dw8250_data {
struct clk *pclk;
struct reset_control *rst;
- unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
unsigned int in_idle:1;
@@ -596,7 +596,6 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_out = dw8250_serial_outq;
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
p->type = PORT_OCTEON;
- data->skip_autocfg = true;
}
#endif
@@ -631,6 +630,28 @@ static void dw8250_shutdown(struct uart_port *port)
d->no_int_count = 0;
}
+static int dw8250_setup_dma(struct uart_port *p)
+{
+ struct dw8250_data *data = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+
+ /* DMA setup requires a FIFO */
+ if (!p->fifosize)
+ return 0;
+
+ data->data.dma.rxconf.src_maxburst = p->fifosize / 4;
+ data->data.dma.txconf.dst_maxburst = p->fifosize / 4;
+ up->dma = &data->data.dma;
+
+ return 0;
+}
+
+static int dw8250_setup(struct uart_port *p)
+{
+ dw8250_setup_port(p);
+ return dw8250_setup_dma(p);
+}
+
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {}, *up = &uart;
@@ -765,19 +786,16 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_setup_dma_filter(p, data);
- if (!data->skip_autocfg)
- dw8250_setup_port(p);
+ if (data->pdata && data->pdata->setup)
+ err = data->pdata->setup(p);
+ else
+ err = dw8250_setup(p);
+ if (err)
+ return err;
/* Use the BUSY-safe sequence for both integer and fractional divisors. */
p->set_divisor = dw8250_set_divisor;
- /* If we have a valid fifosize, try hooking up DMA */
- if (p->fifosize) {
- data->data.dma.rxconf.src_maxburst = p->fifosize / 4;
- data->data.dma.txconf.dst_maxburst = p->fifosize / 4;
- up->dma = &data->data.dma;
- }
-
data->data.uport = serial8250_register_8250_port(up);
if (IS_ERR(data->data.uport))
return PTR_ERR(data->data.uport);
@@ -860,6 +878,7 @@ static const struct dw8250_platform_data dw8250_dw_apb = {
static const struct dw8250_platform_data dw8250_octeon_3860_data = {
.usr_reg = OCTEON_UART_USR,
.quirks = DW_UART_QUIRK_OCTEON,
+ .setup = dw8250_setup_dma,
};
static const struct dw8250_platform_data dw8250_armada_38x_data = {
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 02/12] serial: 8250: widen RX trigger byte counts to 16 bits
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
2026-11-03 21:39 ` [PATCH v7 01/12] serial: 8250_dw: select port setup through platform data James Hilliard
@ 2026-11-03 21:39 ` James Hilliard
2026-11-03 21:43 ` sashiko-bot
2026-11-03 21:39 ` [PATCH v7 03/12] serial: 8250: share the RX trigger conversion helper James Hilliard
` (9 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:39 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
DesignWare UARTs can have 2048-byte FIFOs, with receive thresholds as
large as 2046 bytes. The byte-sized threshold tables, setter argument and
sysfs parser cannot represent these values.
Use u16 for the threshold tables and byte counts throughout the 8250
conversion and sysfs paths, including the uart_port callback interface.
Keep the FCR encoding byte-sized and preserve the existing threshold
selection. The Moxa setter continues to validate against its 128-byte
FIFO before writing the byte-sized trigger register.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/tty/serial/8250/8250.h | 2 +-
drivers/tty/serial/8250/8250_mxpcie.c | 2 +-
drivers/tty/serial/8250/8250_port.c | 12 ++++++------
include/linux/serial_core.h | 2 +-
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 21ed9c41b751..939b7d4209f1 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -69,7 +69,7 @@ struct serial8250_config {
unsigned short fifo_size;
unsigned short tx_loadsz;
unsigned char fcr;
- unsigned char rxtrig_bytes[UART_FCR_R_TRIG_MAX_STATE];
+ u16 rxtrig_bytes[UART_FCR_R_TRIG_MAX_STATE];
unsigned int flags;
};
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index 4935a5d1c1a3..4f0b881b4f83 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -257,7 +257,7 @@ static int mxpcie8250_get_rxtrig(struct uart_port *port)
return serial_port_in(port, MOXA_PUART_RTL);
}
-static int mxpcie8250_set_rxtrig(struct uart_port *port, unsigned char bytes)
+static int mxpcie8250_set_rxtrig(struct uart_port *port, u16 bytes)
{
struct mxpcie8250 *priv = dev_get_drvdata(port->dev);
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 36b2b0a2c05c..452851815ffc 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -3008,14 +3008,14 @@ static int serial8250_request_port(struct uart_port *port)
static int fcr_get_rxtrig_bytes(struct uart_8250_port *up)
{
const struct serial8250_config *conf_type = &uart_config[up->port.type];
- unsigned char bytes;
+ u16 bytes;
bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)];
return bytes ? bytes : -EOPNOTSUPP;
}
-static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes)
+static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, u16 bytes)
{
const struct serial8250_config *conf_type = &uart_config[up->port.type];
int i;
@@ -3073,7 +3073,7 @@ static ssize_t rx_trig_bytes_show(struct device *dev,
return sysfs_emit(buf, "%d\n", rxtrig_bytes);
}
-static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
+static int do_set_rxtrig(struct tty_port *port, u16 bytes)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
@@ -3094,7 +3094,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
return 0;
}
-static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes)
+static int do_serial8250_set_rxtrig(struct tty_port *port, u16 bytes)
{
int ret;
@@ -3111,13 +3111,13 @@ static ssize_t rx_trig_bytes_store(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- unsigned char bytes;
+ u16 bytes;
int ret;
if (!count)
return -EINVAL;
- ret = kstrtou8(buf, 10, &bytes);
+ ret = kstrtou16(buf, 10, &bytes);
if (ret < 0)
return ret;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 4eeb8253752a..97301ef66af0 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -461,7 +461,7 @@ struct uart_port {
unsigned int quot,
unsigned int quot_frac);
int (*get_rxtrig)(struct uart_port *port);
- int (*set_rxtrig)(struct uart_port *port, unsigned char bytes);
+ int (*set_rxtrig)(struct uart_port *port, u16 bytes);
int (*startup)(struct uart_port *port);
void (*shutdown)(struct uart_port *port);
void (*throttle)(struct uart_port *port);
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 03/12] serial: 8250: share the RX trigger conversion helper
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
2026-11-03 21:39 ` [PATCH v7 01/12] serial: 8250_dw: select port setup through platform data James Hilliard
2026-11-03 21:39 ` [PATCH v7 02/12] serial: 8250: widen RX trigger byte counts to 16 bits James Hilliard
@ 2026-11-03 21:39 ` James Hilliard
2026-11-03 21:42 ` sashiko-bot
2026-11-03 21:39 ` [PATCH v7 04/12] serial: 8250: expose RX trigger controls for custom callbacks James Hilliard
` (8 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:39 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
Drivers can supply receive-trigger thresholds through the RX trigger
callbacks without adding a legacy port type to uart_config[]. Extract the
threshold search into serial8250_bytes_to_fcr() so those drivers can use
the same conversion as the generic 8250 implementation.
Keep the implementation in 8250_port.c and share it within 8250_base.
Include the unsupported-table check and preserve the existing nearest-lower
selection and highest-encoding fallback.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/tty/serial/8250/8250.h | 2 ++
drivers/tty/serial/8250/8250_port.c | 14 ++++++++++----
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 939b7d4209f1..8729619160ea 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -73,6 +73,8 @@ struct serial8250_config {
unsigned int flags;
};
+int serial8250_bytes_to_fcr(const u16 *rxtrig_bytes, u16 bytes);
+
enum uart_port_type {
/* Internal 8250 only */
UART_PORT_AIROHA = 124,
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 452851815ffc..73bc9e7ab703 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -3015,16 +3015,15 @@ static int fcr_get_rxtrig_bytes(struct uart_8250_port *up)
return bytes ? bytes : -EOPNOTSUPP;
}
-static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, u16 bytes)
+int serial8250_bytes_to_fcr(const u16 *rxtrig_bytes, u16 bytes)
{
- const struct serial8250_config *conf_type = &uart_config[up->port.type];
int i;
- if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)])
+ if (!rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)])
return -EOPNOTSUPP;
for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) {
- if (bytes < conf_type->rxtrig_bytes[i])
+ if (bytes < rxtrig_bytes[i])
/* Use the nearest lower value */
return (--i) << UART_FCR_R_TRIG_SHIFT;
}
@@ -3032,6 +3031,13 @@ static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, u16 bytes)
return UART_FCR_R_TRIG_11;
}
+static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, u16 bytes)
+{
+ const struct serial8250_config *conf_type = &uart_config[up->port.type];
+
+ return serial8250_bytes_to_fcr(conf_type->rxtrig_bytes, bytes);
+}
+
static int do_get_rxtrig(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 04/12] serial: 8250: expose RX trigger controls for custom callbacks
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (2 preceding siblings ...)
2026-11-03 21:39 ` [PATCH v7 03/12] serial: 8250: share the RX trigger conversion helper James Hilliard
@ 2026-11-03 21:39 ` James Hilliard
2026-11-03 21:45 ` sashiko-bot
2026-11-03 21:39 ` [PATCH v7 05/12] serial: 8250_dw: derive RX trigger thresholds from the FIFO depth James Hilliard
` (7 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:39 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
The rx_trig_bytes attribute dispatches to a port's get_rxtrig and
set_rxtrig callbacks when present, but the attribute group is registered
only when the port type has a static receive-trigger table.
Allow a port that supplies both callbacks to expose the attribute without
a static table. This lets integrations such as Octeon provide their
FIFO-relative thresholds through callbacks while retaining their existing
port type. Require both callbacks because the attribute is read/write;
ports with a static table continue to use the existing fallback handlers.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/tty/serial/8250/8250_port.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 73bc9e7ab703..d87e2b852c3c 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -3152,7 +3152,8 @@ static void register_dev_spec_attr_grp(struct uart_8250_port *up)
{
const struct serial8250_config *conf_type = &uart_config[up->port.type];
- if (conf_type->rxtrig_bytes[0])
+ if (conf_type->rxtrig_bytes[0] ||
+ (up->port.get_rxtrig && up->port.set_rxtrig))
up->port.attr_group = &serial8250_dev_attr_group;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 05/12] serial: 8250_dw: derive RX trigger thresholds from the FIFO depth
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (3 preceding siblings ...)
2026-11-03 21:39 ` [PATCH v7 04/12] serial: 8250: expose RX trigger controls for custom callbacks James Hilliard
@ 2026-11-03 21:39 ` James Hilliard
2026-11-03 21:57 ` sashiko-bot
2026-11-03 21:39 ` [PATCH v7 06/12] dt-bindings: serial: snps-dw-apb-uart: add Allwinner H616 James Hilliard
` (6 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:39 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
DW_apb_uart uses receive thresholds of one byte, one quarter full,
one half full and two bytes below full. The generic 16550A table describes
these encodings only for a 16-byte FIFO. For example, the half-full setting
on a 64-byte DW FIFO is reported as eight bytes instead of 32, and a sysfs
request for 32 bytes selects the 62-byte encoding.
Build a per-port threshold table from the discovered FIFO depth in dwlib
and install receive-trigger callbacks for CPR-described FIFOs, including
LPSS ports. Keep the setup helper available to integrations which obtain
the depth without probing the optional DW registers. Validate that each
threshold is positive and representable before constructing the table.
Serialize FCR updates with termios and the port lock, acquire a runtime PM
reference before accessing the device, and propagate resume errors without
changing the shadow or hardware. Update only the trigger field so changing
the threshold preserves the FIFO contents.
The FCR mapping is documented in the DW_apb_uart databook, section 6,
FIFO Control Register. The existing default FCR encoding is unchanged.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/tty/serial/8250/8250_dw.c | 7 ++-
drivers/tty/serial/8250/8250_dwlib.c | 94 +++++++++++++++++++++++++++++++++++-
drivers/tty/serial/8250/8250_dwlib.h | 4 +-
drivers/tty/serial/8250/8250_lpss.c | 4 +-
4 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a546cf2de7b6..613907b8a40f 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -648,7 +648,12 @@ static int dw8250_setup_dma(struct uart_port *p)
static int dw8250_setup(struct uart_port *p)
{
- dw8250_setup_port(p);
+ int ret;
+
+ ret = dw8250_setup_port(p);
+ if (ret)
+ return ret;
+
return dw8250_setup_dma(p);
}
diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c
index 91b3607b64e6..004817cc8f28 100644
--- a/drivers/tty/serial/8250/8250_dwlib.c
+++ b/drivers/tty/serial/8250/8250_dwlib.c
@@ -1,18 +1,27 @@
// SPDX-License-Identifier: GPL-2.0+
/* Synopsys DesignWare 8250 library. */
+#include <linux/array_size.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/limits.h>
#include <linux/math.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include "8250_dwlib.h"
+/* DesignWare FIFO-relative receive thresholds */
+#define DW_UART_RXTRIG_QUARTER_DIV 4
+#define DW_UART_RXTRIG_HALF_DIV 2
+#define DW_UART_RXTRIG_FULL_MARGIN 2
+
/*
* divisor = div(I) + div(F)
* "I" means integer, "F" means fractional
@@ -208,11 +217,86 @@ static const struct serial_rs485 dw8250_rs485_supported = {
SER_RS485_ADDR_DEST,
};
-void dw8250_setup_port(struct uart_port *p)
+/* The trigger is the masked FCR receive trigger field, in register position */
+static unsigned int dw8250_rxtrig_bytes(struct uart_port *p, unsigned int trigger)
+{
+ switch (trigger) {
+ case UART_FCR_TRIGGER_1:
+ return 1;
+ case UART_FCR_TRIGGER_4:
+ return p->fifosize / DW_UART_RXTRIG_QUARTER_DIV;
+ case UART_FCR_TRIGGER_8:
+ return p->fifosize / DW_UART_RXTRIG_HALF_DIV;
+ default:
+ return p->fifosize - DW_UART_RXTRIG_FULL_MARGIN;
+ }
+}
+
+static int dw8250_get_rxtrig(struct uart_port *p)
+{
+ struct dw8250_port_data *pd = p->private_data;
+ struct uart_8250_port *up = up_to_u8250p(p);
+
+ guard(uart_port_lock_irqsave)(p);
+
+ return pd->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)];
+}
+
+static int dw8250_set_rxtrig(struct uart_port *p, u16 bytes)
+{
+ struct dw8250_port_data *pd = p->private_data;
+ struct uart_8250_port *up = up_to_u8250p(p);
+ int fcr, ret;
+
+ fcr = serial8250_bytes_to_fcr(pd->rxtrig_bytes, bytes);
+ if (fcr < 0)
+ return fcr;
+
+ guard(mutex)(&p->state->port.mutex);
+
+ PM_RUNTIME_ACQUIRE_IF_ENABLED(p->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(uart_port_lock_irqsave)(p);
+
+ up->fcr &= ~UART_FCR_TRIGGER_MASK;
+ up->fcr |= fcr;
+ /* Changing the trigger alone preserves the FIFO contents */
+ serial_port_out(p, UART_FCR, up->fcr);
+
+ return 0;
+}
+
+int dw8250_setup_rxtrig(struct uart_port *p)
+{
+ struct dw8250_port_data *pd = p->private_data;
+
+ /* Each FIFO-relative threshold must be positive and fit in the table */
+ if (p->fifosize < DW_UART_RXTRIG_QUARTER_DIV ||
+ p->fifosize - DW_UART_RXTRIG_FULL_MARGIN > U16_MAX)
+ return dev_err_probe(p->dev, -EINVAL,
+ "invalid FIFO size %u\n", p->fifosize);
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(pd->rxtrig_bytes); i++) {
+ unsigned int trigger = FIELD_PREP(UART_FCR_TRIGGER_MASK, i);
+
+ pd->rxtrig_bytes[i] = dw8250_rxtrig_bytes(p, trigger);
+ }
+ p->get_rxtrig = dw8250_get_rxtrig;
+ p->set_rxtrig = dw8250_set_rxtrig;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(dw8250_setup_rxtrig, "SERIAL_8250");
+
+int dw8250_setup_port(struct uart_port *p)
{
struct dw8250_port_data *pd = p->private_data;
struct uart_8250_port *up = up_to_u8250p(p);
u32 reg, old_dlf;
+ int ret;
pd->hw_rs485_support = dw8250_detect_rs485_hw(p);
if (pd->hw_rs485_support) {
@@ -250,7 +334,7 @@ void dw8250_setup_port(struct uart_port *p)
dev_dbg(p->dev, "CPR is not available, using 0x%08x instead\n", reg);
}
if (!reg)
- return;
+ return 0;
/* Select the type based on FIFO */
if (reg & DW_UART_CPR_FIFO_MODE) {
@@ -258,6 +342,10 @@ void dw8250_setup_port(struct uart_port *p)
p->flags |= UPF_FIXED_TYPE;
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
up->capabilities = UART_CAP_FIFO | UART_CAP_NOTEMT;
+
+ ret = dw8250_setup_rxtrig(p);
+ if (ret)
+ return ret;
}
if (reg & DW_UART_CPR_AFCE_MODE)
@@ -270,5 +358,7 @@ void dw8250_setup_port(struct uart_port *p)
pd->srbr = DW_UART_SRBR_0;
else
pd->srbr = UART_RX;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(dw8250_setup_port);
diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h
index 7191cabfb086..44a5d0c2feba 100644
--- a/drivers/tty/serial/8250/8250_dwlib.h
+++ b/drivers/tty/serial/8250/8250_dwlib.h
@@ -88,6 +88,7 @@ struct dw8250_port_data {
/* Hardware configuration */
u32 cpr_value;
u8 dlf_size;
+ u16 rxtrig_bytes[UART_FCR_R_TRIG_MAX_STATE];
/* RS485 variables */
bool hw_rs485_support;
@@ -100,7 +101,8 @@ struct dw8250_port_data {
unsigned int dw8250_get_divisor_dlf(struct uart_port *p, unsigned int baud, unsigned int *frac);
void dw8250_set_divisor_dlf(struct uart_port *p, unsigned int quot_frac);
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old);
-void dw8250_setup_port(struct uart_port *p);
+int dw8250_setup_rxtrig(struct uart_port *p);
+int dw8250_setup_port(struct uart_port *p);
static inline u32 dw8250_readl_ext(struct uart_port *p, int offset)
{
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index f1b4b975571a..7ace0515038e 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -350,7 +350,9 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
return ret;
- dw8250_setup_port(&uart.port);
+ ret = dw8250_setup_port(&uart.port);
+ if (ret)
+ goto err_exit;
ret = lpss8250_dma_setup(lpss, &uart);
if (ret)
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v7 05/12] serial: 8250_dw: derive RX trigger thresholds from the FIFO depth
2026-11-03 21:39 ` [PATCH v7 05/12] serial: 8250_dw: derive RX trigger thresholds from the FIFO depth James Hilliard
@ 2026-11-03 21:57 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-11-03 21:57 UTC (permalink / raw)
To: James Hilliard; +Cc: linux-serial
> DW_apb_uart uses receive thresholds of one byte, one quarter full,
> one half full and two bytes below full. The generic 16550A table describes
> these encodings only for a 16-byte FIFO. For example, the half-full setting
> on a 64-byte DW FIFO is reported as eight bytes instead of 32, and a sysfs
> request for 32 bytes selects the 62-byte encoding.
>
> Build a per-port threshold table from the discovered FIFO depth in dwlib
> and install receive-trigger callbacks for CPR-described FIFOs, including
> LPSS ports. Keep the setup helper available to integrations which obtain
> the depth without probing the optional DW registers. Validate that each
> threshold is positive and representable before constructing the table.
>
> Serialize FCR updates with termios and the port lock, acquire a runtime PM
> reference before accessing the device, and propagate resume errors without
> changing the shadow or hardware. Update only the trigger field so changing
> the threshold preserves the FIFO contents.
>
> The FCR mapping is documented in the DW_apb_uart databook, section 6,
> FIFO Control Register. The existing default FCR encoding is unchanged.
>
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103-submit-h616-uart-fifo-v1-v7-0-c9e248d685c1@gmail.com?part=5
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v7 06/12] dt-bindings: serial: snps-dw-apb-uart: add Allwinner H616
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (4 preceding siblings ...)
2026-11-03 21:39 ` [PATCH v7 05/12] serial: 8250_dw: derive RX trigger thresholds from the FIFO depth James Hilliard
@ 2026-11-03 21:39 ` James Hilliard
2026-11-03 21:48 ` sashiko-bot
2026-11-03 21:40 ` [PATCH v7 07/12] serial: 8250_dw: configure the Allwinner H616 UART James Hilliard
` (5 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:39 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard, Krzysztof Kozlowski
The H616 UART has 256-byte transmit and receive FIFOs, but its DesignWare
component parameter register does not report the FIFO depth. Its optional
register layout also differs from the generic DesignWare integration.
Add a specific compatible to identify this fixed configuration, retaining
snps,dw-apb-uart as a fallback.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index e2ca126d58ba..fc1289073241 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -60,6 +60,7 @@ properties:
- const: renesas,rzn1-uart
- items:
- enum:
+ - allwinner,sun50i-h616-uart
- anlogic,dr1v90-uart
- brcm,bcm11351-dw-apb-uart
- brcm,bcm21664-dw-apb-uart
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 07/12] serial: 8250_dw: configure the Allwinner H616 UART
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (5 preceding siblings ...)
2026-11-03 21:39 ` [PATCH v7 06/12] dt-bindings: serial: snps-dw-apb-uart: add Allwinner H616 James Hilliard
@ 2026-11-03 21:40 ` James Hilliard
2026-11-03 21:46 ` sashiko-bot
2026-11-03 21:40 ` [PATCH v7 08/12] arm64: dts: allwinner: h616: describe the UART integration James Hilliard
` (4 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:40 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
H616 has 256-byte transmit and receive FIFOs, but its optional DesignWare
component parameter register reads as zero. Generic 16550 probing leaves
the port using the 16-byte FIFO configuration and its trigger-level table.
Keep PORT_16550A and supply the fixed FIFO depth through platform data.
The 8250 core derives the transmit load from that depth. Use the shared
DesignWare receive-trigger setup to describe the 1, 64, 128 and 254-byte
thresholds, with the normal half-full FCR setting selecting 128 bytes.
Advertise automatic flow control so CRTSCTS enables MCR.AFCE, matching the
DesignWare termios path for hardware CTS handling.
Select this configuration through the platform setup callback. H616
has debug-divisor and RS485 control registers overlapping the optional
DesignWare feature probes. Use the fixed configuration with BUSY-safe
integer divisor programming and software RS485 handling.
Keep the UART clock enabled during termios changes with SKIP_SET_RATE.
Its clock is a gate on the shared APB2 source rather than an independent
baud-rate generator.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/tty/serial/8250/8250_dw.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 613907b8a40f..0e7367ba872e 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -63,6 +63,7 @@
struct dw8250_platform_data {
u8 usr_reg;
u32 cpr_value;
+ unsigned int fifo_size;
unsigned int quirks;
int (*setup)(struct uart_port *p);
};
@@ -657,6 +658,30 @@ static int dw8250_setup(struct uart_port *p)
return dw8250_setup_dma(p);
}
+static int dw8250_sunxi_setup(struct uart_port *p)
+{
+ struct dw8250_data *data = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+ int ret;
+
+ p->type = PORT_16550A;
+ p->flags |= UPF_FIXED_TYPE;
+ p->fifosize = data->pdata->fifo_size;
+ up->capabilities = UART_CAP_FIFO | UART_CAP_NOTEMT | UART_CAP_AFE;
+
+ ret = dw8250_setup_rxtrig(p);
+ if (ret)
+ return ret;
+
+ /* Use software RS485 with the Allwinner register layout */
+ p->rs485_config = serial8250_em485_config;
+ p->rs485_supported = serial8250_em485_supported;
+ up->rs485_start_tx = serial8250_em485_start_tx;
+ up->rs485_stop_tx = serial8250_em485_stop_tx;
+
+ return 0;
+}
+
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {}, *up = &uart;
@@ -880,6 +905,13 @@ static const struct dw8250_platform_data dw8250_dw_apb = {
.usr_reg = DW_UART_USR,
};
+static const struct dw8250_platform_data dw8250_h616_data = {
+ .usr_reg = DW_UART_USR,
+ .fifo_size = 256,
+ .quirks = DW_UART_QUIRK_SKIP_SET_RATE,
+ .setup = dw8250_sunxi_setup,
+};
+
static const struct dw8250_platform_data dw8250_octeon_3860_data = {
.usr_reg = OCTEON_UART_USR,
.quirks = DW_UART_QUIRK_OCTEON,
@@ -931,6 +963,7 @@ static const struct dw8250_platform_data dw8250_tda54 = {
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
+ { .compatible = "allwinner,sun50i-h616-uart", .data = &dw8250_h616_data },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
{ .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data },
{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v7 07/12] serial: 8250_dw: configure the Allwinner H616 UART
2026-11-03 21:40 ` [PATCH v7 07/12] serial: 8250_dw: configure the Allwinner H616 UART James Hilliard
@ 2026-11-03 21:46 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-11-03 21:46 UTC (permalink / raw)
To: James Hilliard; +Cc: linux-serial
> H616 has 256-byte transmit and receive FIFOs, but its optional DesignWare
> component parameter register reads as zero. Generic 16550 probing leaves
> the port using the 16-byte FIFO configuration and its trigger-level table.
>
> Keep PORT_16550A and supply the fixed FIFO depth through platform data.
> The 8250 core derives the transmit load from that depth. Use the shared
> DesignWare receive-trigger setup to describe the 1, 64, 128 and 254-byte
> thresholds, with the normal half-full FCR setting selecting 128 bytes.
>
> Advertise automatic flow control so CRTSCTS enables MCR.AFCE, matching the
> DesignWare termios path for hardware CTS handling.
>
> Select this configuration through the platform setup callback. H616
> has debug-divisor and RS485 control registers overlapping the optional
> DesignWare feature probes. Use the fixed configuration with BUSY-safe
> integer divisor programming and software RS485 handling.
>
> Keep the UART clock enabled during termios changes with SKIP_SET_RATE.
> Its clock is a gate on the shared APB2 source rather than an independent
> baud-rate generator.
>
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103-submit-h616-uart-fifo-v1-v7-0-c9e248d685c1@gmail.com?part=7
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v7 08/12] arm64: dts: allwinner: h616: describe the UART integration
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (6 preceding siblings ...)
2026-11-03 21:40 ` [PATCH v7 07/12] serial: 8250_dw: configure the Allwinner H616 UART James Hilliard
@ 2026-11-03 21:40 ` James Hilliard
2026-11-03 21:46 ` sashiko-bot
2026-11-03 21:40 ` [PATCH v7 09/12] dt-bindings: serial: snps-dw-apb-uart: add Allwinner A523 James Hilliard
` (3 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:40 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
Identify the H616 UART integration on each of the six controllers. The
specific compatible selects its fixed FIFO depth and integration-specific
register setup. The driver uses that depth to derive the shared DesignWare
receive thresholds.
Retain snps,dw-apb-uart as the generic fallback. H618 includes this DTSI
and uses the same UART integration.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
index c6b3a3f8359a..b4b2f85726e0 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
@@ -550,7 +550,7 @@ mmc2: mmc@4022000 {
};
uart0: serial@5000000 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun50i-h616-uart", "snps,dw-apb-uart";
reg = <0x05000000 0x400>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -563,7 +563,7 @@ uart0: serial@5000000 {
};
uart1: serial@5000400 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun50i-h616-uart", "snps,dw-apb-uart";
reg = <0x05000400 0x400>;
interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -576,7 +576,7 @@ uart1: serial@5000400 {
};
uart2: serial@5000800 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun50i-h616-uart", "snps,dw-apb-uart";
reg = <0x05000800 0x400>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -589,7 +589,7 @@ uart2: serial@5000800 {
};
uart3: serial@5000c00 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun50i-h616-uart", "snps,dw-apb-uart";
reg = <0x05000c00 0x400>;
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -602,7 +602,7 @@ uart3: serial@5000c00 {
};
uart4: serial@5001000 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun50i-h616-uart", "snps,dw-apb-uart";
reg = <0x05001000 0x400>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -615,7 +615,7 @@ uart4: serial@5001000 {
};
uart5: serial@5001400 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun50i-h616-uart", "snps,dw-apb-uart";
reg = <0x05001400 0x400>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 09/12] dt-bindings: serial: snps-dw-apb-uart: add Allwinner A523
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (7 preceding siblings ...)
2026-11-03 21:40 ` [PATCH v7 08/12] arm64: dts: allwinner: h616: describe the UART integration James Hilliard
@ 2026-11-03 21:40 ` James Hilliard
2026-11-03 21:44 ` sashiko-bot
2026-11-03 21:40 ` [PATCH v7 10/12] serial: 8250_dw: discover Allwinner A523 FIFO depths through FCC James Hilliard
` (2 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:40 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard, Krzysztof Kozlowski
The A523 UART integration has different FIFO depths across its controllers
and reports each controller's depth in the FIFO Clock Control register.
The receive thresholds follow the standard DesignWare FIFO-relative
mapping, while the optional-register layout differs from the generic
DesignWare integration.
Add a compatible for this integration, also used by A527 and T527, with
snps,dw-apb-uart as a fallback.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index fc1289073241..ea6ce99178e3 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -61,6 +61,7 @@ properties:
- items:
- enum:
- allwinner,sun50i-h616-uart
+ - allwinner,sun55i-a523-uart
- anlogic,dr1v90-uart
- brcm,bcm11351-dw-apb-uart
- brcm,bcm21664-dw-apb-uart
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 10/12] serial: 8250_dw: discover Allwinner A523 FIFO depths through FCC
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (8 preceding siblings ...)
2026-11-03 21:40 ` [PATCH v7 09/12] dt-bindings: serial: snps-dw-apb-uart: add Allwinner A523 James Hilliard
@ 2026-11-03 21:40 ` James Hilliard
2026-11-03 21:45 ` sashiko-bot
2026-11-03 21:40 ` [PATCH v7 11/12] arm64: dts: allwinner: a523: describe the UART integration James Hilliard
2026-11-03 21:40 ` [PATCH v7 12/12] serial: 8250_dw: configure RX trigger thresholds for Octeon James Hilliard
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:40 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
The A523 UART integration, also used by A527 and T527, has 64-byte FIFOs
on UART0 and 128-byte FIFOs on UART1 through UART7. Each controller reports
its TX/RX FIFO depth in bits 31:8 of the FIFO Clock Control register at
offset 0xf0. The field holds a byte count, not a logarithmic encoding.
Read this field in the sunxi setup callback when platform data does not
provide a fixed FIFO size. A fixed size takes precedence, so H616 retains
its 256-byte configuration without accessing FCC. The probe has already
enabled the clocks and deasserted reset before invoking the callback.
Leave the FIFO clock-control bits untouched.
Use the shared DesignWare trigger setup to validate the depth and build
the FIFO-relative threshold table. Invalid depths fail probe before
registration instead of producing zero or truncated thresholds. The 8250
core derives the transmit load from the discovered depth.
Select this setup for the A523 compatible. Like H616, this integration
has Allwinner-specific debug-divisor and RS485 registers overlapping the
generic DesignWare feature probes. Use the common sunxi PIO setup,
BUSY-safe integer divisor programming and software RS485 handling. Keep
the APB clock gate enabled during termios updates with SKIP_SET_RATE.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/tty/serial/8250/8250_dw.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 0e7367ba872e..cdd3a62dfa7e 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -44,6 +44,10 @@
#define RZN1_UART_xDMACR_8_WORD_BURST (2 << 1)
#define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3)
+/* Allwinner FIFO Clock Control register */
+#define SUNXI_UART_FCC 0xf0
+#define SUNXI_UART_FCC_FIFO_DEPTH GENMASK(31, 8)
+
/* Quirks */
#define DW_UART_QUIRK_OCTEON BIT(0)
#define DW_UART_QUIRK_ARMADA_38X BIT(1)
@@ -63,6 +67,7 @@
struct dw8250_platform_data {
u8 usr_reg;
u32 cpr_value;
+ /* Fixed FIFO depth; zero selects discovery during setup */
unsigned int fifo_size;
unsigned int quirks;
int (*setup)(struct uart_port *p);
@@ -666,7 +671,13 @@ static int dw8250_sunxi_setup(struct uart_port *p)
p->type = PORT_16550A;
p->flags |= UPF_FIXED_TYPE;
- p->fifosize = data->pdata->fifo_size;
+ if (data->pdata->fifo_size) {
+ p->fifosize = data->pdata->fifo_size;
+ } else {
+ u32 fcc = dw8250_readl_ext(p, SUNXI_UART_FCC);
+
+ p->fifosize = FIELD_GET(SUNXI_UART_FCC_FIFO_DEPTH, fcc);
+ }
up->capabilities = UART_CAP_FIFO | UART_CAP_NOTEMT | UART_CAP_AFE;
ret = dw8250_setup_rxtrig(p);
@@ -912,6 +923,12 @@ static const struct dw8250_platform_data dw8250_h616_data = {
.setup = dw8250_sunxi_setup,
};
+static const struct dw8250_platform_data dw8250_a523_data = {
+ .usr_reg = DW_UART_USR,
+ .quirks = DW_UART_QUIRK_SKIP_SET_RATE,
+ .setup = dw8250_sunxi_setup,
+};
+
static const struct dw8250_platform_data dw8250_octeon_3860_data = {
.usr_reg = OCTEON_UART_USR,
.quirks = DW_UART_QUIRK_OCTEON,
@@ -964,6 +981,7 @@ static const struct dw8250_platform_data dw8250_tda54 = {
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "allwinner,sun50i-h616-uart", .data = &dw8250_h616_data },
+ { .compatible = "allwinner,sun55i-a523-uart", .data = &dw8250_a523_data },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
{ .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data },
{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH v7 10/12] serial: 8250_dw: discover Allwinner A523 FIFO depths through FCC
2026-11-03 21:40 ` [PATCH v7 10/12] serial: 8250_dw: discover Allwinner A523 FIFO depths through FCC James Hilliard
@ 2026-11-03 21:45 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-11-03 21:45 UTC (permalink / raw)
To: James Hilliard; +Cc: linux-serial
> The A523 UART integration, also used by A527 and T527, has 64-byte FIFOs
> on UART0 and 128-byte FIFOs on UART1 through UART7. Each controller reports
> its TX/RX FIFO depth in bits 31:8 of the FIFO Clock Control register at
> offset 0xf0. The field holds a byte count, not a logarithmic encoding.
>
> Read this field in the sunxi setup callback when platform data does not
> provide a fixed FIFO size. A fixed size takes precedence, so H616 retains
> its 256-byte configuration without accessing FCC. The probe has already
> enabled the clocks and deasserted reset before invoking the callback.
> Leave the FIFO clock-control bits untouched.
>
> Use the shared DesignWare trigger setup to validate the depth and build
> the FIFO-relative threshold table. Invalid depths fail probe before
> registration instead of producing zero or truncated thresholds. The 8250
> core derives the transmit load from the discovered depth.
>
> Select this setup for the A523 compatible. Like H616, this integration
> has Allwinner-specific debug-divisor and RS485 registers overlapping the
> generic DesignWare feature probes. Use the common sunxi PIO setup,
> BUSY-safe integer divisor programming and software RS485 handling. Keep
> the APB clock gate enabled during termios updates with SKIP_SET_RATE.
>
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103-submit-h616-uart-fifo-v1-v7-0-c9e248d685c1@gmail.com?part=10
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v7 11/12] arm64: dts: allwinner: a523: describe the UART integration
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (9 preceding siblings ...)
2026-11-03 21:40 ` [PATCH v7 10/12] serial: 8250_dw: discover Allwinner A523 FIFO depths through FCC James Hilliard
@ 2026-11-03 21:40 ` James Hilliard
2026-11-03 21:46 ` sashiko-bot
2026-11-03 21:40 ` [PATCH v7 12/12] serial: 8250_dw: configure RX trigger thresholds for Octeon James Hilliard
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:40 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
Identify the Allwinner UART integration on all eight CPUX controllers.
The specific compatible selects FIFO-depth discovery through FCC,
allowing the driver to derive the shared DesignWare receive thresholds
from each controller's FIFO capacity.
Retain snps,dw-apb-uart as a fallback. The common SoC description supplies
these UART nodes to the A527 and T527 boards as well.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
index 85ef492ffeae..23340b9f58cb 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
@@ -390,7 +390,7 @@ wdt: watchdog@2050000 {
};
uart0: serial@2500000 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02500000 0x400>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -403,7 +403,7 @@ uart0: serial@2500000 {
};
uart1: serial@2500400 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02500400 0x400>;
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -416,7 +416,7 @@ uart1: serial@2500400 {
};
uart2: serial@2500800 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02500800 0x400>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -429,7 +429,7 @@ uart2: serial@2500800 {
};
uart3: serial@2500c00 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02500c00 0x400>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -442,7 +442,7 @@ uart3: serial@2500c00 {
};
uart4: serial@2501000 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02501000 0x400>;
interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -455,7 +455,7 @@ uart4: serial@2501000 {
};
uart5: serial@2501400 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02501400 0x400>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -468,7 +468,7 @@ uart5: serial@2501400 {
};
uart6: serial@2501800 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02501800 0x400>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
@@ -481,7 +481,7 @@ uart6: serial@2501800 {
};
uart7: serial@2501c00 {
- compatible = "snps,dw-apb-uart";
+ compatible = "allwinner,sun55i-a523-uart", "snps,dw-apb-uart";
reg = <0x02501c00 0x400>;
interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH v7 12/12] serial: 8250_dw: configure RX trigger thresholds for Octeon
2026-11-03 21:39 [PATCH v7 00/12] serial: 8250_dw: share RX trigger setup and describe Allwinner UARTs James Hilliard
` (10 preceding siblings ...)
2026-11-03 21:40 ` [PATCH v7 11/12] arm64: dts: allwinner: a523: describe the UART integration James Hilliard
@ 2026-11-03 21:40 ` James Hilliard
2026-11-03 21:47 ` sashiko-bot
11 siblings, 1 reply; 25+ messages in thread
From: James Hilliard @ 2026-11-03 21:40 UTC (permalink / raw)
To: Andy Shevchenko, Ilpo Järvinen, Greg Kroah-Hartman,
Jiri Slaby, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
Cc: linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-sunxi, James Hilliard
Octeon uses the DesignWare receive-trigger mapping with a 64-byte FIFO,
giving thresholds of 1, 16, 32 and 62 bytes. Its setup bypasses
dw8250_setup_port(), so it does not install the common trigger callbacks.
PORT_OCTEON also has no static trigger table, so rx_trig_bytes is not
exposed.
Supply the fixed depth from platform data when firmware has not provided
one and initialize the common trigger table before port registration.
This makes rx_trig_bytes available while preserving the Octeon port type
and register accessors.
Select DMA before filling in the default depth, as before when the 8250
core supplied that default during registration. Thus the new trigger
setup preserves which ports attach DMA and their existing burst sizes.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/tty/serial/8250/8250_dw.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index cdd3a62dfa7e..063441923864 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -663,6 +663,22 @@ static int dw8250_setup(struct uart_port *p)
return dw8250_setup_dma(p);
}
+static int dw8250_octeon_setup(struct uart_port *p)
+{
+ struct dw8250_data *data = to_dw8250_data(p->private_data);
+ int ret;
+
+ /* Preserve DMA selection before supplying the fixed FIFO depth */
+ ret = dw8250_setup_dma(p);
+ if (ret)
+ return ret;
+
+ if (!p->fifosize)
+ p->fifosize = data->pdata->fifo_size;
+
+ return dw8250_setup_rxtrig(p);
+}
+
static int dw8250_sunxi_setup(struct uart_port *p)
{
struct dw8250_data *data = to_dw8250_data(p->private_data);
@@ -931,8 +947,9 @@ static const struct dw8250_platform_data dw8250_a523_data = {
static const struct dw8250_platform_data dw8250_octeon_3860_data = {
.usr_reg = OCTEON_UART_USR,
+ .fifo_size = 64,
.quirks = DW_UART_QUIRK_OCTEON,
- .setup = dw8250_setup_dma,
+ .setup = dw8250_octeon_setup,
};
static const struct dw8250_platform_data dw8250_armada_38x_data = {
--
2.53.0
^ permalink raw reply related [flat|nested] 25+ messages in thread