Commit 6132a490 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'irqchip-6.2' of...

Merge tag 'irqchip-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core

Pull irqchip updates frim Marc Zyngier:

 - More APCI fixes and improvements for the LoongArch architecture,
   adding support for the HTVEC irqchip, suspend-resume, and some
   PCI INTx workarounds

 - Initial DT support for LoongArch. I'm not even kidding.

 - Support for the MTK CIRQv2, a minor deviation from the original version

 - Error handling fixes for wpcm450, GIC...

 - BE detection for a FSL controller

 - Declare the Sifive PLIC as wake-up agnostic

 - Simplify fishing out the device data for the ST irqchip

 - Mark some data structures as __initconst in the apple-aic driver

 - Switch over from strtobool to kstrtobool

 - COMPILE_TEST fixes
parents e6d22108 6ed54e17
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/interrupt-controller/loongarch,cpu-interrupt-controller.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LoongArch CPU Interrupt Controller
maintainers:
- Liu Peibao <liupeibao@loongson.cn>
properties:
compatible:
const: loongarch,cpu-interrupt-controller
'#interrupt-cells':
const: 1
interrupt-controller: true
additionalProperties: false
required:
- compatible
- '#interrupt-cells'
- interrupt-controller
examples:
- |
interrupt-controller {
compatible = "loongarch,cpu-interrupt-controller";
#interrupt-cells = <1>;
interrupt-controller;
};
* Mediatek 27xx cirq
In Mediatek SOCs, the CIRQ is a low power interrupt controller designed to
work outside MCUSYS which comprises with Cortex-Ax cores,CCI and GIC.
The external interrupts (outside MCUSYS) will feed through CIRQ and connect
to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
interrupts and generate a pulse signal to parent interrupt controller when
flush command is executed. With CIRQ, MCUSYS can be completely turned off
to improve the system power consumption without losing interrupts.
Required properties:
- compatible: should be one of
- "mediatek,mt2701-cirq" for mt2701 CIRQ
- "mediatek,mt8135-cirq" for mt8135 CIRQ
- "mediatek,mt8173-cirq" for mt8173 CIRQ
and "mediatek,cirq" as a fallback.
- interrupt-controller : Identifies the node as an interrupt controller.
- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt.
- reg: Physical base address of the cirq registers and length of memory
mapped region.
- mediatek,ext-irq-range: Identifies external irq number range in different
SOCs.
Example:
cirq: interrupt-controller@10204000 {
compatible = "mediatek,mt2701-cirq",
"mediatek,mtk-cirq";
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&sysirq>;
reg = <0 0x10204000 0 0x400>;
mediatek,ext-irq-start = <32 200>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/interrupt-controller/mediatek,mtk-cirq.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek System Interrupt Controller
maintainers:
- Youlin Pei <youlin.pei@mediatek.com>
description:
In MediaTek SoCs, the CIRQ is a low power interrupt controller designed to
work outside of MCUSYS which comprises with Cortex-Ax cores, CCI and GIC.
The external interrupts (outside MCUSYS) will feed through CIRQ and connect
to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
interrupts and generate a pulse signal to parent interrupt controller when
flush command is executed. With CIRQ, MCUSYS can be completely turned off
to improve the system power consumption without losing interrupts.
properties:
compatible:
items:
- enum:
- mediatek,mt2701-cirq
- mediatek,mt8135-cirq
- mediatek,mt8173-cirq
- mediatek,mt8192-cirq
- const: mediatek,mtk-cirq
reg:
maxItems: 1
'#interrupt-cells':
const: 3
interrupt-controller: true
mediatek,ext-irq-range:
$ref: /schemas/types.yaml#/definitions/uint32-array
items:
- description: First CIRQ interrupt
- description: Last CIRQ interrupt
description:
Identifies the range of external interrupts in different SoCs
required:
- compatible
- reg
- '#interrupt-cells'
- interrupt-controller
- mediatek,ext-irq-range
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
cirq: interrupt-controller@10204000 {
compatible = "mediatek,mt2701-cirq", "mediatek,mtk-cirq";
reg = <0x10204000 0x400>;
#interrupt-cells = <3>;
interrupt-controller;
interrupt-parent = <&sysirq>;
mediatek,ext-irq-range = <32 200>;
};
...@@ -93,7 +93,7 @@ int liointc_acpi_init(struct irq_domain *parent, ...@@ -93,7 +93,7 @@ int liointc_acpi_init(struct irq_domain *parent,
int eiointc_acpi_init(struct irq_domain *parent, int eiointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_eio_pic *acpi_eiointc); struct acpi_madt_eio_pic *acpi_eiointc);
struct irq_domain *htvec_acpi_init(struct irq_domain *parent, int htvec_acpi_init(struct irq_domain *parent,
struct acpi_madt_ht_pic *acpi_htvec); struct acpi_madt_ht_pic *acpi_htvec);
int pch_lpc_acpi_init(struct irq_domain *parent, int pch_lpc_acpi_init(struct irq_domain *parent,
struct acpi_madt_lpc_pic *acpi_pchlpc); struct acpi_madt_lpc_pic *acpi_pchlpc);
......
...@@ -387,13 +387,15 @@ int acpi_pci_irq_enable(struct pci_dev *dev) ...@@ -387,13 +387,15 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
u8 pin; u8 pin;
int triggering = ACPI_LEVEL_SENSITIVE; int triggering = ACPI_LEVEL_SENSITIVE;
/* /*
* On ARM systems with the GIC interrupt model, level interrupts * On ARM systems with the GIC interrupt model, or LoongArch
* systems with the LPIC interrupt model, level interrupts
* are always polarity high by specification; PCI legacy * are always polarity high by specification; PCI legacy
* IRQs lines are inverted before reaching the interrupt * IRQs lines are inverted before reaching the interrupt
* controller and must therefore be considered active high * controller and must therefore be considered active high
* as default. * as default.
*/ */
int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ? int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ||
acpi_irq_model == ACPI_IRQ_MODEL_LPIC ?
ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW; ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW;
char *link = NULL; char *link = NULL;
char link_desc[16]; char link_desc[16];
......
...@@ -86,7 +86,7 @@ config ALPINE_MSI ...@@ -86,7 +86,7 @@ config ALPINE_MSI
config AL_FIC config AL_FIC
bool "Amazon's Annapurna Labs Fabric Interrupt Controller" bool "Amazon's Annapurna Labs Fabric Interrupt Controller"
depends on OF || COMPILE_TEST depends on OF
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select IRQ_DOMAIN select IRQ_DOMAIN
help help
...@@ -576,6 +576,7 @@ config IRQ_LOONGARCH_CPU ...@@ -576,6 +576,7 @@ config IRQ_LOONGARCH_CPU
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select IRQ_DOMAIN select IRQ_DOMAIN
select GENERIC_IRQ_EFFECTIVE_AFF_MASK select GENERIC_IRQ_EFFECTIVE_AFF_MASK
select LOONGSON_HTVEC
select LOONGSON_LIOINTC select LOONGSON_LIOINTC
select LOONGSON_EIOINTC select LOONGSON_EIOINTC
select LOONGSON_PCH_PIC select LOONGSON_PCH_PIC
......
...@@ -248,14 +248,14 @@ struct aic_info { ...@@ -248,14 +248,14 @@ struct aic_info {
bool fast_ipi; bool fast_ipi;
}; };
static const struct aic_info aic1_info = { static const struct aic_info aic1_info __initconst = {
.version = 1, .version = 1,
.event = AIC_EVENT, .event = AIC_EVENT,
.target_cpu = AIC_TARGET_CPU, .target_cpu = AIC_TARGET_CPU,
}; };
static const struct aic_info aic1_fipi_info = { static const struct aic_info aic1_fipi_info __initconst = {
.version = 1, .version = 1,
.event = AIC_EVENT, .event = AIC_EVENT,
...@@ -264,7 +264,7 @@ static const struct aic_info aic1_fipi_info = { ...@@ -264,7 +264,7 @@ static const struct aic_info aic1_fipi_info = {
.fast_ipi = true, .fast_ipi = true,
}; };
static const struct aic_info aic2_info = { static const struct aic_info aic2_info __initconst = {
.version = 2, .version = 2,
.irq_cfg = AIC2_IRQ_CFG, .irq_cfg = AIC2_IRQ_CFG,
......
...@@ -102,7 +102,7 @@ static int gic_probe(struct platform_device *pdev) ...@@ -102,7 +102,7 @@ static int gic_probe(struct platform_device *pdev)
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev); ret = pm_runtime_resume_and_get(dev);
if (ret < 0) if (ret < 0)
goto rpm_disable; goto rpm_disable;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/kstrtox.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
...@@ -1171,7 +1172,7 @@ static bool gicv3_nolpi; ...@@ -1171,7 +1172,7 @@ static bool gicv3_nolpi;
static int __init gicv3_nolpi_cfg(char *buf) static int __init gicv3_nolpi_cfg(char *buf)
{ {
return strtobool(buf, &gicv3_nolpi); return kstrtobool(buf, &gicv3_nolpi);
} }
early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg); early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kstrtox.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -1332,7 +1333,7 @@ static bool gicv2_force_probe; ...@@ -1332,7 +1333,7 @@ static bool gicv2_force_probe;
static int __init gicv2_force_probe_cfg(char *buf) static int __init gicv2_force_probe_cfg(char *buf)
{ {
return strtobool(buf, &gicv2_force_probe); return kstrtobool(buf, &gicv2_force_probe);
} }
early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg); early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg);
......
...@@ -92,8 +92,25 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = { ...@@ -92,8 +92,25 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell, .xlate = irq_domain_xlate_onecell,
}; };
static int __init #ifdef CONFIG_OF
liointc_parse_madt(union acpi_subtable_headers *header, static int __init cpuintc_of_init(struct device_node *of_node,
struct device_node *parent)
{
cpuintc_handle = of_node_to_fwnode(of_node);
irq_domain = irq_domain_create_linear(cpuintc_handle, EXCCODE_INT_NUM,
&loongarch_cpu_intc_irq_domain_ops, NULL);
if (!irq_domain)
panic("Failed to add irqdomain for loongarch CPU");
set_handle_irq(&handle_cpu_irq);
return 0;
}
IRQCHIP_DECLARE(cpu_intc, "loongson,cpu-interrupt-controller", cpuintc_of_init);
#endif
static int __init liointc_parse_madt(union acpi_subtable_headers *header,
const unsigned long end) const unsigned long end)
{ {
struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header; struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header;
...@@ -101,8 +118,7 @@ liointc_parse_madt(union acpi_subtable_headers *header, ...@@ -101,8 +118,7 @@ liointc_parse_madt(union acpi_subtable_headers *header,
return liointc_acpi_init(irq_domain, liointc_entry); return liointc_acpi_init(irq_domain, liointc_entry);
} }
static int __init static int __init eiointc_parse_madt(union acpi_subtable_headers *header,
eiointc_parse_madt(union acpi_subtable_headers *header,
const unsigned long end) const unsigned long end)
{ {
struct acpi_madt_eio_pic *eiointc_entry = (struct acpi_madt_eio_pic *)header; struct acpi_madt_eio_pic *eiointc_entry = (struct acpi_madt_eio_pic *)header;
...@@ -112,16 +128,24 @@ eiointc_parse_madt(union acpi_subtable_headers *header, ...@@ -112,16 +128,24 @@ eiointc_parse_madt(union acpi_subtable_headers *header,
static int __init acpi_cascade_irqdomain_init(void) static int __init acpi_cascade_irqdomain_init(void)
{ {
acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, int r;
liointc_parse_madt, 0);
acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, r = acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, liointc_parse_madt, 0);
eiointc_parse_madt, 0); if (r < 0)
return r;
r = acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, eiointc_parse_madt, 0);
if (r < 0)
return r;
return 0; return 0;
} }
static int __init cpuintc_acpi_init(union acpi_subtable_headers *header, static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
const unsigned long end) const unsigned long end)
{ {
int ret;
if (irq_domain) if (irq_domain)
return 0; return 0;
...@@ -139,9 +163,9 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header, ...@@ -139,9 +163,9 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
set_handle_irq(&handle_cpu_irq); set_handle_irq(&handle_cpu_irq);
acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id); acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq); acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);
acpi_cascade_irqdomain_init(); ret = acpi_cascade_irqdomain_init();
return 0; return ret;
} }
IRQCHIP_ACPI_DECLARE(cpuintc_v1, ACPI_MADT_TYPE_CORE_PIC, IRQCHIP_ACPI_DECLARE(cpuintc_v1, ACPI_MADT_TYPE_CORE_PIC,
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/syscore_ops.h>
#define EIOINTC_REG_NODEMAP 0x14a0 #define EIOINTC_REG_NODEMAP 0x14a0
#define EIOINTC_REG_IPMAP 0x14c0 #define EIOINTC_REG_IPMAP 0x14c0
...@@ -301,8 +302,38 @@ static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group ...@@ -301,8 +302,38 @@ static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group
return NULL; return NULL;
} }
static int __init static int eiointc_suspend(void)
pch_pic_parse_madt(union acpi_subtable_headers *header, {
return 0;
}
static void eiointc_resume(void)
{
int i, j;
struct irq_desc *desc;
struct irq_data *irq_data;
eiointc_router_init(0);
for (i = 0; i < nr_pics; i++) {
for (j = 0; j < VEC_COUNT; j++) {
desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j);
if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) {
raw_spin_lock(&desc->lock);
irq_data = &desc->irq_data;
eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0);
raw_spin_unlock(&desc->lock);
}
}
}
}
static struct syscore_ops eiointc_syscore_ops = {
.suspend = eiointc_suspend,
.resume = eiointc_resume,
};
static int __init pch_pic_parse_madt(union acpi_subtable_headers *header,
const unsigned long end) const unsigned long end)
{ {
struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header; struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
...@@ -315,8 +346,7 @@ pch_pic_parse_madt(union acpi_subtable_headers *header, ...@@ -315,8 +346,7 @@ pch_pic_parse_madt(union acpi_subtable_headers *header,
return -EINVAL; return -EINVAL;
} }
static int __init static int __init pch_msi_parse_madt(union acpi_subtable_headers *header,
pch_msi_parse_madt(union acpi_subtable_headers *header,
const unsigned long end) const unsigned long end)
{ {
struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header; struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
...@@ -330,17 +360,23 @@ pch_msi_parse_madt(union acpi_subtable_headers *header, ...@@ -330,17 +360,23 @@ pch_msi_parse_madt(union acpi_subtable_headers *header,
static int __init acpi_cascade_irqdomain_init(void) static int __init acpi_cascade_irqdomain_init(void)
{ {
acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, int r;
pch_pic_parse_madt, 0);
acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0);
pch_msi_parse_madt, 1); if (r < 0)
return r;
r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1);
if (r < 0)
return r;
return 0; return 0;
} }
int __init eiointc_acpi_init(struct irq_domain *parent, int __init eiointc_acpi_init(struct irq_domain *parent,
struct acpi_madt_eio_pic *acpi_eiointc) struct acpi_madt_eio_pic *acpi_eiointc)
{ {
int i, parent_irq; int i, ret, parent_irq;
unsigned long node_map; unsigned long node_map;
struct eiointc_priv *priv; struct eiointc_priv *priv;
...@@ -380,15 +416,16 @@ int __init eiointc_acpi_init(struct irq_domain *parent, ...@@ -380,15 +416,16 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade); parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
register_syscore_ops(&eiointc_syscore_ops);
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,
"irqchip/loongarch/intc:starting", "irqchip/loongarch/intc:starting",
eiointc_router_init, NULL); eiointc_router_init, NULL);
acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group); acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group);
acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group); acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group);
acpi_cascade_irqdomain_init(); ret = acpi_cascade_irqdomain_init();
return 0; return ret;
out_free_handle: out_free_handle:
irq_domain_free_fwnode(priv->domain_handle); irq_domain_free_fwnode(priv->domain_handle);
......
...@@ -16,11 +16,11 @@ ...@@ -16,11 +16,11 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/syscore_ops.h>
/* Registers */ /* Registers */
#define HTVEC_EN_OFF 0x20 #define HTVEC_EN_OFF 0x20
#define HTVEC_MAX_PARENT_IRQ 8 #define HTVEC_MAX_PARENT_IRQ 8
#define VEC_COUNT_PER_REG 32 #define VEC_COUNT_PER_REG 32
#define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG) #define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG)
#define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG) #define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG)
...@@ -30,8 +30,11 @@ struct htvec { ...@@ -30,8 +30,11 @@ struct htvec {
void __iomem *base; void __iomem *base;
struct irq_domain *htvec_domain; struct irq_domain *htvec_domain;
raw_spinlock_t htvec_lock; raw_spinlock_t htvec_lock;
u32 saved_vec_en[HTVEC_MAX_PARENT_IRQ];
}; };
static struct htvec *htvec_priv;
static void htvec_irq_dispatch(struct irq_desc *desc) static void htvec_irq_dispatch(struct irq_desc *desc)
{ {
int i; int i;
...@@ -155,64 +158,169 @@ static void htvec_reset(struct htvec *priv) ...@@ -155,64 +158,169 @@ static void htvec_reset(struct htvec *priv)
} }
} }
static int htvec_of_init(struct device_node *node, static int htvec_suspend(void)
struct device_node *parent) {
int i;
for (i = 0; i < htvec_priv->num_parents; i++)
htvec_priv->saved_vec_en[i] = readl(htvec_priv->base + HTVEC_EN_OFF + 4 * i);
return 0;
}
static void htvec_resume(void)
{ {
int i;
for (i = 0; i < htvec_priv->num_parents; i++)
writel(htvec_priv->saved_vec_en[i], htvec_priv->base + HTVEC_EN_OFF + 4 * i);
}
static struct syscore_ops htvec_syscore_ops = {
.suspend = htvec_suspend,
.resume = htvec_resume,
};
static int htvec_init(phys_addr_t addr, unsigned long size,
int num_parents, int parent_irq[], struct fwnode_handle *domain_handle)
{
int i;
struct htvec *priv; struct htvec *priv;
int err, parent_irq[8], i;
priv = kzalloc(sizeof(*priv), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
priv->num_parents = num_parents;
priv->base = ioremap(addr, size);
raw_spin_lock_init(&priv->htvec_lock); raw_spin_lock_init(&priv->htvec_lock);
priv->base = of_iomap(node, 0);
if (!priv->base) {
err = -ENOMEM;
goto free_priv;
}
/* Interrupt may come from any of the 8 interrupt lines */ /* Setup IRQ domain */
for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) { priv->htvec_domain = irq_domain_create_linear(domain_handle,
parent_irq[i] = irq_of_parse_and_map(node, i);
if (parent_irq[i] <= 0)
break;
priv->num_parents++;
}
if (!priv->num_parents) {
pr_err("Failed to get parent irqs\n");
err = -ENODEV;
goto iounmap_base;
}
priv->htvec_domain = irq_domain_create_linear(of_node_to_fwnode(node),
(VEC_COUNT_PER_REG * priv->num_parents), (VEC_COUNT_PER_REG * priv->num_parents),
&htvec_domain_ops, priv); &htvec_domain_ops, priv);
if (!priv->htvec_domain) { if (!priv->htvec_domain) {
pr_err("Failed to create IRQ domain\n"); pr_err("loongson-htvec: cannot add IRQ domain\n");
err = -ENOMEM; goto iounmap_base;
goto irq_dispose;
} }
htvec_reset(priv); htvec_reset(priv);
for (i = 0; i < priv->num_parents; i++) for (i = 0; i < priv->num_parents; i++) {
irq_set_chained_handler_and_data(parent_irq[i], irq_set_chained_handler_and_data(parent_irq[i],
htvec_irq_dispatch, priv); htvec_irq_dispatch, priv);
}
htvec_priv = priv;
register_syscore_ops(&htvec_syscore_ops);
return 0; return 0;
irq_dispose:
for (; i > 0; i--)
irq_dispose_mapping(parent_irq[i - 1]);
iounmap_base: iounmap_base:
iounmap(priv->base); iounmap(priv->base);
free_priv:
kfree(priv); kfree(priv);
return -EINVAL;
}
#ifdef CONFIG_OF
static int htvec_of_init(struct device_node *node,
struct device_node *parent)
{
int i, err;
int parent_irq[8];
int num_parents = 0;
struct resource res;
if (of_address_to_resource(node, 0, &res))
return -EINVAL;
/* Interrupt may come from any of the 8 interrupt lines */
for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
parent_irq[i] = irq_of_parse_and_map(node, i);
if (parent_irq[i] <= 0)
break;
num_parents++;
}
err = htvec_init(res.start, resource_size(&res),
num_parents, parent_irq, of_node_to_fwnode(node));
if (err < 0)
return err; return err;
return 0;
} }
IRQCHIP_DECLARE(htvec, "loongson,htvec-1.0", htvec_of_init); IRQCHIP_DECLARE(htvec, "loongson,htvec-1.0", htvec_of_init);
#endif
#ifdef CONFIG_ACPI
static int __init pch_pic_parse_madt(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
return pch_pic_acpi_init(htvec_priv->htvec_domain, pchpic_entry);
}
static int __init pch_msi_parse_madt(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
return pch_msi_acpi_init(htvec_priv->htvec_domain, pchmsi_entry);
}
static int __init acpi_cascade_irqdomain_init(void)
{
int r;
r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0);
if (r < 0)
return r;
r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 0);
if (r < 0)
return r;
return 0;
}
int __init htvec_acpi_init(struct irq_domain *parent,
struct acpi_madt_ht_pic *acpi_htvec)
{
int i, ret;
int num_parents, parent_irq[8];
struct fwnode_handle *domain_handle;
if (!acpi_htvec)
return -EINVAL;
num_parents = HTVEC_MAX_PARENT_IRQ;
domain_handle = irq_domain_alloc_fwnode(&acpi_htvec->address);
if (!domain_handle) {
pr_err("Unable to allocate domain handle\n");
return -ENOMEM;
}
/* Interrupt may come from any of the 8 interrupt lines */
for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++)
parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]);
ret = htvec_init(acpi_htvec->address, acpi_htvec->size,
num_parents, parent_irq, domain_handle);
if (ret == 0)
ret = acpi_cascade_irqdomain_init();
else
irq_domain_free_fwnode(domain_handle);
return ret;
}
#endif
...@@ -167,7 +167,12 @@ static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, ...@@ -167,7 +167,12 @@ static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
if (WARN_ON(intsize < 1)) if (WARN_ON(intsize < 1))
return -EINVAL; return -EINVAL;
*out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ; *out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ;
if (intsize > 1)
*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
else
*out_type = IRQ_TYPE_NONE; *out_type = IRQ_TYPE_NONE;
return 0; return 0;
} }
...@@ -207,10 +212,13 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision, ...@@ -207,10 +212,13 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
"reg-names", core_reg_names[i]); "reg-names", core_reg_names[i]);
if (index < 0) if (index < 0)
goto out_iounmap; continue;
priv->core_isr[i] = of_iomap(node, index); priv->core_isr[i] = of_iomap(node, index);
} }
if (!priv->core_isr[0])
goto out_iounmap;
} }
/* Setup IRQ domain */ /* Setup IRQ domain */
...@@ -349,6 +357,26 @@ IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init); ...@@ -349,6 +357,26 @@ IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init);
#endif #endif
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static int __init htintc_parse_madt(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_ht_pic *htintc_entry = (struct acpi_madt_ht_pic *)header;
struct irq_domain *parent = irq_find_matching_fwnode(liointc_handle, DOMAIN_BUS_ANY);
return htvec_acpi_init(parent, htintc_entry);
}
static int __init acpi_cascade_irqdomain_init(void)
{
int r;
r = acpi_table_parse_madt(ACPI_MADT_TYPE_HT_PIC, htintc_parse_madt, 0);
if (r < 0)
return r;
return 0;
}
int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc) int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc)
{ {
int ret; int ret;
...@@ -365,9 +393,12 @@ int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic ...@@ -365,9 +393,12 @@ int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic
pr_err("Unable to allocate domain handle\n"); pr_err("Unable to allocate domain handle\n");
return -ENOMEM; return -ENOMEM;
} }
ret = liointc_init(acpi_liointc->address, acpi_liointc->size, ret = liointc_init(acpi_liointc->address, acpi_liointc->size,
1, domain_handle, NULL); 1, domain_handle, NULL);
if (ret) if (ret == 0)
ret = acpi_cascade_irqdomain_init();
else
irq_domain_free_fwnode(domain_handle); irq_domain_free_fwnode(domain_handle);
return ret; return ret;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/syscore_ops.h>
/* Registers */ /* Registers */
#define LPC_INT_CTL 0x00 #define LPC_INT_CTL 0x00
...@@ -34,6 +35,7 @@ struct pch_lpc { ...@@ -34,6 +35,7 @@ struct pch_lpc {
u32 saved_reg_pol; u32 saved_reg_pol;
}; };
static struct pch_lpc *pch_lpc_priv;
struct fwnode_handle *pch_lpc_handle; struct fwnode_handle *pch_lpc_handle;
static void lpc_irq_ack(struct irq_data *d) static void lpc_irq_ack(struct irq_data *d)
...@@ -147,6 +149,26 @@ static int pch_lpc_disabled(struct pch_lpc *priv) ...@@ -147,6 +149,26 @@ static int pch_lpc_disabled(struct pch_lpc *priv)
(readl(priv->base + LPC_INT_STS) == 0xffffffff); (readl(priv->base + LPC_INT_STS) == 0xffffffff);
} }
static int pch_lpc_suspend(void)
{
pch_lpc_priv->saved_reg_ctl = readl(pch_lpc_priv->base + LPC_INT_CTL);
pch_lpc_priv->saved_reg_ena = readl(pch_lpc_priv->base + LPC_INT_ENA);
pch_lpc_priv->saved_reg_pol = readl(pch_lpc_priv->base + LPC_INT_POL);
return 0;
}
static void pch_lpc_resume(void)
{
writel(pch_lpc_priv->saved_reg_ctl, pch_lpc_priv->base + LPC_INT_CTL);
writel(pch_lpc_priv->saved_reg_ena, pch_lpc_priv->base + LPC_INT_ENA);
writel(pch_lpc_priv->saved_reg_pol, pch_lpc_priv->base + LPC_INT_POL);
}
static struct syscore_ops pch_lpc_syscore_ops = {
.suspend = pch_lpc_suspend,
.resume = pch_lpc_resume,
};
int __init pch_lpc_acpi_init(struct irq_domain *parent, int __init pch_lpc_acpi_init(struct irq_domain *parent,
struct acpi_madt_lpc_pic *acpi_pchlpc) struct acpi_madt_lpc_pic *acpi_pchlpc)
{ {
...@@ -191,7 +213,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, ...@@ -191,7 +213,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent,
parent_irq = irq_create_fwspec_mapping(&fwspec); parent_irq = irq_create_fwspec_mapping(&fwspec);
irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv); irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv);
pch_lpc_priv = priv;
pch_lpc_handle = irq_handle; pch_lpc_handle = irq_handle;
register_syscore_ops(&pch_lpc_syscore_ops);
return 0; return 0;
free_irq_handle: free_irq_handle:
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/syscore_ops.h>
/* Registers */ /* Registers */
#define PCH_PIC_MASK 0x20 #define PCH_PIC_MASK 0x20
...@@ -42,6 +43,9 @@ struct pch_pic { ...@@ -42,6 +43,9 @@ struct pch_pic {
raw_spinlock_t pic_lock; raw_spinlock_t pic_lock;
u32 vec_count; u32 vec_count;
u32 gsi_base; u32 gsi_base;
u32 saved_vec_en[PIC_REG_COUNT];
u32 saved_vec_pol[PIC_REG_COUNT];
u32 saved_vec_edge[PIC_REG_COUNT];
}; };
static struct pch_pic *pch_pic_priv[MAX_IO_PICS]; static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
...@@ -145,6 +149,7 @@ static struct irq_chip pch_pic_irq_chip = { ...@@ -145,6 +149,7 @@ static struct irq_chip pch_pic_irq_chip = {
.irq_ack = pch_pic_ack_irq, .irq_ack = pch_pic_ack_irq,
.irq_set_affinity = irq_chip_set_affinity_parent, .irq_set_affinity = irq_chip_set_affinity_parent,
.irq_set_type = pch_pic_set_type, .irq_set_type = pch_pic_set_type,
.flags = IRQCHIP_SKIP_SET_WAKE,
}; };
static int pch_pic_domain_translate(struct irq_domain *d, static int pch_pic_domain_translate(struct irq_domain *d,
...@@ -155,14 +160,20 @@ static int pch_pic_domain_translate(struct irq_domain *d, ...@@ -155,14 +160,20 @@ static int pch_pic_domain_translate(struct irq_domain *d,
struct pch_pic *priv = d->host_data; struct pch_pic *priv = d->host_data;
struct device_node *of_node = to_of_node(fwspec->fwnode); struct device_node *of_node = to_of_node(fwspec->fwnode);
if (fwspec->param_count < 1) if (of_node) {
if (fwspec->param_count < 2)
return -EINVAL; return -EINVAL;
if (of_node) {
*hwirq = fwspec->param[0] + priv->ht_vec_base; *hwirq = fwspec->param[0] + priv->ht_vec_base;
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
} else { } else {
if (fwspec->param_count < 1)
return -EINVAL;
*hwirq = fwspec->param[0] - priv->gsi_base; *hwirq = fwspec->param[0] - priv->gsi_base;
if (fwspec->param_count > 1)
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
else
*type = IRQ_TYPE_NONE; *type = IRQ_TYPE_NONE;
} }
...@@ -228,6 +239,46 @@ static void pch_pic_reset(struct pch_pic *priv) ...@@ -228,6 +239,46 @@ static void pch_pic_reset(struct pch_pic *priv)
} }
} }
static int pch_pic_suspend(void)
{
int i, j;
for (i = 0; i < nr_pics; i++) {
for (j = 0; j < PIC_REG_COUNT; j++) {
pch_pic_priv[i]->saved_vec_pol[j] =
readl(pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j);
pch_pic_priv[i]->saved_vec_edge[j] =
readl(pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j);
pch_pic_priv[i]->saved_vec_en[j] =
readl(pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j);
}
}
return 0;
}
static void pch_pic_resume(void)
{
int i, j;
for (i = 0; i < nr_pics; i++) {
pch_pic_reset(pch_pic_priv[i]);
for (j = 0; j < PIC_REG_COUNT; j++) {
writel(pch_pic_priv[i]->saved_vec_pol[j],
pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j);
writel(pch_pic_priv[i]->saved_vec_edge[j],
pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j);
writel(pch_pic_priv[i]->saved_vec_en[j],
pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j);
}
}
}
static struct syscore_ops pch_pic_syscore_ops = {
.suspend = pch_pic_suspend,
.resume = pch_pic_resume,
};
static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
struct irq_domain *parent_domain, struct fwnode_handle *domain_handle, struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
u32 gsi_base) u32 gsi_base)
...@@ -260,6 +311,8 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, ...@@ -260,6 +311,8 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
pch_pic_handle[nr_pics] = domain_handle; pch_pic_handle[nr_pics] = domain_handle;
pch_pic_priv[nr_pics++] = priv; pch_pic_priv[nr_pics++] = priv;
register_syscore_ops(&pch_pic_syscore_ops);
return 0; return 0;
iounmap_base: iounmap_base:
...@@ -325,8 +378,7 @@ int find_pch_pic(u32 gsi) ...@@ -325,8 +378,7 @@ int find_pch_pic(u32 gsi)
return -1; return -1;
} }
static int __init static int __init pch_lpc_parse_madt(union acpi_subtable_headers *header,
pch_lpc_parse_madt(union acpi_subtable_headers *header,
const unsigned long end) const unsigned long end)
{ {
struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header; struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header;
...@@ -336,8 +388,12 @@ pch_lpc_parse_madt(union acpi_subtable_headers *header, ...@@ -336,8 +388,12 @@ pch_lpc_parse_madt(union acpi_subtable_headers *header,
static int __init acpi_cascade_irqdomain_init(void) static int __init acpi_cascade_irqdomain_init(void)
{ {
acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, int r;
pch_lpc_parse_madt, 0);
r = acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, pch_lpc_parse_madt, 0);
if (r < 0)
return r;
return 0; return 0;
} }
...@@ -364,7 +420,7 @@ int __init pch_pic_acpi_init(struct irq_domain *parent, ...@@ -364,7 +420,7 @@ int __init pch_pic_acpi_init(struct irq_domain *parent,
} }
if (acpi_pchpic->id == 0) if (acpi_pchpic->id == 0)
acpi_cascade_irqdomain_init(); ret = acpi_cascade_irqdomain_init();
return ret; return ret;
} }
......
...@@ -203,7 +203,7 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent) ...@@ -203,7 +203,7 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)
if (ret) if (ret)
goto err_parse_map; goto err_parse_map;
priv->big_endian = of_device_is_big_endian(parent); priv->big_endian = of_device_is_big_endian(node->parent);
priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") || priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") ||
of_device_is_compatible(node, "fsl,ls1043a-extirq"); of_device_is_compatible(node, "fsl,ls1043a-extirq");
raw_spin_lock_init(&priv->lock); raw_spin_lock_init(&priv->lock);
......
...@@ -494,7 +494,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, ...@@ -494,7 +494,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin; map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
/* /*
* If adding support for more per-cpu interrupts, keep the the * If adding support for more per-cpu interrupts, keep the
* array in gic_all_vpes_irq_cpu_online() in sync. * array in gic_all_vpes_irq_cpu_online() in sync.
*/ */
switch (intr) { switch (intr) {
......
...@@ -15,14 +15,41 @@ ...@@ -15,14 +15,41 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#define CIRQ_ACK 0x40 enum mtk_cirq_regoffs_index {
#define CIRQ_MASK_SET 0xc0 CIRQ_STA,
#define CIRQ_MASK_CLR 0x100 CIRQ_ACK,
#define CIRQ_SENS_SET 0x180 CIRQ_MASK_SET,
#define CIRQ_SENS_CLR 0x1c0 CIRQ_MASK_CLR,
#define CIRQ_POL_SET 0x240 CIRQ_SENS_SET,
#define CIRQ_POL_CLR 0x280 CIRQ_SENS_CLR,
#define CIRQ_CONTROL 0x300 CIRQ_POL_SET,
CIRQ_POL_CLR,
CIRQ_CONTROL
};
static const u32 mtk_cirq_regoffs_v1[] = {
[CIRQ_STA] = 0x0,
[CIRQ_ACK] = 0x40,
[CIRQ_MASK_SET] = 0xc0,
[CIRQ_MASK_CLR] = 0x100,
[CIRQ_SENS_SET] = 0x180,
[CIRQ_SENS_CLR] = 0x1c0,
[CIRQ_POL_SET] = 0x240,
[CIRQ_POL_CLR] = 0x280,
[CIRQ_CONTROL] = 0x300,
};
static const u32 mtk_cirq_regoffs_v2[] = {
[CIRQ_STA] = 0x0,
[CIRQ_ACK] = 0x80,
[CIRQ_MASK_SET] = 0x180,
[CIRQ_MASK_CLR] = 0x200,
[CIRQ_SENS_SET] = 0x300,
[CIRQ_SENS_CLR] = 0x380,
[CIRQ_POL_SET] = 0x480,
[CIRQ_POL_CLR] = 0x500,
[CIRQ_CONTROL] = 0x600,
};
#define CIRQ_EN 0x1 #define CIRQ_EN 0x1
#define CIRQ_EDGE 0x2 #define CIRQ_EDGE 0x2
...@@ -32,18 +59,32 @@ struct mtk_cirq_chip_data { ...@@ -32,18 +59,32 @@ struct mtk_cirq_chip_data {
void __iomem *base; void __iomem *base;
unsigned int ext_irq_start; unsigned int ext_irq_start;
unsigned int ext_irq_end; unsigned int ext_irq_end;
const u32 *offsets;
struct irq_domain *domain; struct irq_domain *domain;
}; };
static struct mtk_cirq_chip_data *cirq_data; static struct mtk_cirq_chip_data *cirq_data;
static void mtk_cirq_write_mask(struct irq_data *data, unsigned int offset) static void __iomem *mtk_cirq_reg(struct mtk_cirq_chip_data *chip_data,
enum mtk_cirq_regoffs_index idx)
{
return chip_data->base + chip_data->offsets[idx];
}
static void __iomem *mtk_cirq_irq_reg(struct mtk_cirq_chip_data *chip_data,
enum mtk_cirq_regoffs_index idx,
unsigned int cirq_num)
{
return mtk_cirq_reg(chip_data, idx) + (cirq_num / 32) * 4;
}
static void mtk_cirq_write_mask(struct irq_data *data, enum mtk_cirq_regoffs_index idx)
{ {
struct mtk_cirq_chip_data *chip_data = data->chip_data; struct mtk_cirq_chip_data *chip_data = data->chip_data;
unsigned int cirq_num = data->hwirq; unsigned int cirq_num = data->hwirq;
u32 mask = 1 << (cirq_num % 32); u32 mask = 1 << (cirq_num % 32);
writel_relaxed(mask, chip_data->base + offset + (cirq_num / 32) * 4); writel_relaxed(mask, mtk_cirq_irq_reg(chip_data, idx, cirq_num));
} }
static void mtk_cirq_mask(struct irq_data *data) static void mtk_cirq_mask(struct irq_data *data)
...@@ -160,6 +201,7 @@ static const struct irq_domain_ops cirq_domain_ops = { ...@@ -160,6 +201,7 @@ static const struct irq_domain_ops cirq_domain_ops = {
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int mtk_cirq_suspend(void) static int mtk_cirq_suspend(void)
{ {
void __iomem *reg;
u32 value, mask; u32 value, mask;
unsigned int irq, hwirq_num; unsigned int irq, hwirq_num;
bool pending, masked; bool pending, masked;
...@@ -200,31 +242,34 @@ static int mtk_cirq_suspend(void) ...@@ -200,31 +242,34 @@ static int mtk_cirq_suspend(void)
continue; continue;
} }
reg = mtk_cirq_irq_reg(cirq_data, CIRQ_ACK, i);
mask = 1 << (i % 32); mask = 1 << (i % 32);
writel_relaxed(mask, cirq_data->base + CIRQ_ACK + (i / 32) * 4); writel_relaxed(mask, reg);
} }
/* set edge_only mode, record edge-triggerd interrupts */ /* set edge_only mode, record edge-triggerd interrupts */
/* enable cirq */ /* enable cirq */
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
value = readl_relaxed(reg);
value |= (CIRQ_EDGE | CIRQ_EN); value |= (CIRQ_EDGE | CIRQ_EN);
writel_relaxed(value, cirq_data->base + CIRQ_CONTROL); writel_relaxed(value, reg);
return 0; return 0;
} }
static void mtk_cirq_resume(void) static void mtk_cirq_resume(void)
{ {
void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
u32 value; u32 value;
/* flush recorded interrupts, will send signals to parent controller */ /* flush recorded interrupts, will send signals to parent controller */
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); value = readl_relaxed(reg);
writel_relaxed(value | CIRQ_FLUSH, cirq_data->base + CIRQ_CONTROL); writel_relaxed(value | CIRQ_FLUSH, reg);
/* disable cirq */ /* disable cirq */
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); value = readl_relaxed(reg);
value &= ~(CIRQ_EDGE | CIRQ_EN); value &= ~(CIRQ_EDGE | CIRQ_EN);
writel_relaxed(value, cirq_data->base + CIRQ_CONTROL); writel_relaxed(value, reg);
} }
static struct syscore_ops mtk_cirq_syscore_ops = { static struct syscore_ops mtk_cirq_syscore_ops = {
...@@ -240,10 +285,19 @@ static void mtk_cirq_syscore_init(void) ...@@ -240,10 +285,19 @@ static void mtk_cirq_syscore_init(void)
static inline void mtk_cirq_syscore_init(void) {} static inline void mtk_cirq_syscore_init(void) {}
#endif #endif
static const struct of_device_id mtk_cirq_of_match[] = {
{ .compatible = "mediatek,mt2701-cirq", .data = &mtk_cirq_regoffs_v1 },
{ .compatible = "mediatek,mt8135-cirq", .data = &mtk_cirq_regoffs_v1 },
{ .compatible = "mediatek,mt8173-cirq", .data = &mtk_cirq_regoffs_v1 },
{ .compatible = "mediatek,mt8192-cirq", .data = &mtk_cirq_regoffs_v2 },
{ /* sentinel */ }
};
static int __init mtk_cirq_of_init(struct device_node *node, static int __init mtk_cirq_of_init(struct device_node *node,
struct device_node *parent) struct device_node *parent)
{ {
struct irq_domain *domain, *domain_parent; struct irq_domain *domain, *domain_parent;
const struct of_device_id *match;
unsigned int irq_num; unsigned int irq_num;
int ret; int ret;
...@@ -274,6 +328,13 @@ static int __init mtk_cirq_of_init(struct device_node *node, ...@@ -274,6 +328,13 @@ static int __init mtk_cirq_of_init(struct device_node *node,
if (ret) if (ret)
goto out_unmap; goto out_unmap;
match = of_match_node(mtk_cirq_of_match, node);
if (!match) {
ret = -ENODEV;
goto out_unmap;
}
cirq_data->offsets = match->data;
irq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1; irq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1;
domain = irq_domain_add_hierarchy(domain_parent, 0, domain = irq_domain_add_hierarchy(domain_parent, 0,
irq_num, node, irq_num, node,
......
...@@ -187,7 +187,8 @@ static struct irq_chip plic_edge_chip = { ...@@ -187,7 +187,8 @@ static struct irq_chip plic_edge_chip = {
.irq_set_affinity = plic_set_affinity, .irq_set_affinity = plic_set_affinity,
#endif #endif
.irq_set_type = plic_irq_set_type, .irq_set_type = plic_irq_set_type,
.flags = IRQCHIP_AFFINITY_PRE_STARTUP, .flags = IRQCHIP_SKIP_SET_WAKE |
IRQCHIP_AFFINITY_PRE_STARTUP,
}; };
static struct irq_chip plic_chip = { static struct irq_chip plic_chip = {
...@@ -201,7 +202,8 @@ static struct irq_chip plic_chip = { ...@@ -201,7 +202,8 @@ static struct irq_chip plic_chip = {
.irq_set_affinity = plic_set_affinity, .irq_set_affinity = plic_set_affinity,
#endif #endif
.irq_set_type = plic_irq_set_type, .irq_set_type = plic_irq_set_type,
.flags = IRQCHIP_AFFINITY_PRE_STARTUP, .flags = IRQCHIP_SKIP_SET_WAKE |
IRQCHIP_AFFINITY_PRE_STARTUP,
}; };
static int plic_irq_set_type(struct irq_data *d, unsigned int type) static int plic_irq_set_type(struct irq_data *d, unsigned int type)
......
...@@ -65,8 +65,7 @@ static int sl28cpld_intc_probe(struct platform_device *pdev) ...@@ -65,8 +65,7 @@ static int sl28cpld_intc_probe(struct platform_device *pdev)
irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs); irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs);
irqchip->chip.num_regs = 1; irqchip->chip.num_regs = 1;
irqchip->chip.status_base = base + INTC_IP; irqchip->chip.status_base = base + INTC_IP;
irqchip->chip.mask_base = base + INTC_IE; irqchip->chip.unmask_base = base + INTC_IE;
irqchip->chip.mask_invert = true;
irqchip->chip.ack_base = base + INTC_IP; irqchip->chip.ack_base = base + INTC_IP;
return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev), return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
......
...@@ -153,18 +153,13 @@ static int st_irq_syscfg_enable(struct platform_device *pdev) ...@@ -153,18 +153,13 @@ static int st_irq_syscfg_enable(struct platform_device *pdev)
static int st_irq_syscfg_probe(struct platform_device *pdev) static int st_irq_syscfg_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct st_irq_syscfg *ddata; struct st_irq_syscfg *ddata;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata) if (!ddata)
return -ENOMEM; return -ENOMEM;
match = of_match_device(st_irq_syscfg_match, &pdev->dev); ddata->syscfg = (unsigned int) device_get_match_data(&pdev->dev);
if (!match)
return -ENODEV;
ddata->syscfg = (unsigned int)match->data;
ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(ddata->regmap)) { if (IS_ERR(ddata->regmap)) {
......
...@@ -146,6 +146,7 @@ static int __init wpcm450_aic_of_init(struct device_node *node, ...@@ -146,6 +146,7 @@ static int __init wpcm450_aic_of_init(struct device_node *node,
aic->regs = of_iomap(node, 0); aic->regs = of_iomap(node, 0);
if (!aic->regs) { if (!aic->regs) {
pr_err("Failed to map WPCM450 AIC registers\n"); pr_err("Failed to map WPCM450 AIC registers\n");
kfree(aic);
return -ENOMEM; return -ENOMEM;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment