Commit a572ba63 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull core irq updates from Thomas Gleixner:
 "Updates from the irq departement:

   - Update the interrupt spreading code so it handles numa node with
     different CPU counts properly.

   - A large overhaul of the ARM GiCv3 driver to support new PPI and SPI
     ranges.

   - Conversion of all alloc_fwnode() users to use physical addresses
     instead of virtual addresses so the virtual addresses are not
     leaked. The physical address is sufficient to identify the
     associated interrupt chip.

   - Add support for Marvel MMP3, Amlogic Meson SM1 interrupt chips.

   - Enforce interrupt threading at compile time if RT is enabled.

   - Small updates and improvements all over the place"

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (37 commits)
  irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices
  irqchip/uniphier-aidet: Use devm_platform_ioremap_resource()
  irqdom...
parents 258b16ec 9cc5b7fb
...@@ -115,6 +115,8 @@ stable kernels. ...@@ -115,6 +115,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip0{6,7} | #161010701 | N/A | | Hisilicon | Hip0{6,7} | #161010701 | N/A |
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip0{6,7} | #161010803 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 | | Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 |
+----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+
| Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A | | Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A |
......
...@@ -16,6 +16,7 @@ Required properties: ...@@ -16,6 +16,7 @@ Required properties:
"amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912) "amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912)
"amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X) "amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X)
"amlogic,meson-g12a-gpio-intc" for G12A SoCs (S905D2, S905X2, S905Y2) "amlogic,meson-g12a-gpio-intc" for G12A SoCs (S905D2, S905X2, S905Y2)
"amlogic,meson-sm1-gpio-intc" for SM1 SoCs (S905D3, S905X3, S905Y3)
- reg : Specifies base physical address and size of the registers. - reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller. - interrupt-controller : Identifies the node as an interrupt controller.
- #interrupt-cells : Specifies the number of cells needed to encode an - #interrupt-cells : Specifies the number of cells needed to encode an
......
...@@ -44,11 +44,13 @@ properties: ...@@ -44,11 +44,13 @@ properties:
be at least 4. be at least 4.
The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
interrupts. Other values are reserved for future use. interrupts, 2 for interrupts in the Extended SPI range, 3 for the
Extended PPI range. Other values are reserved for future use.
The 2nd cell contains the interrupt number for the interrupt type. The 2nd cell contains the interrupt number for the interrupt type.
SPI interrupts are in the range [0-987]. PPI interrupts are in the SPI interrupts are in the range [0-987]. PPI interrupts are in the
range [0-15]. range [0-15]. Extented SPI interrupts are in the range [0-1023].
Extended PPI interrupts are in the range [0-127].
The 3rd cell is the flags, encoded as follows: The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags. bits[3:0] trigger type and level flags.
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000) #define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000)
#define ICU_REG(x) (ICU_VIRT_BASE + (x)) #define ICU_REG(x) (ICU_VIRT_BASE + (x))
#define ICU2_VIRT_BASE (AXI_VIRT_BASE + 0x84000)
#define ICU2_REG(x) (ICU2_VIRT_BASE + (x))
#define ICU_INT_CONF(n) ICU_REG((n) << 2) #define ICU_INT_CONF(n) ICU_REG((n) << 2)
#define ICU_INT_CONF_MASK (0xf) #define ICU_INT_CONF_MASK (0xf)
......
...@@ -41,6 +41,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, ...@@ -41,6 +41,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data) void *data)
{ {
for (; quirks->desc; quirks++) { for (; quirks->desc; quirks++) {
if (quirks->compatible)
continue;
if (quirks->iidr != (quirks->mask & iidr)) if (quirks->iidr != (quirks->mask & iidr))
continue; continue;
if (quirks->init(data)) if (quirks->init(data))
...@@ -63,7 +65,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, ...@@ -63,7 +65,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
* for "irq", depending on "type". * for "irq", depending on "type".
*/ */
raw_spin_lock_irqsave(&irq_controller_lock, flags); raw_spin_lock_irqsave(&irq_controller_lock, flags);
val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); val = oldval = readl_relaxed(base + confoff);
if (type & IRQ_TYPE_LEVEL_MASK) if (type & IRQ_TYPE_LEVEL_MASK)
val &= ~confmask; val &= ~confmask;
else if (type & IRQ_TYPE_EDGE_BOTH) else if (type & IRQ_TYPE_EDGE_BOTH)
...@@ -83,14 +85,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, ...@@ -83,14 +85,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
* does not allow us to set the configuration or we are in a * does not allow us to set the configuration or we are in a
* non-secure mode, and hence it may not be catastrophic. * non-secure mode, and hence it may not be catastrophic.
*/ */
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); writel_relaxed(val, base + confoff);
if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val) { if (readl_relaxed(base + confoff) != val)
if (WARN_ON(irq >= 32)) ret = -EINVAL;
ret = -EINVAL;
else
pr_warn("GIC: PPI%d is secure or misconfigured\n",
irq - 16);
}
raw_spin_unlock_irqrestore(&irq_controller_lock, flags); raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
if (sync_access) if (sync_access)
...@@ -132,26 +130,31 @@ void gic_dist_config(void __iomem *base, int gic_irqs, ...@@ -132,26 +130,31 @@ void gic_dist_config(void __iomem *base, int gic_irqs,
sync_access(); sync_access();
} }
void gic_cpu_config(void __iomem *base, void (*sync_access)(void)) void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void))
{ {
int i; int i;
/* /*
* Deal with the banked PPI and SGI interrupts - disable all * Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled. * private interrupts. Make sure everything is deactivated.
* Make sure everything is deactivated.
*/ */
writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR); for (i = 0; i < nr; i += 32) {
writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR); writel_relaxed(GICD_INT_EN_CLR_X32,
writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); base + GIC_DIST_ACTIVE_CLEAR + i / 8);
writel_relaxed(GICD_INT_EN_CLR_X32,
base + GIC_DIST_ENABLE_CLEAR + i / 8);
}
/* /*
* Set priority on PPI and SGI interrupts * Set priority on PPI and SGI interrupts
*/ */
for (i = 0; i < 32; i += 4) for (i = 0; i < nr; i += 4)
writel_relaxed(GICD_INT_DEF_PRI_X4, writel_relaxed(GICD_INT_DEF_PRI_X4,
base + GIC_DIST_PRI + i * 4 / 4); base + GIC_DIST_PRI + i * 4 / 4);
/* Ensure all SGI interrupts are now enabled */
writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
if (sync_access) if (sync_access)
sync_access(); sync_access();
} }
...@@ -22,7 +22,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, ...@@ -22,7 +22,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void)); void __iomem *base, void (*sync_access)(void));
void gic_dist_config(void __iomem *base, int gic_irqs, void gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void)); void (*sync_access)(void));
void gic_cpu_config(void __iomem *base, void (*sync_access)(void)); void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void));
void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data); void *data);
void gic_enable_of_quirks(const struct device_node *np, void gic_enable_of_quirks(const struct device_node *np,
......
...@@ -525,7 +525,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, ...@@ -525,7 +525,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
spi_start, nr_spis); spi_start, nr_spis);
} }
fwnode = irq_domain_alloc_fwnode((void *)m->base_address); fwnode = irq_domain_alloc_fwnode(&res.start);
if (!fwnode) { if (!fwnode) {
pr_err("Unable to allocate GICv2m domain token\n"); pr_err("Unable to allocate GICv2m domain token\n");
return -EINVAL; return -EINVAL;
......
...@@ -2464,6 +2464,7 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number ...@@ -2464,6 +2464,7 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number
{ {
int idx; int idx;
/* Find a free LPI region in lpi_map and allocate them. */
idx = bitmap_find_free_region(dev->event_map.lpi_map, idx = bitmap_find_free_region(dev->event_map.lpi_map,
dev->event_map.nr_lpis, dev->event_map.nr_lpis,
get_count_order(nvecs)); get_count_order(nvecs));
...@@ -2471,7 +2472,6 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number ...@@ -2471,7 +2472,6 @@ static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number
return -ENOSPC; return -ENOSPC;
*hwirq = dev->event_map.lpi_base + idx; *hwirq = dev->event_map.lpi_base + idx;
set_bit(idx, dev->event_map.lpi_map);
return 0; return 0;
} }
...@@ -2641,14 +2641,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, ...@@ -2641,14 +2641,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
struct its_node *its = its_dev->its; struct its_node *its = its_dev->its;
int i; int i;
bitmap_release_region(its_dev->event_map.lpi_map,
its_get_event_id(irq_domain_get_irq_data(domain, virq)),
get_count_order(nr_irqs));
for (i = 0; i < nr_irqs; i++) { for (i = 0; i < nr_irqs; i++) {
struct irq_data *data = irq_domain_get_irq_data(domain, struct irq_data *data = irq_domain_get_irq_data(domain,
virq + i); virq + i);
u32 event = its_get_event_id(data);
/* Mark interrupt index as unused */
clear_bit(event, its_dev->event_map.lpi_map);
/* Nuke the entry in the domain */ /* Nuke the entry in the domain */
irq_domain_reset_irq_data(data); irq_domain_reset_irq_data(data);
} }
...@@ -3921,7 +3920,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, ...@@ -3921,7 +3920,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1; res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1;
res.flags = IORESOURCE_MEM; res.flags = IORESOURCE_MEM;
dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address); dom_handle = irq_domain_alloc_fwnode(&res.start);
if (!dom_handle) { if (!dom_handle) {
pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n", pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n",
&res.start); &res.start);
......
This diff is collapsed.
...@@ -291,6 +291,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -291,6 +291,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
{ {
void __iomem *base = gic_dist_base(d); void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d); unsigned int gicirq = gic_irq(d);
int ret;
/* Interrupt configuration for SGIs can't be changed */ /* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16) if (gicirq < 16)
...@@ -301,7 +302,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -301,7 +302,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
type != IRQ_TYPE_EDGE_RISING) type != IRQ_TYPE_EDGE_RISING)
return -EINVAL; return -EINVAL;
return gic_configure_irq(gicirq, type, base, NULL); ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL);
if (ret && gicirq < 32) {
/* Misconfigured PPIs are usually not fatal */
pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16);
ret = 0;
}
return ret;
} }
static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
...@@ -535,7 +543,7 @@ static int gic_cpu_init(struct gic_chip_data *gic) ...@@ -535,7 +543,7 @@ static int gic_cpu_init(struct gic_chip_data *gic)
gic_cpu_map[i] &= ~cpu_mask; gic_cpu_map[i] &= ~cpu_mask;
} }
gic_cpu_config(dist_base, NULL); gic_cpu_config(dist_base, 32, NULL);
writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
gic_cpu_if_up(gic); gic_cpu_if_up(gic);
...@@ -1627,7 +1635,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, ...@@ -1627,7 +1635,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
/* /*
* Initialize GIC instance zero (no multi-GIC support). * Initialize GIC instance zero (no multi-GIC support).
*/ */
domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base); domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
if (!domain_handle) { if (!domain_handle) {
pr_err("Unable to allocate domain handle\n"); pr_err("Unable to allocate domain handle\n");
gic_teardown(gic); gic_teardown(gic);
......
...@@ -130,7 +130,12 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -130,7 +130,12 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
raw_spin_lock(&irq_controller_lock); raw_spin_lock(&irq_controller_lock);
ret = gic_configure_irq(irq, type, base, NULL); ret = gic_configure_irq(irq, type, base + GIC_DIST_CONFIG, NULL);
if (ret && irq < 32) {
/* Misconfigured PPIs are usually not fatal */
pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16);
ret = 0;
}
raw_spin_unlock(&irq_controller_lock); raw_spin_unlock(&irq_controller_lock);
...@@ -268,7 +273,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc) ...@@ -268,7 +273,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
if (i != cpu) if (i != cpu)
hip04_cpu_map[i] &= ~cpu_mask; hip04_cpu_map[i] &= ~cpu_mask;
gic_cpu_config(dist_base, NULL); gic_cpu_config(dist_base, 32, NULL);
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
writel_relaxed(1, base + GIC_CPU_CTRL); writel_relaxed(1, base + GIC_CPU_CTRL);
......
...@@ -362,10 +362,8 @@ static int pdc_intc_probe(struct platform_device *pdev) ...@@ -362,10 +362,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
} }
for (i = 0; i < priv->nr_perips; ++i) { for (i = 0; i < priv->nr_perips; ++i) {
irq = platform_get_irq(pdev, 1 + i); irq = platform_get_irq(pdev, 1 + i);
if (irq < 0) { if (irq < 0)
dev_err(&pdev->dev, "cannot find perip IRQ #%u\n", i);
return irq; return irq;
}
priv->perip_irqs[i] = irq; priv->perip_irqs[i] = irq;
} }
/* check if too many were provided */ /* check if too many were provided */
...@@ -376,10 +374,8 @@ static int pdc_intc_probe(struct platform_device *pdev) ...@@ -376,10 +374,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
/* Get syswake IRQ number */ /* Get syswake IRQ number */
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0)
dev_err(&pdev->dev, "cannot find syswake IRQ\n");
return irq; return irq;
}
priv->syswake_irq = irq; priv->syswake_irq = irq;
/* Set up an IRQ domain */ /* Set up an IRQ domain */
......
...@@ -319,7 +319,7 @@ void __init ixp4xx_irq_init(resource_size_t irqbase, ...@@ -319,7 +319,7 @@ void __init ixp4xx_irq_init(resource_size_t irqbase,
pr_crit("IXP4XX: could not ioremap interrupt controller\n"); pr_crit("IXP4XX: could not ioremap interrupt controller\n");
return; return;
} }
fwnode = irq_domain_alloc_fwnode(base); fwnode = irq_domain_alloc_fwnode(&irqbase);
if (!fwnode) { if (!fwnode) {
pr_crit("IXP4XX: no domain handle\n"); pr_crit("IXP4XX: no domain handle\n");
return; return;
......
...@@ -164,10 +164,8 @@ static int keystone_irq_probe(struct platform_device *pdev) ...@@ -164,10 +164,8 @@ static int keystone_irq_probe(struct platform_device *pdev)
} }
kirq->irq = platform_get_irq(pdev, 0); kirq->irq = platform_get_irq(pdev, 0);
if (kirq->irq < 0) { if (kirq->irq < 0)
dev_err(dev, "no irq resource %d\n", kirq->irq);
return kirq->irq; return kirq->irq;
}
kirq->dev = dev; kirq->dev = dev;
kirq->mask = ~0x0; kirq->mask = ~0x0;
......
...@@ -24,14 +24,25 @@ ...@@ -24,14 +24,25 @@
#define REG_PIN_47_SEL 0x08 #define REG_PIN_47_SEL 0x08
#define REG_FILTER_SEL 0x0c #define REG_FILTER_SEL 0x0c
#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x))) /*
* Note: The S905X3 datasheet reports that BOTH_EDGE is controlled by
* bits 24 to 31. Tests on the actual HW show that these bits are
* stuck at 0. Bits 8 to 15 are responsive and have the expected
* effect.
*/
#define REG_EDGE_POL_EDGE(x) BIT(x) #define REG_EDGE_POL_EDGE(x) BIT(x)
#define REG_EDGE_POL_LOW(x) BIT(16 + (x)) #define REG_EDGE_POL_LOW(x) BIT(16 + (x))
#define REG_BOTH_EDGE(x) BIT(8 + (x))
#define REG_EDGE_POL_MASK(x) ( \
REG_EDGE_POL_EDGE(x) | \
REG_EDGE_POL_LOW(x) | \
REG_BOTH_EDGE(x))
#define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8) #define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8)
#define REG_FILTER_SEL_SHIFT(x) ((x) * 4) #define REG_FILTER_SEL_SHIFT(x) ((x) * 4)
struct meson_gpio_irq_params { struct meson_gpio_irq_params {
unsigned int nr_hwirq; unsigned int nr_hwirq;
bool support_edge_both;
}; };
static const struct meson_gpio_irq_params meson8_params = { static const struct meson_gpio_irq_params meson8_params = {
...@@ -54,6 +65,11 @@ static const struct meson_gpio_irq_params axg_params = { ...@@ -54,6 +65,11 @@ static const struct meson_gpio_irq_params axg_params = {
.nr_hwirq = 100, .nr_hwirq = 100,
}; };
static const struct meson_gpio_irq_params sm1_params = {
.nr_hwirq = 100,
.support_edge_both = true,
};
static const struct of_device_id meson_irq_gpio_matches[] = { static const struct of_device_id meson_irq_gpio_matches[] = {
{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params }, { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
...@@ -61,11 +77,12 @@ static const struct of_device_id meson_irq_gpio_matches[] = { ...@@ -61,11 +77,12 @@ static const struct of_device_id meson_irq_gpio_matches[] = {
{ .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
{ .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
{ .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params }, { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
{ .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
{ } { }
}; };
struct meson_gpio_irq_controller { struct meson_gpio_irq_controller {
unsigned int nr_hwirq; const struct meson_gpio_irq_params *params;
void __iomem *base; void __iomem *base;
u32 channel_irqs[NUM_CHANNEL]; u32 channel_irqs[NUM_CHANNEL];
DECLARE_BITMAP(channel_map, NUM_CHANNEL); DECLARE_BITMAP(channel_map, NUM_CHANNEL);
...@@ -168,14 +185,22 @@ static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl, ...@@ -168,14 +185,22 @@ static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl,
*/ */
type &= IRQ_TYPE_SENSE_MASK; type &= IRQ_TYPE_SENSE_MASK;
if (type == IRQ_TYPE_EDGE_BOTH) /*
return -EINVAL; * New controller support EDGE_BOTH trigger. This setting takes
* precedence over the other edge/polarity settings
*/
if (type == IRQ_TYPE_EDGE_BOTH) {
if (!ctl->params->support_edge_both)
return -EINVAL;
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) val |= REG_BOTH_EDGE(idx);
val |= REG_EDGE_POL_EDGE(idx); } else {
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
val |= REG_EDGE_POL_EDGE(idx);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
val |= REG_EDGE_POL_LOW(idx); val |= REG_EDGE_POL_LOW(idx);
}
spin_lock(&ctl->lock); spin_lock(&ctl->lock);
...@@ -199,7 +224,7 @@ static unsigned int meson_gpio_irq_type_output(unsigned int type) ...@@ -199,7 +224,7 @@ static unsigned int meson_gpio_irq_type_output(unsigned int type)
*/ */
if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
type |= IRQ_TYPE_LEVEL_HIGH; type |= IRQ_TYPE_LEVEL_HIGH;
else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) else
type |= IRQ_TYPE_EDGE_RISING; type |= IRQ_TYPE_EDGE_RISING;
return type; return type;
...@@ -328,15 +353,13 @@ static int __init meson_gpio_irq_parse_dt(struct device_node *node, ...@@ -328,15 +353,13 @@ static int __init meson_gpio_irq_parse_dt(struct device_node *node,
struct meson_gpio_irq_controller *ctl) struct meson_gpio_irq_controller *ctl)
{ {
const struct of_device_id *match; const struct of_device_id *match;
const struct meson_gpio_irq_params *params;
int ret; int ret;
match = of_match_node(meson_irq_gpio_matches, node); match = of_match_node(meson_irq_gpio_matches, node);
if (!match) if (!match)
return -ENODEV; return -ENODEV;
params = match->data; ctl->params = match->data;
ctl->nr_hwirq = params->nr_hwirq;
ret = of_property_read_variable_u32_array(node, ret = of_property_read_variable_u32_array(node,
"amlogic,channel-interrupts", "amlogic,channel-interrupts",
...@@ -385,7 +408,8 @@ static int __init meson_gpio_irq_of_init(struct device_node *node, ...@@ -385,7 +408,8 @@ static int __init meson_gpio_irq_of_init(struct device_node *node,
if (ret) if (ret)
goto free_channel_irqs; goto free_channel_irqs;
domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq, domain = irq_domain_create_hierarchy(parent_domain, 0,
ctl->params->nr_hwirq,
of_node_to_fwnode(node), of_node_to_fwnode(node),
&meson_gpio_irq_domain_ops, &meson_gpio_irq_domain_ops,
ctl); ctl);
...@@ -396,7 +420,7 @@ static int __init meson_gpio_irq_of_init(struct device_node *node, ...@@ -396,7 +420,7 @@ static int __init meson_gpio_irq_of_init(struct device_node *node,
} }
pr_info("%d to %d gpio interrupt mux initialized\n", pr_info("%d to %d gpio interrupt mux initialized\n",
ctl->nr_hwirq, NUM_CHANNEL); ctl->params->nr_hwirq, NUM_CHANNEL);