irqchip updates for 4.16
- Fix a GICv3 issue when parsing ACPI entries for disabled CPUs - Driver for the MIPS Goldfish virtual platform - Small fixlet for the ompic driver - Interrupt polatiry support for the Raspberry Pi irqchip -----BEGIN PGP SIGNATURE----- iQJJBAABCAAzFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAlpWYKkVHG1hcmMuenlu Z2llckBhcm0uY29tAAoJECPQ0LrRPXpDJ+MQAKIoE5YA5AydC64kAyQyuKcPb5S4 N/9R/9DoPDbYLc9SY+1I5ygHGzorq7zx/PWJmamNMjknwk0xhfuBaS5smE/m6H+1 dCmgTM3fknEMd5HfLIwpAp/L1Pmq9KYqMtxounSabduWnVMnIqc+7OGAj5fZE7B1 IPTh8xQQ4HPGR3MBYa/754OIBe8Uprb2KGrZugU2Pz8WPAd9NDdKxM84jCwQ9r58 4TFesdC4iC1J83Qr1JmxiBdGOnfhi3cq7wfmRLnTmBeRlhXqYHuzRxPQmjbKtcWk yzFj3OhSLB2KoV7x4nXaaIcKrwETJCj+GThlK8/ZRZ7lu0irBnmBNomFm4RwwRV4 MkqItMqvNAwd+enq0LMAxBScUt/3EEYUJxV6xA6RBfluKPlZMlcyfGi+pS72fNho 0SiKSzokaiTt/XLBfT1s0NI1ASkdPD5Xqo7yAzxDN4O8SzLY71bkFLrQB3ErL/gr 50FYOsRv24e9a6NrSmtw/7z1Os6mY6QEB6lcSi7A0/+MmudU6Kk0mTk5fRf92+rl vqcB7bkkZrMSSsFPJkrBqoPZ+O9R6yqZudt29+n2G9BNWMea/oOCWnz6oYZh0HvX DdE3YQUQBJj2ZGc0CG8XlWY94sJLsS8n99rLxXDkAJ7aQU0uT4g8hbxJG0nDXJfu d7J2FO7LTtaW4JKo =QFqN -----END PGP SIGNATURE----- Merge tag 'irqchip-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core Pull irqchip updates for 4.16 from Marc Zyngier - Fix a GICv3 issue when parsing ACPI entries for disabled CPUs - Driver for the MIPS Goldfish virtual platform - Small fixlet for the ompic driver - Interrupt polarity support for the Raspberry Pi irqchip
This commit is contained in:
commit
80023aea83
|
@ -12,7 +12,7 @@ Required properties:
|
|||
registers
|
||||
- interrupt-controller: Identifies the node as an interrupt controller
|
||||
- #interrupt-cells: Specifies the number of cells needed to encode an
|
||||
interrupt source. The value shall be 1
|
||||
interrupt source. The value shall be 2
|
||||
|
||||
Please refer to interrupts.txt in this directory for details of the common
|
||||
Interrupt Controllers bindings used by client devices.
|
||||
|
@ -32,6 +32,6 @@ local_intc: local_intc {
|
|||
compatible = "brcm,bcm2836-l1-intc";
|
||||
reg = <0x40000000 0x100>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
Android Goldfish PIC
|
||||
|
||||
Android Goldfish programmable interrupt device used by Android
|
||||
emulator.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should contain "google,goldfish-pic"
|
||||
- reg : <registers mapping>
|
||||
- interrupts : <interrupt mapping>
|
||||
|
||||
Example for mips when used in cascade mode:
|
||||
|
||||
cpuintc {
|
||||
#interrupt-cells = <0x1>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
compatible = "mti,cpu-interrupt-controller";
|
||||
};
|
||||
|
||||
interrupt-controller@1f000000 {
|
||||
compatible = "google,goldfish-pic";
|
||||
reg = <0x1f000000 0x1000>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <0x1>;
|
||||
|
||||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <0x2>;
|
||||
};
|
|
@ -867,6 +867,12 @@ S: Supported
|
|||
F: drivers/android/
|
||||
F: drivers/staging/android/
|
||||
|
||||
ANDROID GOLDFISH PIC DRIVER
|
||||
M: Miodrag Dinic <miodrag.dinic@mips.com>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt
|
||||
F: drivers/irqchip/irq-goldfish-pic.c
|
||||
|
||||
ANDROID GOLDFISH RTC DRIVER
|
||||
M: Miodrag Dinic <miodrag.dinic@mips.com>
|
||||
S: Supported
|
||||
|
|
|
@ -13,24 +13,24 @@
|
|||
compatible = "brcm,bcm2836-l1-intc";
|
||||
reg = <0x40000000 0x100>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
};
|
||||
|
||||
arm-pmu {
|
||||
compatible = "arm,cortex-a7-pmu";
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <9>;
|
||||
interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
timer {
|
||||
compatible = "arm,armv7-timer";
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <0>, // PHYS_SECURE_PPI
|
||||
<1>, // PHYS_NONSECURE_PPI
|
||||
<3>, // VIRT_PPI
|
||||
<2>; // HYP_PPI
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI
|
||||
<1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI
|
||||
<3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI
|
||||
<2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI
|
||||
always-on;
|
||||
};
|
||||
|
||||
|
@ -76,7 +76,7 @@
|
|||
compatible = "brcm,bcm2836-armctrl-ic";
|
||||
reg = <0x7e00b200 0x200>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <8>;
|
||||
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
&cpu_thermal {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
compatible = "brcm,bcm2836-l1-intc";
|
||||
reg = <0x40000000 0x100>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
};
|
||||
};
|
||||
|
@ -20,10 +20,10 @@
|
|||
timer {
|
||||
compatible = "arm,armv7-timer";
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <0>, // PHYS_SECURE_PPI
|
||||
<1>, // PHYS_NONSECURE_PPI
|
||||
<3>, // VIRT_PPI
|
||||
<2>; // HYP_PPI
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI
|
||||
<1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI
|
||||
<3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI
|
||||
<2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI
|
||||
always-on;
|
||||
};
|
||||
|
||||
|
@ -73,7 +73,7 @@
|
|||
compatible = "brcm,bcm2836-armctrl-ic";
|
||||
reg = <0x7e00b200 0x200>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <8>;
|
||||
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
&cpu_thermal {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <dt-bindings/clock/bcm2835.h>
|
||||
#include <dt-bindings/clock/bcm2835-aux.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
/* firmware-provided startup stubs live here, where the secondary CPUs are
|
||||
* spinning.
|
||||
|
|
|
@ -343,4 +343,12 @@ config MESON_IRQ_GPIO
|
|||
help
|
||||
Support Meson SoC Family GPIO Interrupt Multiplexer
|
||||
|
||||
config GOLDFISH_PIC
|
||||
bool "Goldfish programmable interrupt controller"
|
||||
depends on MIPS && (GOLDFISH || COMPILE_TEST)
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
Say yes here to enable Goldfish interrupt controller driver used
|
||||
for Goldfish based virtual platforms.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -84,3 +84,4 @@ obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
|
|||
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
|
||||
obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o
|
||||
obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o
|
||||
obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
|
||||
|
|
|
@ -98,13 +98,35 @@ static struct irq_chip bcm2836_arm_irqchip_gpu = {
|
|||
.irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq,
|
||||
};
|
||||
|
||||
static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip)
|
||||
static int bcm2836_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
int irq = irq_create_mapping(intc.domain, hwirq);
|
||||
struct irq_chip *chip;
|
||||
|
||||
switch (hw) {
|
||||
case LOCAL_IRQ_CNTPSIRQ:
|
||||
case LOCAL_IRQ_CNTPNSIRQ:
|
||||
case LOCAL_IRQ_CNTHPIRQ:
|
||||
case LOCAL_IRQ_CNTVIRQ:
|
||||
chip = &bcm2836_arm_irqchip_timer;
|
||||
break;
|
||||
case LOCAL_IRQ_GPU_FAST:
|
||||
chip = &bcm2836_arm_irqchip_gpu;
|
||||
break;
|
||||
case LOCAL_IRQ_PMU_FAST:
|
||||
chip = &bcm2836_arm_irqchip_pmu;
|
||||
break;
|
||||
default:
|
||||
pr_warn_once("Unexpected hw irq: %lu\n", hw);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq_set_percpu_devid(irq);
|
||||
irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq);
|
||||
irq_domain_set_info(d, irq, hw, chip, d->host_data,
|
||||
handle_percpu_devid_irq, NULL, NULL);
|
||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -165,7 +187,8 @@ static int bcm2836_cpu_dying(unsigned int cpu)
|
|||
#endif
|
||||
|
||||
static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
|
||||
.xlate = irq_domain_xlate_onecell
|
||||
.xlate = irq_domain_xlate_onetwocell,
|
||||
.map = bcm2836_map,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -218,19 +241,6 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
|
|||
if (!intc.domain)
|
||||
panic("%pOF: unable to create IRQ domain\n", node);
|
||||
|
||||
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPSIRQ,
|
||||
&bcm2836_arm_irqchip_timer);
|
||||
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPNSIRQ,
|
||||
&bcm2836_arm_irqchip_timer);
|
||||
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTHPIRQ,
|
||||
&bcm2836_arm_irqchip_timer);
|
||||
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTVIRQ,
|
||||
&bcm2836_arm_irqchip_timer);
|
||||
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_GPU_FAST,
|
||||
&bcm2836_arm_irqchip_gpu);
|
||||
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_PMU_FAST,
|
||||
&bcm2836_arm_irqchip_pmu);
|
||||
|
||||
bcm2836_arm_irqchip_smp_init();
|
||||
|
||||
set_handle_irq(bcm2836_arm_irqchip_handle_irq);
|
||||
|
|
|
@ -1331,6 +1331,10 @@ gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
|
|||
u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
|
||||
void __iomem *redist_base;
|
||||
|
||||
/* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */
|
||||
if (!(gicc->flags & ACPI_MADT_ENABLED))
|
||||
return 0;
|
||||
|
||||
redist_base = ioremap(gicc->gicr_base_address, size);
|
||||
if (!redist_base)
|
||||
return -ENOMEM;
|
||||
|
@ -1380,6 +1384,13 @@ static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header,
|
|||
if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* It's perfectly valid firmware can pass disabled GICC entry, driver
|
||||
* should not treat as errors, skip the entry instead of probe fail.
|
||||
*/
|
||||
if (!(gicc->flags & ACPI_MADT_ENABLED))
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Driver for MIPS Goldfish Programmable Interrupt Controller.
|
||||
*
|
||||
* Author: Miodrag Dinic <miodrag.dinic@mips.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#define GFPIC_NR_IRQS 32
|
||||
|
||||
/* 8..39 Cascaded Goldfish PIC interrupts */
|
||||
#define GFPIC_IRQ_BASE 8
|
||||
|
||||
#define GFPIC_REG_IRQ_PENDING 0x04
|
||||
#define GFPIC_REG_IRQ_DISABLE_ALL 0x08
|
||||
#define GFPIC_REG_IRQ_DISABLE 0x0c
|
||||
#define GFPIC_REG_IRQ_ENABLE 0x10
|
||||
|
||||
struct goldfish_pic_data {
|
||||
void __iomem *base;
|
||||
struct irq_domain *irq_domain;
|
||||
};
|
||||
|
||||
static void goldfish_pic_cascade(struct irq_desc *desc)
|
||||
{
|
||||
struct goldfish_pic_data *gfpic = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *host_chip = irq_desc_get_chip(desc);
|
||||
u32 pending, hwirq, virq;
|
||||
|
||||
chained_irq_enter(host_chip, desc);
|
||||
|
||||
pending = readl(gfpic->base + GFPIC_REG_IRQ_PENDING);
|
||||
while (pending) {
|
||||
hwirq = __fls(pending);
|
||||
virq = irq_linear_revmap(gfpic->irq_domain, hwirq);
|
||||
generic_handle_irq(virq);
|
||||
pending &= ~(1 << hwirq);
|
||||
}
|
||||
|
||||
chained_irq_exit(host_chip, desc);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops goldfish_irq_domain_ops = {
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
static int __init goldfish_pic_of_init(struct device_node *of_node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct goldfish_pic_data *gfpic;
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
unsigned int parent_irq;
|
||||
int ret = 0;
|
||||
|
||||
gfpic = kzalloc(sizeof(*gfpic), GFP_KERNEL);
|
||||
if (!gfpic) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
parent_irq = irq_of_parse_and_map(of_node, 0);
|
||||
if (!parent_irq) {
|
||||
pr_err("Failed to map parent IRQ!\n");
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
gfpic->base = of_iomap(of_node, 0);
|
||||
if (!gfpic->base) {
|
||||
pr_err("Failed to map base address!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_unmap_irq;
|
||||
}
|
||||
|
||||
/* Mask interrupts. */
|
||||
writel(1, gfpic->base + GFPIC_REG_IRQ_DISABLE_ALL);
|
||||
|
||||
gc = irq_alloc_generic_chip("GFPIC", 1, GFPIC_IRQ_BASE, gfpic->base,
|
||||
handle_level_irq);
|
||||
if (!gc) {
|
||||
pr_err("Failed to allocate chip structures!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_iounmap;
|
||||
}
|
||||
|
||||
ct = gc->chip_types;
|
||||
ct->regs.enable = GFPIC_REG_IRQ_ENABLE;
|
||||
ct->regs.disable = GFPIC_REG_IRQ_DISABLE;
|
||||
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
|
||||
ct->chip.irq_mask = irq_gc_mask_disable_reg;
|
||||
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS), 0,
|
||||
IRQ_NOPROBE | IRQ_LEVEL, 0);
|
||||
|
||||
gfpic->irq_domain = irq_domain_add_legacy(of_node, GFPIC_NR_IRQS,
|
||||
GFPIC_IRQ_BASE, 0,
|
||||
&goldfish_irq_domain_ops,
|
||||
NULL);
|
||||
if (!gfpic->irq_domain) {
|
||||
pr_err("Failed to add irqdomain!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_destroy_generic_chip;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(parent_irq,
|
||||
goldfish_pic_cascade, gfpic);
|
||||
|
||||
pr_info("Successfully registered.\n");
|
||||
return 0;
|
||||
|
||||
out_destroy_generic_chip:
|
||||
irq_destroy_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS),
|
||||
IRQ_NOPROBE | IRQ_LEVEL, 0);
|
||||
out_iounmap:
|
||||
iounmap(gfpic->base);
|
||||
out_unmap_irq:
|
||||
irq_dispose_mapping(parent_irq);
|
||||
out_free:
|
||||
kfree(gfpic);
|
||||
out_err:
|
||||
pr_err("Failed to initialize! (errno = %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(google_gf_pic, "google,goldfish-pic", goldfish_pic_of_init);
|
|
@ -171,9 +171,9 @@ static int __init ompic_of_init(struct device_node *node,
|
|||
|
||||
/* Setup the device */
|
||||
ompic_base = ioremap(res.start, resource_size(&res));
|
||||
if (IS_ERR(ompic_base)) {
|
||||
if (!ompic_base) {
|
||||
pr_err("ompic: unable to map registers");
|
||||
return PTR_ERR(ompic_base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
|
|
Loading…
Reference in New Issue