2015-04-09 20:05:45

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V4 0/5] Add big-endian MMIO support to serial8250

V3->V4:

Rebase on Linus' head of tree

Tweak documentation per Grant's request

Drop the of_earlycon patches in favor of Peter's series


Kevin Cernekee (5):
of: Add helper function to check MMIO register endianness
of/fdt: Add endianness helper function for early init code
of: Document {little,big,native}-endian bindings
serial: 8250: Add support for big-endian MMIO accesses
serial: of_serial: Support big-endian register accesses

.../devicetree/bindings/common-properties.txt | 60 ++++++++++++++++++++++
drivers/of/base.c | 23 +++++++++
drivers/of/fdt.c | 19 +++++++
drivers/tty/serial/8250/8250_core.c | 20 ++++++++
drivers/tty/serial/8250/8250_early.c | 5 ++
drivers/tty/serial/of_serial.c | 3 +-
include/linux/of.h | 6 +++
include/linux/of_fdt.h | 2 +
8 files changed, 137 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/common-properties.txt

--
2.2.2


2015-04-09 20:07:09

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V4 1/5] of: Add helper function to check MMIO register endianness

SoC peripherals can come in several different flavors:

- little-endian: registers always need to be accessed in LE mode (so the
kernel should perform a swap if the CPU is running BE)

- big-endian: registers always need to be accessed in BE mode (so the
kernel should perform a swap if the CPU is running LE)

- native-endian: the bus will automatically swap accesses, so the kernel
should never swap

Introduce a function that checks an OF device node to see whether it
contains a "big-endian" or "native-endian" property. For the former case,
always return true. For the latter case, return true iff the kernel was
built for BE (implying that the BE MMIO accessors do not perform a swap).
Otherwise return false, assuming LE registers.

LE registers are assumed by default because most existing drivers (libahci,
serial8250, usb) always use readl/writel in the absence of instructions
to the contrary, so that will be our fallback.

Signed-off-by: Kevin Cernekee <[email protected]>
---
drivers/of/base.c | 23 +++++++++++++++++++++++
include/linux/of.h | 6 ++++++
2 files changed, 29 insertions(+)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8f165b112e03..3a10d1ed37f8 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -568,6 +568,29 @@ bool of_device_is_available(const struct device_node *device)
EXPORT_SYMBOL(of_device_is_available);

/**
+ * of_device_is_big_endian - check if a device has BE registers
+ *
+ * @device: Node to check for endianness
+ *
+ * Returns true if the device has a "big-endian" property, or if the kernel
+ * was compiled for BE *and* the device has a "native-endian" property.
+ * Returns false otherwise.
+ *
+ * Callers would nominally use ioread32be/iowrite32be if
+ * of_device_is_big_endian() == true, or readl/writel otherwise.
+ */
+bool of_device_is_big_endian(const struct device_node *device)
+{
+ if (of_property_read_bool(device, "big-endian"))
+ return true;
+ if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
+ of_property_read_bool(device, "native-endian"))
+ return true;
+ return false;
+}
+EXPORT_SYMBOL(of_device_is_big_endian);
+
+/**
* of_get_parent - Get a node's parent if any
* @node: Node to get parent
*
diff --git a/include/linux/of.h b/include/linux/of.h
index dfde07e77a63..a0cd62ef22db 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -305,6 +305,7 @@ extern int of_property_read_string_helper(struct device_node *np,
extern int of_device_is_compatible(const struct device_node *device,
const char *);
extern bool of_device_is_available(const struct device_node *device);
+extern bool of_device_is_big_endian(const struct device_node *device);
extern const void *of_get_property(const struct device_node *node,
const char *name,
int *lenp);
@@ -466,6 +467,11 @@ static inline bool of_device_is_available(const struct device_node *device)
return false;
}

+static inline bool of_device_is_big_endian(const struct device_node *device)
+{
+ return false;
+}
+
static inline struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
--
2.2.2

2015-04-09 20:06:48

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V4 2/5] of/fdt: Add endianness helper function for early init code

Provide a libfdt-based equivalent for of_device_is_big_endian(), suitable
for use in the early_init_* functions.

Signed-off-by: Kevin Cernekee <[email protected]>
---
drivers/of/fdt.c | 19 +++++++++++++++++++
include/linux/of_fdt.h | 2 ++
2 files changed, 21 insertions(+)

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 3a896c9aeb74..1ebd6194fe7f 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -109,6 +109,25 @@ int of_fdt_is_compatible(const void *blob,
}

/**
+ * of_fdt_is_big_endian - Return true if given node needs BE MMIO accesses
+ * @blob: A device tree blob
+ * @node: node to test
+ *
+ * Returns true if the node has a "big-endian" property, or if the kernel
+ * was compiled for BE *and* the node has a "native-endian" property.
+ * Returns false otherwise.
+ */
+bool of_fdt_is_big_endian(const void *blob, unsigned long node)
+{
+ if (fdt_getprop(blob, node, "big-endian", NULL))
+ return true;
+ if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
+ fdt_getprop(blob, node, "native-endian", NULL))
+ return true;
+ return false;
+}
+
+/**
* of_fdt_match - Return true if node matches a list of compatible values
*/
int of_fdt_match(const void *blob, unsigned long node,
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 0ff360d5b3b3..587ee507965d 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -33,6 +33,8 @@ extern void *of_fdt_get_property(const void *blob,
extern int of_fdt_is_compatible(const void *blob,
unsigned long node,
const char *compat);
+extern bool of_fdt_is_big_endian(const void *blob,
+ unsigned long node);
extern int of_fdt_match(const void *blob, unsigned long node,
const char *const *compat);
extern void of_fdt_unflatten_tree(unsigned long *blob,
--
2.2.2

2015-04-09 20:06:30

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V4 3/5] of: Document {little,big,native}-endian bindings

These apply to newly converted drivers, like serial8250/libahci/...
The examples were adapted from the regmap bindings document.

Signed-off-by: Kevin Cernekee <[email protected]>
---
.../devicetree/bindings/common-properties.txt | 60 ++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 Documentation/devicetree/bindings/common-properties.txt

diff --git a/Documentation/devicetree/bindings/common-properties.txt b/Documentation/devicetree/bindings/common-properties.txt
new file mode 100644
index 000000000000..3193979b1d05
--- /dev/null
+++ b/Documentation/devicetree/bindings/common-properties.txt
@@ -0,0 +1,60 @@
+Common properties
+
+The ePAPR specification does not define any properties related to hardware
+byteswapping, but endianness issues show up frequently in porting Linux to
+different machine types. This document attempts to provide a consistent
+way of handling byteswapping across drivers.
+
+Optional properties:
+ - big-endian: Boolean; force big endian register accesses
+ unconditionally (e.g. ioread32be/iowrite32be). Use this if you
+ know the peripheral always needs to be accessed in BE mode.
+ - little-endian: Boolean; force little endian register accesses
+ unconditionally (e.g. readl/writel). Use this if you know the
+ peripheral always needs to be accessed in LE mode.
+ - native-endian: Boolean; always use register accesses matched to the
+ endianness of the kernel binary (e.g. LE vmlinux -> readl/writel,
+ BE vmlinux -> ioread32be/iowrite32be). In this case no byteswaps
+ will ever be performed. Use this if the hardware "self-adjusts"
+ register endianness based on the CPU's configured endianness.
+
+If a binding supports these properties, then the binding should also
+specify the default behavior if none of these properties are present.
+In such cases, little-endian is the preferred default, but it is not
+a requirement. The of_device_is_big_endian() and of_fdt_is_big_endian()
+helper functions do assume that little-endian is the default, because
+most existing (PCI-based) drivers implicitly default to LE by using
+readl/writel for MMIO accesses.
+
+Examples:
+Scenario 1 : CPU in LE mode & device in LE mode.
+dev: dev@40031000 {
+ compatible = "name";
+ reg = <0x40031000 0x1000>;
+ ...
+ native-endian;
+};
+
+Scenario 2 : CPU in LE mode & device in BE mode.
+dev: dev@40031000 {
+ compatible = "name";
+ reg = <0x40031000 0x1000>;
+ ...
+ big-endian;
+};
+
+Scenario 3 : CPU in BE mode & device in BE mode.
+dev: dev@40031000 {
+ compatible = "name";
+ reg = <0x40031000 0x1000>;
+ ...
+ native-endian;
+};
+
+Scenario 4 : CPU in BE mode & device in LE mode.
+dev: dev@40031000 {
+ compatible = "name";
+ reg = <0x40031000 0x1000>;
+ ...
+ little-endian;
+};
--
2.2.2

2015-04-09 20:05:50

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V4 4/5] serial: 8250: Add support for big-endian MMIO accesses

Add cases for UPIO_MEM32BE wherever there are currently cases handling
UPIO_MEM32.

Signed-off-by: Kevin Cernekee <[email protected]>
---
drivers/tty/serial/8250/8250_core.c | 20 ++++++++++++++++++++
drivers/tty/serial/8250/8250_early.c | 5 +++++
2 files changed, 25 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index deae122c9c4b..0bffa735eaa1 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -439,6 +439,18 @@ static unsigned int mem32_serial_in(struct uart_port *p, int offset)
return readl(p->membase + offset);
}

