Skip to content

Commit

Permalink
Merge tag 'mvebu-fixes-3.13' of git://git.infradead.org/linux-mvebu i…
Browse files Browse the repository at this point in the history
…nto 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>
  • Loading branch information
Kevin Hilman committed Jan 14, 2014
2 parents 1588c51 + f8b94be commit d267aae
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 2 deletions.
6 changes: 5 additions & 1 deletion Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ Required properties :

- reg : Offset and length of the register set for the device
- compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c"
or "marvell,mv78230-i2c"
or "marvell,mv78230-i2c" or "marvell,mv78230-a0-i2c"
Note: Only use "marvell,mv78230-a0-i2c" for a very rare,
initial version of the SoC which had broken offload
support. Linux auto-detects this and sets it
appropriately.
- interrupts : The interrupt number

Optional properties :
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/mach-mvebu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \

AFLAGS_coherency_ll.o := -Wa,-march=armv7-a

obj-y += system-controller.o
obj-y += system-controller.o mvebu-soc-id.o
obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o
obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
Expand Down
32 changes: 32 additions & 0 deletions arch/arm/mach-mvebu/armada-370-xp.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
#include <linux/clocksource.h>
#include <linux/dma-mapping.h>
#include <linux/mbus.h>
#include <linux/slab.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include "armada-370-xp.h"
#include "common.h"
#include "coherency.h"
#include "mvebu-soc-id.h"

static void __init armada_370_xp_map_io(void)
{
Expand All @@ -45,8 +47,38 @@ static void __init armada_370_xp_timer_and_clk_init(void)
#endif
}

static void __init i2c_quirk(void)
{
struct device_node *np;
u32 dev, rev;

/*
* Only revisons more recent than A0 support the offload
* mechanism. We can exit only if we are sure that we can
* get the SoC revision and it is more recent than A0.
*/
if (mvebu_get_soc_id(&rev, &dev) == 0 && dev > MV78XX0_A0_REV)
return;

for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
struct property *new_compat;

new_compat = kzalloc(sizeof(*new_compat), GFP_KERNEL);

new_compat->name = kstrdup("compatible", GFP_KERNEL);
new_compat->length = sizeof("marvell,mv78230-a0-i2c");
new_compat->value = kstrdup("marvell,mv78230-a0-i2c",
GFP_KERNEL);

of_update_property(np, new_compat);
}
return;
}

static void __init armada_370_xp_dt_init(void)
{
if (of_machine_is_compatible("plathome,openblocks-ax3-4"))
i2c_quirk();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}

Expand Down
119 changes: 119 additions & 0 deletions arch/arm/mach-mvebu/mvebu-soc-id.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* ID and revision information for mvebu SoCs
*
* Copyright (C) 2014 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* All the mvebu SoCs have information related to their variant and
* revision that can be read from the PCI control register. This is
* done before the PCI initialization to avoid any conflict. Once the
* ID and revision are retrieved, the mapping is freed.
*/

#define pr_fmt(fmt) "mvebu-soc-id: " fmt

#include <linux/clk.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "mvebu-soc-id.h"

#define PCIE_DEV_ID_OFF 0x0
#define PCIE_DEV_REV_OFF 0x8

#define SOC_ID_MASK 0xFFFF0000
#define SOC_REV_MASK 0xFF

static u32 soc_dev_id;
static u32 soc_rev;
static bool is_id_valid;

static const struct of_device_id mvebu_pcie_of_match_table[] = {
{ .compatible = "marvell,armada-xp-pcie", },
{ .compatible = "marvell,armada-370-pcie", },
{},
};

int mvebu_get_soc_id(u32 *dev, u32 *rev)
{
if (is_id_valid) {
*dev = soc_dev_id;
*rev = soc_rev;
return 0;
} else
return -1;
}

static int __init mvebu_soc_id_init(void)
{
struct device_node *np;
int ret = 0;
void __iomem *pci_base;
struct clk *clk;
struct device_node *child;

np = of_find_matching_node(NULL, mvebu_pcie_of_match_table);
if (!np)
return ret;

/*
* ID and revision are available from any port, so we
* just pick the first one
*/
child = of_get_next_child(np, NULL);
if (child == NULL) {
pr_err("cannot get pci node\n");
ret = -ENOMEM;
goto clk_err;
}

clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(clk)) {
pr_err("cannot get clock\n");
ret = -ENOMEM;
goto clk_err;
}

ret = clk_prepare_enable(clk);
if (ret) {
pr_err("cannot enable clock\n");
goto clk_err;
}

pci_base = of_iomap(child, 0);
if (IS_ERR(pci_base)) {
pr_err("cannot map registers\n");
ret = -ENOMEM;
goto res_ioremap;
}

/* SoC ID */
soc_dev_id = readl(pci_base + PCIE_DEV_ID_OFF) >> 16;

/* SoC revision */
soc_rev = readl(pci_base + PCIE_DEV_REV_OFF) & SOC_REV_MASK;

is_id_valid = true;

pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev);

iounmap(pci_base);

res_ioremap:
clk_disable_unprepare(clk);

clk_err:
of_node_put(child);
of_node_put(np);

return ret;
}
core_initcall(mvebu_soc_id_init);

32 changes: 32 additions & 0 deletions arch/arm/mach-mvebu/mvebu-soc-id.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Marvell EBU SoC ID and revision definitions.
*
* Copyright (C) 2014 Marvell Semiconductor
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/

#ifndef __LINUX_MVEBU_SOC_ID_H
#define __LINUX_MVEBU_SOC_ID_H

/* Armada XP ID */
#define MV78230_DEV_ID 0x7823
#define MV78260_DEV_ID 0x7826
#define MV78460_DEV_ID 0x7846

/* Armada XP Revision */
#define MV78XX0_A0_REV 0x1
#define MV78XX0_B0_REV 0x2

#ifdef CONFIG_ARCH_MVEBU
int mvebu_get_soc_id(u32 *dev, u32 *rev);
#else
static inline int mvebu_get_soc_id(u32 *dev, u32 *rev)
{
return -1;
}
#endif

#endif /* __LINUX_MVEBU_SOC_ID_H */
5 changes: 5 additions & 0 deletions drivers/i2c/busses/i2c-mv64xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
{ .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
{ .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{ .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{ .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{}
};
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
Expand Down Expand Up @@ -783,6 +784,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
drv_data->errata_delay = true;
}

if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) {
drv_data->offload_enabled = false;
drv_data->errata_delay = true;
}
out:
return rc;
#endif
Expand Down

0 comments on commit d267aae

Please sign in to comment.