aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Hilman <khilman@linaro.org>2014-01-14 13:55:48 -0500
committerKevin Hilman <khilman@linaro.org>2014-01-14 13:56:01 -0500
commitd267aae2f30ec7739adce351f6d20cd7f4eb6448 (patch)
tree6911378e02841a3eb58f21d5c8344d46ba3ee73d
parent1588c51cf6d782e63a8719681d905ef0ac22ee62 (diff)
parentf8b94beb7e6a374cb0de531b72377c49857b35ca (diff)
Merge tag 'mvebu-fixes-3.13' of git://git.infradead.org/linux-mvebu into next/fixes-non-critical
From Jason Cooper: mvebu late fixes for v3.13 - mvebu - fix boot hang on Armada XP due to broken i2c offloading in A0 SoC revision (specifically experienced on some early OpenBlocks AX3-4 boards) * tag 'mvebu-fixes-3.13' of git://git.infradead.org/linux-mvebu: i2c: mv64xxx: Document the newly introduced Armada XP A0 compatible i2c: mv64xxx: Fix bus hang on A0 version of the Armada XP SoCs ARM: mvebu: Add quirk for i2c for the OpenBlocks AX3-4 board ARM: mvebu: Add support to get the ID and the revision of a SoC Signed-off-by: Kevin Hilman <khilman@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt6
-rw-r--r--arch/arm/mach-mvebu/Makefile2
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.c32
-rw-r--r--arch/arm/mach-mvebu/mvebu-soc-id.c119
-rw-r--r--arch/arm/mach-mvebu/mvebu-soc-id.h32
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c5
6 files changed, 194 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
index 82e8f6f17179..582b4652a82a 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
@@ -5,7 +5,11 @@ Required properties :
5 5
6 - reg : Offset and length of the register set for the device 6 - reg : Offset and length of the register set for the device
7 - compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c" 7 - compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c"
8 or "marvell,mv78230-i2c" 8 or "marvell,mv78230-i2c" or "marvell,mv78230-a0-i2c"
9 Note: Only use "marvell,mv78230-a0-i2c" for a very rare,
10 initial version of the SoC which had broken offload
11 support. Linux auto-detects this and sets it
12 appropriately.
9 - interrupts : The interrupt number 13 - interrupts : The interrupt number
10 14
11Optional properties : 15Optional properties :
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 2d04f0e21870..878aebe98dcc 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -3,7 +3,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
3 3
4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a 4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a
5 5
6obj-y += system-controller.o 6obj-y += system-controller.o mvebu-soc-id.o
7obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o 7obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o
8obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o 8obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o
9obj-$(CONFIG_SMP) += platsmp.o headsmp.o 9obj-$(CONFIG_SMP) += platsmp.o headsmp.o
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index e2acff98e750..f6c9d1d85c14 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -21,6 +21,7 @@
21#include <linux/clocksource.h> 21#include <linux/clocksource.h>
22#include <linux/dma-mapping.h> 22#include <linux/dma-mapping.h>
23#include <linux/mbus.h> 23#include <linux/mbus.h>
24#include <linux/slab.h>
24#include <asm/hardware/cache-l2x0.h> 25#include <asm/hardware/cache-l2x0.h>
25#include <asm/mach/arch.h> 26#include <asm/mach/arch.h>
26#include <asm/mach/map.h> 27#include <asm/mach/map.h>
@@ -28,6 +29,7 @@
28#include "armada-370-xp.h" 29#include "armada-370-xp.h"
29#include "common.h" 30#include "common.h"
30#include "coherency.h" 31#include "coherency.h"
32#include "mvebu-soc-id.h"
31 33
32static void __init armada_370_xp_map_io(void) 34static void __init armada_370_xp_map_io(void)
33{ 35{
@@ -45,8 +47,38 @@ static void __init armada_370_xp_timer_and_clk_init(void)
45#endif 47#endif
46} 48}
47 49
50static void __init i2c_quirk(void)
51{
52 struct device_node *np;
53 u32 dev, rev;
54
55 /*
56 * Only revisons more recent than A0 support the offload
57 * mechanism. We can exit only if we are sure that we can
58 * get the SoC revision and it is more recent than A0.
59 */
60 if (mvebu_get_soc_id(&rev, &dev) == 0 && dev > MV78XX0_A0_REV)
61 return;
62
63 for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
64 struct property *new_compat;
65
66 new_compat = kzalloc(sizeof(*new_compat), GFP_KERNEL);
67
68 new_compat->name = kstrdup("compatible", GFP_KERNEL);
69 new_compat->length = sizeof("marvell,mv78230-a0-i2c");
70 new_compat->value = kstrdup("marvell,mv78230-a0-i2c",
71 GFP_KERNEL);
72
73 of_update_property(np, new_compat);
74 }
75 return;
76}
77
48static void __init armada_370_xp_dt_init(void) 78static void __init armada_370_xp_dt_init(void)
49{ 79{
80 if (of_machine_is_compatible("plathome,openblocks-ax3-4"))
81 i2c_quirk();
50 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 82 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
51} 83}
52 84
diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c
new file mode 100644
index 000000000000..fe4fc1cbdfaf
--- /dev/null
+++ b/arch/arm/mach-mvebu/mvebu-soc-id.c
@@ -0,0 +1,119 @@
1/*
2 * ID and revision information for mvebu SoCs
3 *
4 * Copyright (C) 2014 Marvell
5 *
6 * Gregory CLEMENT <gregory.clement@free-electrons.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 *
12 * All the mvebu SoCs have information related to their variant and
13 * revision that can be read from the PCI control register. This is
14 * done before the PCI initialization to avoid any conflict. Once the
15 * ID and revision are retrieved, the mapping is freed.
16 */
17
18#define pr_fmt(fmt) "mvebu-soc-id: " fmt
19
20#include <linux/clk.h>
21#include <linux/init.h>
22#include <linux/io.h>
23#include <linux/kernel.h>
24#include <linux/of.h>
25#include <linux/of_address.h>
26#include "mvebu-soc-id.h"
27
28#define PCIE_DEV_ID_OFF 0x0
29#define PCIE_DEV_REV_OFF 0x8
30
31#define SOC_ID_MASK 0xFFFF0000
32#define SOC_REV_MASK 0xFF
33
34static u32 soc_dev_id;
35static u32 soc_rev;
36static bool is_id_valid;
37
38static const struct of_device_id mvebu_pcie_of_match_table[] = {
39 { .compatible = "marvell,armada-xp-pcie", },
40 { .compatible = "marvell,armada-370-pcie", },
41 {},
42};
43
44int mvebu_get_soc_id(u32 *dev, u32 *rev)
45{
46 if (is_id_valid) {
47 *dev = soc_dev_id;
48 *rev = soc_rev;
49 return 0;
50 } else
51 return -1;
52}
53
54static int __init mvebu_soc_id_init(void)
55{
56 struct device_node *np;
57 int ret = 0;
58 void __iomem *pci_base;
59 struct clk *clk;
60 struct device_node *child;
61
62 np = of_find_matching_node(NULL, mvebu_pcie_of_match_table);
63 if (!np)
64 return ret;
65
66 /*
67 * ID and revision are available from any port, so we
68 * just pick the first one
69 */
70 child = of_get_next_child(np, NULL);
71 if (child == NULL) {
72 pr_err("cannot get pci node\n");
73 ret = -ENOMEM;
74 goto clk_err;
75 }
76
77 clk = of_clk_get_by_name(child, NULL);
78 if (IS_ERR(clk)) {
79 pr_err("cannot get clock\n");
80 ret = -ENOMEM;
81 goto clk_err;
82 }
83
84 ret = clk_prepare_enable(clk);
85 if (ret) {
86 pr_err("cannot enable clock\n");
87 goto clk_err;
88 }
89
90 pci_base = of_iomap(child, 0);
91 if (IS_ERR(pci_base)) {
92 pr_err("cannot map registers\n");
93 ret = -ENOMEM;
94 goto res_ioremap;
95 }
96
97 /* SoC ID */
98 soc_dev_id = readl(pci_base + PCIE_DEV_ID_OFF) >> 16;
99
100 /* SoC revision */
101 soc_rev = readl(pci_base + PCIE_DEV_REV_OFF) & SOC_REV_MASK;
102
103 is_id_valid = true;
104
105 pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev);
106
107 iounmap(pci_base);
108
109res_ioremap:
110 clk_disable_unprepare(clk);
111
112clk_err:
113 of_node_put(child);
114 of_node_put(np);
115
116 return ret;
117}
118core_initcall(mvebu_soc_id_init);
119
diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.h b/arch/arm/mach-mvebu/mvebu-soc-id.h
new file mode 100644
index 000000000000..31654252fe35
--- /dev/null
+++ b/arch/arm/mach-mvebu/mvebu-soc-id.h
@@ -0,0 +1,32 @@
1/*
2 * Marvell EBU SoC ID and revision definitions.
3 *
4 * Copyright (C) 2014 Marvell Semiconductor
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11#ifndef __LINUX_MVEBU_SOC_ID_H
12#define __LINUX_MVEBU_SOC_ID_H
13
14/* Armada XP ID */
15#define MV78230_DEV_ID 0x7823
16#define MV78260_DEV_ID 0x7826
17#define MV78460_DEV_ID 0x7846
18
19/* Armada XP Revision */
20#define MV78XX0_A0_REV 0x1
21#define MV78XX0_B0_REV 0x2
22
23#ifdef CONFIG_ARCH_MVEBU
24int mvebu_get_soc_id(u32 *dev, u32 *rev);
25#else
26static inline int mvebu_get_soc_id(u32 *dev, u32 *rev)
27{
28 return -1;
29}
30#endif
31
32#endif /* __LINUX_MVEBU_SOC_ID_H */
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 8be7e42aa4de..b8c5187b9ee0 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -692,6 +692,7 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
692 { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i}, 692 { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
693 { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, 693 { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
694 { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, 694 { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
695 { .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
695 {} 696 {}
696}; 697};
697MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); 698MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
@@ -783,6 +784,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
783 drv_data->errata_delay = true; 784 drv_data->errata_delay = true;
784 } 785 }
785 786
787 if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) {
788 drv_data->offload_enabled = false;
789 drv_data->errata_delay = true;
790 }
786out: 791out:
787 return rc; 792 return rc;
788#endif 793#endif