+static void mem32be_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = offset << p->regshift;
+ iowrite32be(value, p->membase + offset);
+}
+
+static unsigned int mem32be_serial_in(struct uart_port *p, int offset)
+{
+ offset = offset << p->regshift;
+ return ioread32be(p->membase + offset);
+}
+
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = offset << p->regshift;
@@ -477,6 +489,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem32_serial_out;
break;

+ case UPIO_MEM32BE:
+ p->serial_in = mem32be_serial_in;
+ p->serial_out = mem32be_serial_out;
+ break;
+
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
case UPIO_AU:
p->serial_in = au_serial_in;
@@ -502,6 +519,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
switch (p->iotype) {
case UPIO_MEM:
case UPIO_MEM32:
+ case UPIO_MEM32BE:
case UPIO_AU:
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
@@ -2743,6 +2761,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_AU:
case UPIO_TSI:
case UPIO_MEM32:
+ case UPIO_MEM32BE:
case UPIO_MEM:
if (!port->mapbase)
break;
@@ -2779,6 +2798,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_AU:
case UPIO_TSI:
case UPIO_MEM32:
+ case UPIO_MEM32BE:
case UPIO_MEM:
if (!port->mapbase)
break;
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index c31a22b4f845..84f6d11bbeed 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -45,6 +45,8 @@ unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offse
return readb(port->membase + offset);
case UPIO_MEM32:
return readl(port->membase + (offset << 2));
+ case UPIO_MEM32BE:
+ return ioread32be(port->membase + (offset << 2));
case UPIO_PORT:
return inb(port->iobase + offset);
default:
@@ -61,6 +63,9 @@ void __weak __init serial8250_early_out(struct uart_port *port, int offset, int
case UPIO_MEM32:
writel(value, port->membase + (offset << 2));
break;
+ case UPIO_MEM32BE:
+ iowrite32be(value, port->membase + (offset << 2));
+ break;
case UPIO_PORT:
outb(value, port->iobase + offset);
break;
--
2.2.2

2015-04-09 20:06:12

by Kevin Cernekee

[permalink] [raw]
Subject: [PATCH V4 5/5] serial: of_serial: Support big-endian register accesses

If the device node has a "big-endian" property and 32-bit registers, tell
the serial driver to use UPIO_MEM32BE instead of UPIO_MEM32.

Signed-off-by: Kevin Cernekee <[email protected]>
---
drivers/tty/serial/of_serial.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 33fb94f78967..e15c443b2a3c 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -115,7 +115,8 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->iotype = UPIO_MEM;
break;
case 4:
- port->iotype = UPIO_MEM32;
+ port->iotype = of_device_is_big_endian(np) ?
+ UPIO_MEM32BE : UPIO_MEM32;
break;
default:
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
--
2.2.2

2015-04-10 13:53:20

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH V4 0/5] Add big-endian MMIO support to serial8250

On Thu, Apr 9, 2015 at 3:05 PM, Kevin Cernekee <[email protected]> wrote:
> V3->V4:
>
> Rebase on Linus' head of tree
>
> Tweak documentation per Grant's request
>
> Drop the of_earlycon patches in favor of Peter's series

Are there conflicts with Peter's stuff? The series looks good to me.
So either I can take it with Greg's ack or Greg can take it.

Acked-by: Rob Herring <[email protected]>

Rob

>
>
> Kevin Cernekee (5):
> of: Add helper function to check MMIO register endianness
> of/fdt: Add endianness helper function for early init code
> of: Document {little,big,native}-endian bindings
> serial: 8250: Add support for big-endian MMIO accesses
> serial: of_serial: Support big-endian register accesses
>
> .../devicetree/bindings/common-properties.txt | 60 ++++++++++++++++++++++
> drivers/of/base.c | 23 +++++++++
> drivers/of/fdt.c | 19 +++++++
> drivers/tty/serial/8250/8250_core.c | 20 ++++++++
> drivers/tty/serial/8250/8250_early.c | 5 ++
> drivers/tty/serial/of_serial.c | 3 +-
> include/linux/of.h | 6 +++
> include/linux/of_fdt.h | 2 +
> 8 files changed, 137 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/devicetree/bindings/common-properties.txt
>
> --
> 2.2.2
>

2015-04-10 14:29:03

by Peter Hurley

[permalink] [raw]
Subject: Re: [PATCH V4 0/5] Add big-endian MMIO support to serial8250

On 04/10/2015 09:52 AM, Rob Herring wrote:
> On Thu, Apr 9, 2015 at 3:05 PM, Kevin Cernekee <[email protected]> wrote:
>> V3->V4:
>>
>> Rebase on Linus' head of tree
>>
>> Tweak documentation per Grant's request
>>
>> Drop the of_earlycon patches in favor of Peter's series
>
> Are there conflicts with Peter's stuff?

No.

It adds the required pieces so that a trivial patch on top of
both series will enable mmio32be for earlycon.

> The series looks good to me.

Same.

Reviewed-by: Peter Hurley <[email protected]>

2015-04-13 17:09:21

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH V4 0/5] Add big-endian MMIO support to serial8250

