irqchip/gic: Support RealView variant setup
authorLinus Walleij <linus.walleij@linaro.org>
Fri, 23 Oct 2015 22:15:52 +0000 (00:15 +0200)
committerMarc Zyngier <marc.zyngier@arm.com>
Wed, 16 Dec 2015 15:30:50 +0000 (15:30 +0000)
The ARM RealView PB11MPCore reference design has some special
bits in a system controller register to set up the GIC in one
of three modes: legacy, new with DCC, new without DCC. The
register is also used to enable FIQ.

Since the platform will not boot unless this register is set
up to "new with DCC" mode, we need a special quirk to be
compiled-in for the RealView platforms.

If we find the right compatible string on the GIC TestChip,
we enable this quirk by looking up the system controller and
enabling the special bits.

We depend on the CONFIG_REALVIEW_DT Kconfig symbol as the old
boardfile code has the same fix hardcoded, and this is only
needed for the attempts to modernize the RealView code using
device tree.

After fixing this, the PB11MPCore boots with device tree
only.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
drivers/irqchip/Makefile
drivers/irqchip/irq-gic-realview.c [new file with mode: 0644]
drivers/irqchip/irq-gic.c
include/linux/irqchip/arm-gic.h

index 177f78f6e6d6313fd9fd16595fe36089296ce25f..c3f58db1108327c503f71497d1cec7d6be7a1e4c 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_ARCH_SUNXI)              += irq-sun4i.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)            += spear-shirq.o
 obj-$(CONFIG_ARM_GIC)                  += irq-gic.o irq-gic-common.o
+obj-$(CONFIG_REALVIEW_DT)              += irq-gic-realview.o
 obj-$(CONFIG_ARM_GIC_V2M)              += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)               += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)           += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
diff --git a/drivers/irqchip/irq-gic-realview.c b/drivers/irqchip/irq-gic-realview.c
new file mode 100644 (file)
index 0000000..aa46eb2
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Special GIC quirks for the ARM RealView
+ * Copyright (C) 2015 Linus Walleij
+ */
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/bitops.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+
+#define REALVIEW_SYS_LOCK_OFFSET       0x20
+#define REALVIEW_PB11MP_SYS_PLD_CTRL1  0x74
+#define VERSATILE_LOCK_VAL             0xA05F
+#define PLD_INTMODE_MASK               BIT(22)|BIT(23)|BIT(24)
+#define PLD_INTMODE_LEGACY             0x0
+#define PLD_INTMODE_NEW_DCC            BIT(22)
+#define PLD_INTMODE_NEW_NO_DCC         BIT(23)
+#define PLD_INTMODE_FIQ_ENABLE         BIT(24)
+
+static int __init
+realview_gic_of_init(struct device_node *node, struct device_node *parent)
+{
+       static struct regmap *map;
+
+       /* The PB11MPCore GIC needs to be configured in the syscon */
+       map = syscon_regmap_lookup_by_compatible("arm,realview-pb11mp-syscon");
+       if (!IS_ERR(map)) {
+               /* new irq mode with no DCC */
+               regmap_write(map, REALVIEW_SYS_LOCK_OFFSET,
+                            VERSATILE_LOCK_VAL);
+               regmap_update_bits(map, REALVIEW_PB11MP_SYS_PLD_CTRL1,
+                                  PLD_INTMODE_NEW_NO_DCC,
+                                  PLD_INTMODE_MASK);
+               regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, 0x0000);
+               pr_info("TC11MP GIC: set up interrupt controller to NEW mode, no DCC\n");
+       } else {
+               pr_err("TC11MP GIC setup: could not find syscon\n");
+               return -ENXIO;
+       }
+       return gic_of_init(node, parent);
+}
+IRQCHIP_DECLARE(armtc11mp_gic, "arm,tc11mp-gic", realview_gic_of_init);
index abf2ffaed392270c97d14c7fdc2ab247e63a58e1..9736a1b9d7fd742affd067dccd3a4c9cc07eaf4a 100644 (file)
@@ -1196,7 +1196,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
        return true;
 }
 
-static int __init
+int __init
 gic_of_init(struct device_node *node, struct device_node *parent)
 {
        void __iomem *cpu_base;
index bae69e5d693c3e60cea1a209fc06d2d33fdfb960..d0a29db73bc7103bde82d47a05b393f291435afb 100644 (file)
@@ -103,6 +103,16 @@ struct device_node;
 void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
 int gic_cpu_if_down(unsigned int gic_nr);
 
+/*
+ * Subdrivers that need some preparatory work can initialize their
+ * chips and call this to register their GICs.
+ */
+int gic_of_init(struct device_node *node, struct device_node *parent);
+
+/*
+ * Legacy platforms not converted to DT yet must use this to init
+ * their GIC
+ */
 void gic_init(unsigned int nr, int start,
              void __iomem *dist , void __iomem *cpu);