diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-24 08:46:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-24 08:46:18 -0700 |
commit | d56a669ca59c37ed0a7282a251b2f2f22533343a (patch) | |
tree | cef7bd4699754057474cc96430864f690f1786e0 | |
parent | 836ee4874e201a5907f9658fb2bf3527dd952d30 (diff) | |
parent | 04fca0e390e80d88c2f959aef86e0bb7f26fea01 (diff) | |
download | linux-d56a669ca59c37ed0a7282a251b2f2f22533343a.tar.bz2 |
Merge tag 'devicetree-for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull second batch of devicetree updates from Rob Herring:
"As Grant mentioned in the first devicetree pull request, here is the
2nd batch of DT changes for 4.1. The main remaining item here is the
endianness bindings and related 8250 driver support.
- DT endianness specification bindings
- big-endian 8250 serial support
- DT overlay unittest updates
- various DT doc updates
- compile fixes for OF_IRQ=n"
* tag 'devicetree-for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux:
frv: add io{read,write}{16,32}be functions
mn10300: add io{read,write}{16,32}be functions
Documentation: DT bindings: add doc for Altera's SoCFPGA platform
of: base: improve of_get_next_child() kernel-doc
Doc: dt: arch_timer: discourage clock-frequency use
of: unittest: overlay: Keep track of created overlays
of/fdt: fix allocation size for device node path
serial: of_serial: Support big-endian register accesses
serial: 8250: Add support for big-endian MMIO accesses
of: Document {little,big,native}-endian bindings
of/fdt: Add endianness helper function for early init code
of: Add helper function to check MMIO register endianness
of/fdt: Remove "reg" data prints from early_init_dt_scan_memory
of: add vendor prefix for Artesyn
of: Add dummy of_irq_to_resource_table() for IRQ_OF=n
of: OF_IRQ should depend on IRQ_DOMAIN
-rw-r--r-- | Documentation/devicetree/bindings/arm/altera.txt | 14 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/arm/arch_timer.txt | 8 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/common-properties.txt | 60 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/vendor-prefixes.txt | 1 | ||||
-rw-r--r-- | arch/frv/include/asm/io.h | 5 | ||||
-rw-r--r-- | arch/mn10300/include/asm/io.h | 5 | ||||
-rw-r--r-- | drivers/of/Kconfig | 2 | ||||
-rw-r--r-- | drivers/of/base.c | 28 | ||||
-rw-r--r-- | drivers/of/fdt.c | 24 | ||||
-rw-r--r-- | drivers/of/unittest.c | 62 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_core.c | 20 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_early.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/of_serial.c | 3 | ||||
-rw-r--r-- | include/linux/of.h | 6 | ||||
-rw-r--r-- | include/linux/of_fdt.h | 2 | ||||
-rw-r--r-- | include/linux/of_irq.h | 9 |
16 files changed, 243 insertions, 11 deletions
diff --git a/Documentation/devicetree/bindings/arm/altera.txt b/Documentation/devicetree/bindings/arm/altera.txt new file mode 100644 index 000000000000..558735aacca8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/altera.txt @@ -0,0 +1,14 @@ +Altera's SoCFPGA platform device tree bindings +--------------------------------------------- + +Boards with Cyclone 5 SoC: +Required root node properties: +compatible = "altr,socfpga-cyclone5", "altr,socfpga"; + +Boards with Arria 5 SoC: +Required root node properties: +compatible = "altr,socfpga-arria5", "altr,socfpga"; + +Boards with Arria 10 SoC: +Required root node properties: +compatible = "altr,socfpga-arria10", "altr,socfpga"; diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt index 256b4d8bab7b..e774128935d5 100644 --- a/Documentation/devicetree/bindings/arm/arch_timer.txt +++ b/Documentation/devicetree/bindings/arm/arch_timer.txt @@ -17,7 +17,10 @@ to deliver its interrupts via SPIs. - interrupts : Interrupt list for secure, non-secure, virtual and hypervisor timers, in that order. -- clock-frequency : The frequency of the main counter, in Hz. Optional. +- clock-frequency : The frequency of the main counter, in Hz. Should be present + only where necessary to work around broken firmware which does not configure + CNTFRQ on all CPUs to a uniform correct value. Use of this property is + strongly discouraged; fix your firmware unless absolutely impossible. - always-on : a boolean property. If present, the timer is powered through an always-on power domain, therefore it never loses context. @@ -46,7 +49,8 @@ Example: - compatible : Should at least contain "arm,armv7-timer-mem". -- clock-frequency : The frequency of the main counter, in Hz. Optional. +- clock-frequency : The frequency of the main counter, in Hz. Should be present + only when firmware has not configured the MMIO CNTFRQ registers. - reg : The control frame base address. 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; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 83737a3403d7..80339192c93e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -26,6 +26,7 @@ aptina Aptina Imaging arasan Arasan Chip Systems arm ARM Ltd. armadeus ARMadeus Systems SARL +artesyn Artesyn Embedded Technologies Inc. asahi-kasei Asahi Kasei Corp. atmel Atmel Corporation auo AU Optronics Corporation diff --git a/arch/frv/include/asm/io.h b/arch/frv/include/asm/io.h index 99bb7efaf9b7..0b78bc89e840 100644 --- a/arch/frv/include/asm/io.h +++ b/arch/frv/include/asm/io.h @@ -342,6 +342,11 @@ static inline void iowrite32(u32 val, void __iomem *p) __flush_PCI_writes(); } +#define ioread16be(addr) be16_to_cpu(ioread16(addr)) +#define ioread32be(addr) be32_to_cpu(ioread32(addr)) +#define iowrite16be(v, addr) iowrite16(cpu_to_be16(v), (addr)) +#define iowrite32be(v, addr) iowrite32(cpu_to_be32(v), (addr)) + static inline void ioread8_rep(void __iomem *p, void *dst, unsigned long count) { io_insb((unsigned long) p, dst, count); diff --git a/arch/mn10300/include/asm/io.h b/arch/mn10300/include/asm/io.h index 897ba3c12b32..cc4a2ba9e228 100644 --- a/arch/mn10300/include/asm/io.h +++ b/arch/mn10300/include/asm/io.h @@ -197,6 +197,11 @@ static inline void outsl(unsigned long addr, const void *buffer, int count) #define iowrite16(v, addr) writew((v), (addr)) #define iowrite32(v, addr) writel((v), (addr)) +#define ioread16be(addr) be16_to_cpu(readw(addr)) +#define ioread32be(addr) be32_to_cpu(readl(addr)) +#define iowrite16be(v, addr) writew(cpu_to_be16(v), (addr)) +#define iowrite32be(v, addr) writel(cpu_to_be32(v), (addr)) + #define ioread8_rep(p, dst, count) \ insb((unsigned long) (p), (dst), (count)) #define ioread16_rep(p, dst, count) \ diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 1470b5227834..07bb3c8f191b 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -50,7 +50,7 @@ config OF_ADDRESS_PCI config OF_IRQ def_bool y - depends on !SPARC + depends on !SPARC && IRQ_DOMAIN config OF_NET depends on NETDEVICES diff --git a/drivers/of/base.c b/drivers/of/base.c index a1aa0c7dee50..99764db0875a 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 * @@ -640,8 +663,9 @@ static struct device_node *__of_get_next_child(const struct device_node *node, * @node: parent node * @prev: previous child of the parent node, or NULL to get first * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. + * Returns a node pointer with refcount incremented, use of_node_put() on + * it when done. Returns NULL when prev is the last child. Decrements the + * refcount of prev. */ struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 3a896c9aeb74..cde35c5d0191 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, @@ -172,7 +191,7 @@ static void * unflatten_dt_node(void *blob, if (!pathp) return mem; - allocl = l++; + allocl = ++l; /* version 0x10 has a more compact unit name here instead of the full * path. we accumulate the full path size using "fpsize", we'll rebuild @@ -879,8 +898,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, endp = reg + (l / sizeof(__be32)); - pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n", - uname, l, reg[0], reg[1], reg[2], reg[3]); + pr_debug("memory scan node %s, reg size %d,\n", uname, l); while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { u64 base, size; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index e844907c9efa..18016341d5a9 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -23,6 +23,8 @@ #include <linux/i2c.h> #include <linux/i2c-mux.h> +#include <linux/bitops.h> + #include "of_private.h" static struct unittest_results { @@ -1109,6 +1111,59 @@ static const char *overlay_path(int nr) static const char *bus_path = "/testcase-data/overlay-node/test-bus"; +/* it is guaranteed that overlay ids are assigned in sequence */ +#define MAX_UNITTEST_OVERLAYS 256 +static unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_UNITTEST_OVERLAYS)]; +static int overlay_first_id = -1; + +static void of_unittest_track_overlay(int id) +{ + if (overlay_first_id < 0) + overlay_first_id = id; + id -= overlay_first_id; + + /* we shouldn't need that many */ + BUG_ON(id >= MAX_UNITTEST_OVERLAYS); + overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id); +} + +static void of_unittest_untrack_overlay(int id) +{ + if (overlay_first_id < 0) + return; + id -= overlay_first_id; + BUG_ON(id >= MAX_UNITTEST_OVERLAYS); + overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id); +} + +static void of_unittest_destroy_tracked_overlays(void) +{ + int id, ret, defers; + + if (overlay_first_id < 0) + return; + + /* try until no defers */ + do { + defers = 0; + /* remove in reverse order */ + for (id = MAX_UNITTEST_OVERLAYS - 1; id >= 0; id--) { + if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id))) + continue; + + ret = of_overlay_destroy(id + overlay_first_id); + if (ret != 0) { + defers++; + pr_warn("%s: overlay destroy failed for #%d\n", + __func__, id + overlay_first_id); + continue; + } + + overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id); + } + } while (defers > 0); +} + static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr, int *overlay_id) { @@ -1130,6 +1185,7 @@ static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr, goto out; } id = ret; + of_unittest_track_overlay(id); ret = 0; @@ -1343,6 +1399,7 @@ static void of_unittest_overlay_6(void) return; } ov_id[i] = ret; + of_unittest_track_overlay(ov_id[i]); } for (i = 0; i < 2; i++) { @@ -1367,6 +1424,7 @@ static void of_unittest_overlay_6(void) PDEV_OVERLAY)); return; } + of_unittest_untrack_overlay(ov_id[i]); } for (i = 0; i < 2; i++) { @@ -1411,6 +1469,7 @@ static void of_unittest_overlay_8(void) return; } ov_id[i] = ret; + of_unittest_track_overlay(ov_id[i]); } /* now try to remove first overlay (it should fail) */ @@ -1433,6 +1492,7 @@ static void of_unittest_overlay_8(void) PDEV_OVERLAY)); return; } + of_unittest_untrack_overlay(ov_id[i]); } unittest(1, "overlay test %d passed\n", 8); @@ -1855,6 +1915,8 @@ static void __init of_unittest_overlay(void) of_unittest_overlay_i2c_cleanup(); #endif + of_unittest_destroy_tracked_overlays(); + out: of_node_put(bus_np); } diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 422ebea96a64..4506e405c8f3 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -450,6 +450,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; @@ -488,6 +500,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; @@ -513,6 +530,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 */ @@ -2748,6 +2766,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; @@ -2784,6 +2803,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 8e119682266a..6c0fd8b9d1c3 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -42,6 +42,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: @@ -58,6 +60,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; diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index aa00154c4a6d..5b73afb9f9f3 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -116,7 +116,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", diff --git a/include/linux/of.h b/include/linux/of.h index 5f124f685e07..ddeaae6d2083 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); @@ -467,6 +468,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) 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, diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index bfec136a6d1e..d884929a7747 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -37,8 +37,6 @@ extern int of_irq_parse_one(struct device_node *device, int index, extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data); extern int of_irq_to_resource(struct device_node *dev, int index, struct resource *r); -extern int of_irq_to_resource_table(struct device_node *dev, - struct resource *res, int nr_irqs); extern void of_irq_init(const struct of_device_id *matches); @@ -46,6 +44,8 @@ extern void of_irq_init(const struct of_device_id *matches); extern int of_irq_count(struct device_node *dev); extern int of_irq_get(struct device_node *dev, int index); extern int of_irq_get_byname(struct device_node *dev, const char *name); +extern int of_irq_to_resource_table(struct device_node *dev, + struct resource *res, int nr_irqs); #else static inline int of_irq_count(struct device_node *dev) { @@ -59,6 +59,11 @@ static inline int of_irq_get_byname(struct device_node *dev, const char *name) { return 0; } +static inline int of_irq_to_resource_table(struct device_node *dev, + struct resource *res, int nr_irqs) +{ + return 0; +} #endif #if defined(CONFIG_OF) |