From: James Hilliard <james.hilliard1@gmail.com>
To: "Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Jiri Slaby" <jirislaby@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Chen-Yu Tsai" <wens@kernel.org>,
"Jernej Skrabec" <jernej.skrabec@gmail.com>,
"Samuel Holland" <samuel@sholland.org>
Cc: linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org,
devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-sunxi@lists.linux.dev,
James Hilliard <james.hilliard1@gmail.com>
Subject: [PATCH v6 4/8] serial: 8250_dw: configure the Allwinner H616 UART
Date: Mon, 02 Nov 2026 12:55:19 -0700 [thread overview]
Message-ID: <20261102-submit-h616-uart-fifo-v1-v6-4-25afcb346b0c@gmail.com> (raw)
In-Reply-To: <20261102-submit-h616-uart-fifo-v1-v6-0-25afcb346b0c@gmail.com>
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 H616's fixed FIFO depth through platform data.
The 8250 core derives the transmit load from that depth.
Allwinner encodes receive thresholds relative to the FIFO depth: one byte,
quarter-full, half-full and depth minus two. Construct the RX trigger
threshold array on the fly so other FIFO sizes can reuse the same mapping.
For H616 the thresholds are 1, 64, 128 and 254 bytes, with the normal
half-full FCR setting selecting 128 bytes. Use this array for both RX
trigger callbacks and the shared bytes-to-FCR conversion.
Serialize trigger changes with termios through the port mutex. Hold a
runtime PM reference for the register access and the UART port lock while
updating the FCR shadow and hardware. Changing only the trigger field
preserves the FIFO contents; a runtime resume failure leaves both the
shadow and hardware unchanged.
Advertise automatic flow control so CRTSCTS enables MCR.AFCE, matching the
DesignWare termios path's hardware CTS handling.
Select this configuration through the platform setup callback. H616's
debug-divisor and RS485 control registers overlap offsets used to detect
generic DesignWare features. 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 | 104 ++++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a546cf2de7b6..0b0156464af6 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -9,6 +9,7 @@
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
+#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
@@ -19,6 +20,7 @@
#include <linux/io.h>
#include <linux/lockdep.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -44,6 +46,11 @@
#define RZN1_UART_xDMACR_8_WORD_BURST (2 << 1)
#define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3)
+/* Allwinner FIFO-relative receive thresholds */
+#define SUNXI_UART_RXTRIG_QUARTER_DIV 4
+#define SUNXI_UART_RXTRIG_HALF_DIV 2
+#define SUNXI_UART_RXTRIG_FULL_MARGIN 2
+
/* Quirks */
#define DW_UART_QUIRK_OCTEON BIT(0)
#define DW_UART_QUIRK_ARMADA_38X BIT(1)
@@ -63,6 +70,7 @@
struct dw8250_platform_data {
u8 usr_reg;
u32 cpr_value;
+ unsigned int fifo_size;
unsigned int quirks;
int (*setup)(struct uart_port *p);
};
@@ -81,6 +89,7 @@ struct dw8250_data {
unsigned int in_idle:1;
u8 no_int_count;
+ u8 rxtrig_bytes[UART_FCR_R_TRIG_MAX_STATE];
};
static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
@@ -652,6 +661,93 @@ static int dw8250_setup(struct uart_port *p)
return dw8250_setup_dma(p);
}
+/* The trigger is the masked FCR receive trigger field, in register position */
+static unsigned int dw8250_sunxi_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 / SUNXI_UART_RXTRIG_QUARTER_DIV;
+ case UART_FCR_TRIGGER_8:
+ return p->fifosize / SUNXI_UART_RXTRIG_HALF_DIV;
+ default:
+ return p->fifosize - SUNXI_UART_RXTRIG_FULL_MARGIN;
+ }
+}
+
+static int dw8250_sunxi_get_rxtrig(struct uart_port *p)
+{
+ struct dw8250_data *data = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+
+ guard(uart_port_lock_irqsave)(p);
+
+ return data->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)];
+}
+
+static int dw8250_sunxi_set_rxtrig(struct uart_port *p, unsigned char bytes)
+{
+ struct dw8250_data *data = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+ int fcr, ret;
+
+ fcr = serial8250_bytes_to_fcr(data->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;
+}
+
+static void dw8250_sunxi_setup_rxtrig(struct uart_port *p)
+{
+ struct dw8250_data *data = to_dw8250_data(p->private_data);
+
+ /* Allwinner RX thresholds differ from the standard 16550A table */
+ for (unsigned int i = 0; i < ARRAY_SIZE(data->rxtrig_bytes); i++) {
+ unsigned int trigger = FIELD_PREP(UART_FCR_TRIGGER_MASK, i);
+
+ data->rxtrig_bytes[i] = dw8250_sunxi_rxtrig_bytes(p, trigger);
+ }
+ p->get_rxtrig = dw8250_sunxi_get_rxtrig;
+ p->set_rxtrig = dw8250_sunxi_set_rxtrig;
+}
+
+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);
+
+ 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;
+
+ dw8250_sunxi_setup_rxtrig(p);
+
+ /* 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;
@@ -875,6 +971,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,
@@ -926,6 +1029,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
next prev parent reply other threads:[~2026-11-02 19:55 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 19:55 [PATCH v6 0/8] serial: 8250_dw: describe the Allwinner H616 and A523 UART configurations James Hilliard
2026-11-02 19:55 ` [PATCH v6 1/8] serial: 8250_dw: select port setup through platform data James Hilliard
2026-11-02 19:55 ` [PATCH v6 2/8] serial: 8250: share the RX trigger conversion helper James Hilliard
2026-11-02 19:55 ` [PATCH v6 3/8] dt-bindings: serial: snps-dw-apb-uart: add Allwinner H616 James Hilliard
2026-11-02 19:55 ` James Hilliard [this message]
2026-11-02 19:55 ` [PATCH v6 5/8] arm64: dts: allwinner: h616: describe the UART integration James Hilliard
2026-11-02 19:55 ` [PATCH v6 6/8] dt-bindings: serial: snps-dw-apb-uart: add Allwinner A523 James Hilliard
2026-11-02 19:55 ` [PATCH v6 7/8] serial: 8250_dw: discover Allwinner A523 FIFO depths through FCC James Hilliard
2026-11-02 19:55 ` [PATCH v6 8/8] arm64: dts: allwinner: a523: describe the UART integration James Hilliard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261102-submit-h616-uart-fifo-v1-v6-4-25afcb346b0c@gmail.com \
--to=james.hilliard1@gmail.com \
--cc=andriy.shevchenko@linux.intel.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=jernej.skrabec@gmail.com \
--cc=jirislaby@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=linux-sunxi@lists.linux.dev \
--cc=robh@kernel.org \
--cc=samuel@sholland.org \
--cc=wens@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®