From 5129ee22ce4aff7c5907d4c3d67d23f86cd6db9b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 26 Jul 2014 19:20:37 +0200 Subject: ARM: mvebu: armada xp: Generalize use of i2c quirk A second product has come to light which makes use of the A0 stepping of the Armada XP SoC. A0 stepping has a hardware bug in the i2c core meaning that hardware offload does not work, resulting in the kernel failing to boot. The quirk detects that the kernel is running on an A0 stepping SoC and disables the use of hardware offload. Currently the quirk is only enabled for PlatHome Openblocks AX3. The AX3 has been produced with both A0 and B0 stepping SoCs. The second product is the Lenovo Iomega IX4-300d. It seems likely that this device will also swap from A0 to B0 SoC sometime during its life. If there are two products using A0, it seems likely there are more products with A0. Also, since the number of A0 SoCs is limited, these products are also likely to transition to B0. Hence detecting at run time is the safest option. So enable the quirk for all Armada XP boards. Tested on an AX3 with A0 stepping. Signed-off-by: Andrew Lunn Acked-by: Gregory CLEMENT Acked-by: Thomas Petazzoni Cc: stable@vger.kernel.org # v3.12+ Fixes: 930ab3d403ae: ("i2c: mv64xxx: Add I2C Transaction Generator support") Link: https://lkml.kernel.org/r/1406395238-29758-2-git-send-email-andrew@lunn.ch Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 6478626e3ff6..d0d39f150fab 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -188,7 +188,7 @@ static void __init thermal_quirk(void) static void __init mvebu_dt_init(void) { - if (of_machine_is_compatible("plathome,openblocks-ax3-4")) + if (of_machine_is_compatible("marvell,armadaxp")) i2c_quirk(); if (of_machine_is_compatible("marvell,a375-db")) { external_abort_quirk(); -- cgit v1.2.3 From 9ece8839b1277fb9128ff6833411614ab6c88d68 Mon Sep 17 00:00:00 2001 From: Evgeniy Dushistov Date: Sat, 26 Jul 2014 19:56:59 +0400 Subject: ARM: orion: Fix for certain sequence of request_irq can cause irq storm The problem is that hardware handled by arm/plat-orion/gpio.c, require ack for edge irq, and no ack for level irq. The code handle this issue, by two "struct irq_chip_type" per one "struct irq_chip_generic". For one "struct irq_chip_generic" irq_ack pointer is setted, for another it is NULL. But we have only one mask_cache per two "struct irq_chip_type". So if we 1)unmask interrupt A for "edge type" trigger, 2)unmask interrupt B for "level type" trigger, 3)unmask interrupt C for "edge type", we, because of usage of generic irq_gc_mask_clr_bit/irq_gc_mask_set_bit, have hardware configured to trigger interrupt B on "edge type", because of shared mask_cache. But kernel think that B is "level type", so when interrupt B occur via "edge" reason, we don't ack it, and B triggered again and again. Signed-off-by: Evgeniy A. Dushistov Link: https://lkml.kernel.org/r/20140726155659.GA22977@fifteen Signed-off-by: Jason Cooper --- arch/arm/plat-orion/gpio.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index b61a3bcc2fa8..e048f6198d68 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -497,6 +497,34 @@ static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define orion_gpio_dbg_show NULL #endif +static void orion_gpio_unmask_irq(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + u32 reg_val; + u32 mask = d->mask; + + irq_gc_lock(gc); + reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask); + reg_val |= mask; + irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask); + irq_gc_unlock(gc); +} + +static void orion_gpio_mask_irq(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + u32 mask = d->mask; + u32 reg_val; + + irq_gc_lock(gc); + reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask); + reg_val &= ~mask; + irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask); + irq_gc_unlock(gc); +} + void __init orion_gpio_init(struct device_node *np, int gpio_base, int ngpio, void __iomem *base, int mask_offset, @@ -565,8 +593,8 @@ void __init orion_gpio_init(struct device_node *np, ct = gc->chip_types; ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_mask = orion_gpio_mask_irq; + ct->chip.irq_unmask = orion_gpio_unmask_irq; ct->chip.irq_set_type = gpio_irq_set_type; ct->chip.name = ochip->chip.label; @@ -575,8 +603,8 @@ void __init orion_gpio_init(struct device_node *np, ct->regs.ack = GPIO_EDGE_CAUSE_OFF; ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; ct->chip.irq_ack = irq_gc_ack_clr_bit; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_mask = orion_gpio_mask_irq; + ct->chip.irq_unmask = orion_gpio_unmask_irq; ct->chip.irq_set_type = gpio_irq_set_type; ct->handler = handle_edge_irq; ct->chip.name = ochip->chip.label; -- cgit v1.2.3