On Fri, Apr 10, 2015 at 10:28:55AM -0400, Peter Hurley wrote:
> On 04/10/2015 09:52 AM, Rob Herring wrote:
> > On Thu, Apr 9, 2015 at 3:05 PM, Kevin Cernekee <[email protected]> wrote:
> >> V3->V4:
> >>
> >> Rebase on Linus' head of tree
> >>
> >> Tweak documentation per Grant's request
> >>
> >> Drop the of_earlycon patches in favor of Peter's series
> >
> > Are there conflicts with Peter's stuff?
>
> No.
>
> It adds the required pieces so that a trivial patch on top of
> both series will enable mmio32be for earlycon.
>
> > The series looks good to me.
>
> Same.
>
> Reviewed-by: Peter Hurley <[email protected]>

Acked-by: Greg Kroah-Hartman <[email protected]>

2015-04-15 12:51:43

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH V4 0/5] Add big-endian MMIO support to serial8250

On Mon, Apr 13, 2015 at 12:09 PM, Greg Kroah-Hartman
<[email protected]> wrote:
> On Fri, Apr 10, 2015 at 10:28:55AM -0400, Peter Hurley wrote:
>> On 04/10/2015 09:52 AM, Rob Herring wrote:
>> > On Thu, Apr 9, 2015 at 3:05 PM, Kevin Cernekee <[email protected]> wrote:
>> >> V3->V4:
>> >>
>> >> Rebase on Linus' head of tree
>> >>
>> >> Tweak documentation per Grant's request
>> >>
>> >> Drop the of_earlycon patches in favor of Peter's series
>> >
>> > Are there conflicts with Peter's stuff?
>>
>> No.
>>
>> It adds the required pieces so that a trivial patch on top of
>> both series will enable mmio32be for earlycon.
>>
>> > The series looks good to me.
>>
>> Same.
>>
>> Reviewed-by: Peter Hurley <[email protected]>
>
> Acked-by: Greg Kroah-Hartman <[email protected]>

I've applied the series for 4.1. I took it since it got dropped last time.

Rob