[PATCH v2] serial: 8250: handle ixp4xx register endianness correctly

Linus Walleij <[email protected]>
Newsgroups gmane.linux.serial
Message-ID <[email protected]>
From: Arnd Bergmann <[email protected]>

Unlike modern SoCs that just work in both big-endian and little-endian
mode using the readl()/writel() or readb()/writeb() accessors, the
internal registers on ixp4xx behave like native-endian 32-bit registers
in both modes, which requires adjusting the register address
when using 8-bit access.

The existing dts files are written for big-endian kernels and 8-bit
access, which does not work with little-endian kernels.

Add a quirk that makes the 8250 OF driver:

1. Mask off any hardcoded offset.
2. Add the += 3 offset if and only if we are running on big endian.

This should work in all combinations of big-endian and little-endian
kernels with either variant of the DTS file.

Signed-off-by: Arnd Bergmann <[email protected]>
[[email protected]: Modified to just play with the offset]
Signed-off-by: Linus Walleij <[email protected]>
---
Changes in v2:
- Use PTR_ALIGN_DOWN(*,4) instead of the custom &= 3, which also
  works with a pointer which is an unsigned char *
- Fix to the earlycon code to do the same thing as the main
  serial port.
- Link to v1: https://patch.msgid.link/[email protected]
---
 drivers/tty/serial/8250/8250_early.c | 19 ++++++++++++++++++-
 drivers/tty/serial/8250/8250_of.c    | 12 ++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index dc0371857ecb..44ec209f37c4 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -23,6 +23,7 @@
  *	console=uart8250,mmio32,0xff5e0000,115200n8
  */
 
+#include <linux/align.h>
 #include <linux/tty.h>
 #include <linux/init.h>
 #include <linux/console.h>
@@ -177,6 +178,23 @@ OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
 OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
 OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
 
+static int __init early_serial8250_xscale_setup(struct earlycon_device *device,
+					     const char *options)
+{
+	/*
+	 * Adjust for BE32 register accesses: drop any hardcoded
+	 * address for the big endian byte target, add it explicitly
+	 * if running on BE32.
+	 */
+	device->port.membase = PTR_ALIGN_DOWN(device->port.membase, 4);
+	if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE32))
+		device->port.membase += 3;
+	device->port.regshift = 2;
+
+	return early_serial8250_setup(device, options);
+}
+OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_xscale_setup);
+
 static int __init early_serial8250_rs2_setup(struct earlycon_device *device,
 					     const char *options)
 {
@@ -184,7 +202,6 @@ static int __init early_serial8250_rs2_setup(struct earlycon_device *device,
 
 	return early_serial8250_setup(device, options);
 }
-OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup);
 OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup);
 OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup);
 
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 81644d40b09a..f0537fb6ef4f 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -5,6 +5,7 @@
  *    Copyright (C) 2006 Arnd Bergmann <[email protected]>, IBM Corp.
  */
 
+#include <linux/align.h>
 #include <linux/bits.h>
 #include <linux/console.h>
 #include <linux/math.h>
@@ -122,6 +123,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
 	if (ret)
 		goto err_pmruntime;
 
+	if (IS_ENABLED(CONFIG_CPU_XSCALE) && type == PORT_XSCALE) {
+		/*
+		 * Adjust for BE32 register accesses: drop any hardcoded
+		 * address for the big endian byte target, add it explicitly
+		 * if running on BE32.
+		 */
+		port->mapbase = PTR_ALIGN_DOWN(port->mapbase, 4);
+		if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE32))
+			port->mapbase += 3;
+	}
+
 	/* Get clk rate through clk driver if present */
 	if (!port->uartclk) {
 		struct clk *bus_clk;

---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260709-ixp4xx-serial-hackfix-c5cd90dcca93

Best regards,
--  
Linus Walleij <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.