diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 177f78f6e6d6..c3f58db11083 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -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 index 000000000000..aa46eb280a7f --- /dev/null +++ b/drivers/irqchip/irq-gic-realview.c @@ -0,0 +1,43 @@ +/* + * Special GIC quirks for the ARM RealView + * Copyright (C) 2015 Linus Walleij + */ +#include +#include +#include +#include +#include +#include + +#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); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index abf2ffaed392..9736a1b9d7fd 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -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; diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index bae69e5d693c..d0a29db73bc7 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -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);