mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-11 08:18:47 +00:00
irqchip updates for 6.2
- 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 -----BEGIN PGP SIGNATURE----- iQJDBAABCgAtFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAmOQsZ8PHG1hekBrZXJu ZWwub3JnAAoJECPQ0LrRPXpDQMwQAJWBLgkSHnPSJizG+KLpDSljRmkUif7j3PBk TVCwfj/xXiCUzP7PBhq2DUZWLvrKIiYl79Z6j/Jz4xlavPAVp6Cs+afxmJF2n/wy OwWF8uevHvFhKIFJUFxrSDaODWGI6afmDT7iflE3/Uz2ahVYoLkz5a10ji78N3JU peeX81i/kZE19w1aCs0sdMgzJufjK98hj55917GGv/IRBAjj2qi2tOZnPdQuE6d4 +vDiRtKDjDZYp9toaaH7DGBlBMG/yQzBhPaXtMnxH9wGK5858sYmHZroeM4FFbPR sJ/rCiaBEuvC6F1JkShKsRqT2DW1BgXYjSPxh+qhzwCOSG32DDjkj6LqVkygSoKQ MogCIkC3C4D0BIiokSdJByN1PWjoynwtYJrUkYPk4fMg7JxHYwee9dCptT81irMM +3L1mqx9CAll7YkzPVwrCbFyJF9K4ax9kjEvSH3E8xZxLKGnS9iqjQBfE9NKILCl tT6dmCJXTXsoGFjK4zz4o2N8i8aOeUz/B3GX5eYD+x0s0riXhg4kYIWFVXsxwJlX VSxBphr5fAQrdgBdOOESmiqNxPv9HuLRyR2mZ4blE4ylDa9NRUd+4UTy8x0bRmxD BO7qPof0CnrplBNEQi7kDtc91q4UxQoOV/G8LoFp454d9imMlAuPMbizTAULpWZu JxPXyrJl =fhi8 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
6132a490f9
@ -0,0 +1,34 @@
|
||||
# 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;
|
||||
};
|
@ -1,33 +0,0 @@
|
||||
* 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>;
|
||||
};
|
@ -0,0 +1,68 @@
|
||||
# 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,
|
||||
int eiointc_acpi_init(struct irq_domain *parent,
|
||||
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);
|
||||
int pch_lpc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_lpc_pic *acpi_pchlpc);
|
||||
|
@ -387,13 +387,15 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
||||
u8 pin;
|
||||
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
|
||||
* IRQs lines are inverted before reaching the interrupt
|
||||
* controller and must therefore be considered active high
|
||||
* 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;
|
||||
char *link = NULL;
|
||||
char link_desc[16];
|
||||
|
@ -86,7 +86,7 @@ config ALPINE_MSI
|
||||
|
||||
config AL_FIC
|
||||
bool "Amazon's Annapurna Labs Fabric Interrupt Controller"
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on OF
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
@ -576,6 +576,7 @@ config IRQ_LOONGARCH_CPU
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
select LOONGSON_HTVEC
|
||||
select LOONGSON_LIOINTC
|
||||
select LOONGSON_EIOINTC
|
||||
select LOONGSON_PCH_PIC
|
||||
|
@ -248,14 +248,14 @@ struct aic_info {
|
||||
bool fast_ipi;
|
||||
};
|
||||
|
||||
static const struct aic_info aic1_info = {
|
||||
static const struct aic_info aic1_info __initconst = {
|
||||
.version = 1,
|
||||
|
||||
.event = AIC_EVENT,
|
||||
.target_cpu = AIC_TARGET_CPU,
|
||||
};
|
||||
|
||||
static const struct aic_info aic1_fipi_info = {
|
||||
static const struct aic_info aic1_fipi_info __initconst = {
|
||||
.version = 1,
|
||||
|
||||
.event = AIC_EVENT,
|
||||
@ -264,7 +264,7 @@ static const struct aic_info aic1_fipi_info = {
|
||||
.fast_ipi = true,
|
||||
};
|
||||
|
||||
static const struct aic_info aic2_info = {
|
||||
static const struct aic_info aic2_info __initconst = {
|
||||
.version = 2,
|
||||
|
||||
.irq_cfg = AIC2_IRQ_CFG,
|
||||
|
@ -102,7 +102,7 @@ static int gic_probe(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret < 0)
|
||||
goto rpm_disable;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
@ -1171,7 +1172,7 @@ static bool gicv3_nolpi;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
@ -1332,7 +1333,7 @@ static bool gicv2_force_probe;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -92,18 +92,34 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = {
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
static int __init
|
||||
liointc_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
#ifdef CONFIG_OF
|
||||
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)
|
||||
{
|
||||
struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header;
|
||||
|
||||
return liointc_acpi_init(irq_domain, liointc_entry);
|
||||
}
|
||||
|
||||
static int __init
|
||||
eiointc_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
static int __init eiointc_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
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,
|
||||
|
||||
static int __init acpi_cascade_irqdomain_init(void)
|
||||
{
|
||||
acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC,
|
||||
liointc_parse_madt, 0);
|
||||
acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC,
|
||||
eiointc_parse_madt, 0);
|
||||
int r;
|
||||
|
||||
r = acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, liointc_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;
|
||||
}
|
||||
|
||||
static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (irq_domain)
|
||||
return 0;
|
||||
|
||||
@ -139,9 +163,9 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
|
||||
set_handle_irq(&handle_cpu_irq);
|
||||
acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
|
||||
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,
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#define EIOINTC_REG_NODEMAP 0x14a0
|
||||
#define EIOINTC_REG_IPMAP 0x14c0
|
||||
@ -301,9 +302,39 @@ static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __init
|
||||
pch_pic_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
static int eiointc_suspend(void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
|
||||
unsigned int node = (pchpic_entry->address >> 44) & 0xf;
|
||||
@ -315,9 +346,8 @@ pch_pic_parse_madt(union acpi_subtable_headers *header,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int __init
|
||||
pch_msi_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
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;
|
||||
struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group);
|
||||
@ -330,17 +360,23 @@ pch_msi_parse_madt(union acpi_subtable_headers *header,
|
||||
|
||||
static int __init acpi_cascade_irqdomain_init(void)
|
||||
{
|
||||
acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC,
|
||||
pch_pic_parse_madt, 0);
|
||||
acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC,
|
||||
pch_msi_parse_madt, 1);
|
||||
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, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init eiointc_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_eio_pic *acpi_eiointc)
|
||||
{
|
||||
int i, parent_irq;
|
||||
int i, ret, parent_irq;
|
||||
unsigned long node_map;
|
||||
struct eiointc_priv *priv;
|
||||
|
||||
@ -380,15 +416,16 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
|
||||
parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
|
||||
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,
|
||||
"irqchip/loongarch/intc:starting",
|
||||
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, msi_group);
|
||||
acpi_cascade_irqdomain_init();
|
||||
ret = acpi_cascade_irqdomain_init();
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
|
||||
out_free_handle:
|
||||
irq_domain_free_fwnode(priv->domain_handle);
|
||||
|
@ -16,11 +16,11 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
/* Registers */
|
||||
#define HTVEC_EN_OFF 0x20
|
||||
#define HTVEC_MAX_PARENT_IRQ 8
|
||||
|
||||
#define VEC_COUNT_PER_REG 32
|
||||
#define VEC_REG_IDX(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 {
|
||||
void __iomem *base;
|
||||
struct irq_domain *htvec_domain;
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
@ -155,64 +158,169 @@ static void htvec_reset(struct htvec *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static int htvec_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
static int htvec_suspend(void)
|
||||
{
|
||||
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;
|
||||
int err, parent_irq[8], i;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->num_parents = num_parents;
|
||||
priv->base = ioremap(addr, size);
|
||||
raw_spin_lock_init(&priv->htvec_lock);
|
||||
priv->base = of_iomap(node, 0);
|
||||
if (!priv->base) {
|
||||
err = -ENOMEM;
|
||||
goto free_priv;
|
||||
|
||||
/* Setup IRQ domain */
|
||||
priv->htvec_domain = irq_domain_create_linear(domain_handle,
|
||||
(VEC_COUNT_PER_REG * priv->num_parents),
|
||||
&htvec_domain_ops, priv);
|
||||
if (!priv->htvec_domain) {
|
||||
pr_err("loongson-htvec: cannot add IRQ domain\n");
|
||||
goto iounmap_base;
|
||||
}
|
||||
|
||||
htvec_reset(priv);
|
||||
|
||||
for (i = 0; i < priv->num_parents; i++) {
|
||||
irq_set_chained_handler_and_data(parent_irq[i],
|
||||
htvec_irq_dispatch, priv);
|
||||
}
|
||||
|
||||
htvec_priv = priv;
|
||||
|
||||
register_syscore_ops(&htvec_syscore_ops);
|
||||
|
||||
return 0;
|
||||
|
||||
iounmap_base:
|
||||
iounmap(priv->base);
|
||||
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;
|
||||
|
||||
priv->num_parents++;
|
||||
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),
|
||||
&htvec_domain_ops, priv);
|
||||
if (!priv->htvec_domain) {
|
||||
pr_err("Failed to create IRQ domain\n");
|
||||
err = -ENOMEM;
|
||||
goto irq_dispose;
|
||||
}
|
||||
|
||||
htvec_reset(priv);
|
||||
|
||||
for (i = 0; i < priv->num_parents; i++)
|
||||
irq_set_chained_handler_and_data(parent_irq[i],
|
||||
htvec_irq_dispatch, priv);
|
||||
err = htvec_init(res.start, resource_size(&res),
|
||||
num_parents, parent_irq, of_node_to_fwnode(node));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
|
||||
irq_dispose:
|
||||
for (; i > 0; i--)
|
||||
irq_dispose_mapping(parent_irq[i - 1]);
|
||||
iounmap_base:
|
||||
iounmap(priv->base);
|
||||
free_priv:
|
||||
kfree(priv);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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,
|
||||
if (WARN_ON(intsize < 1))
|
||||
return -EINVAL;
|
||||
*out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ;
|
||||
*out_type = IRQ_TYPE_NONE;
|
||||
|
||||
if (intsize > 1)
|
||||
*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
|
||||
else
|
||||
*out_type = IRQ_TYPE_NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -207,10 +212,13 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
|
||||
"reg-names", core_reg_names[i]);
|
||||
|
||||
if (index < 0)
|
||||
goto out_iounmap;
|
||||
continue;
|
||||
|
||||
priv->core_isr[i] = of_iomap(node, index);
|
||||
}
|
||||
|
||||
if (!priv->core_isr[0])
|
||||
goto out_iounmap;
|
||||
}
|
||||
|
||||
/* Setup IRQ domain */
|
||||
@ -349,6 +357,26 @@ IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init);
|
||||
#endif
|
||||
|
||||
#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 ret;
|
||||
@ -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");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = liointc_init(acpi_liointc->address, acpi_liointc->size,
|
||||
1, domain_handle, NULL);
|
||||
if (ret)
|
||||
if (ret == 0)
|
||||
ret = acpi_cascade_irqdomain_init();
|
||||
else
|
||||
irq_domain_free_fwnode(domain_handle);
|
||||
|
||||
return ret;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
/* Registers */
|
||||
#define LPC_INT_CTL 0x00
|
||||
@ -34,6 +35,7 @@ struct pch_lpc {
|
||||
u32 saved_reg_pol;
|
||||
};
|
||||
|
||||
static struct pch_lpc *pch_lpc_priv;
|
||||
struct fwnode_handle *pch_lpc_handle;
|
||||
|
||||
static void lpc_irq_ack(struct irq_data *d)
|
||||
@ -147,6 +149,26 @@ static int pch_lpc_disabled(struct pch_lpc *priv)
|
||||
(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,
|
||||
struct acpi_madt_lpc_pic *acpi_pchlpc)
|
||||
{
|
||||
@ -191,7 +213,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent,
|
||||
parent_irq = irq_create_fwspec_mapping(&fwspec);
|
||||
irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv);
|
||||
|
||||
pch_lpc_priv = priv;
|
||||
pch_lpc_handle = irq_handle;
|
||||
register_syscore_ops(&pch_lpc_syscore_ops);
|
||||
|
||||
return 0;
|
||||
|
||||
free_irq_handle:
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
/* Registers */
|
||||
#define PCH_PIC_MASK 0x20
|
||||
@ -42,6 +43,9 @@ struct pch_pic {
|
||||
raw_spinlock_t pic_lock;
|
||||
u32 vec_count;
|
||||
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];
|
||||
@ -145,6 +149,7 @@ static struct irq_chip pch_pic_irq_chip = {
|
||||
.irq_ack = pch_pic_ack_irq,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_set_type = pch_pic_set_type,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static int pch_pic_domain_translate(struct irq_domain *d,
|
||||
@ -155,15 +160,21 @@ static int pch_pic_domain_translate(struct irq_domain *d,
|
||||
struct pch_pic *priv = d->host_data;
|
||||
struct device_node *of_node = to_of_node(fwspec->fwnode);
|
||||
|
||||
if (fwspec->param_count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (of_node) {
|
||||
if (fwspec->param_count < 2)
|
||||
return -EINVAL;
|
||||
|
||||
*hwirq = fwspec->param[0] + priv->ht_vec_base;
|
||||
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
|
||||
} else {
|
||||
if (fwspec->param_count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
*hwirq = fwspec->param[0] - priv->gsi_base;
|
||||
*type = IRQ_TYPE_NONE;
|
||||
if (fwspec->param_count > 1)
|
||||
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
|
||||
else
|
||||
*type = IRQ_TYPE_NONE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -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,
|
||||
struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
|
||||
u32 gsi_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_priv[nr_pics++] = priv;
|
||||
|
||||
register_syscore_ops(&pch_pic_syscore_ops);
|
||||
|
||||
return 0;
|
||||
|
||||
iounmap_base:
|
||||
@ -325,9 +378,8 @@ int find_pch_pic(u32 gsi)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __init
|
||||
pch_lpc_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
static int __init pch_lpc_parse_madt(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
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,
|
||||
|
||||
static int __init acpi_cascade_irqdomain_init(void)
|
||||
{
|
||||
acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC,
|
||||
pch_lpc_parse_madt, 0);
|
||||
int r;
|
||||
|
||||
r = acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, pch_lpc_parse_madt, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -364,7 +420,7 @@ int __init pch_pic_acpi_init(struct irq_domain *parent,
|
||||
}
|
||||
|
||||
if (acpi_pchpic->id == 0)
|
||||
acpi_cascade_irqdomain_init();
|
||||
ret = acpi_cascade_irqdomain_init();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)
|
||||
if (ret)
|
||||
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") ||
|
||||
of_device_is_compatible(node, "fsl,ls1043a-extirq");
|
||||
raw_spin_lock_init(&priv->lock);
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
switch (intr) {
|
||||
|
@ -15,14 +15,41 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#define CIRQ_ACK 0x40
|
||||
#define CIRQ_MASK_SET 0xc0
|
||||
#define CIRQ_MASK_CLR 0x100
|
||||
#define CIRQ_SENS_SET 0x180
|
||||
#define CIRQ_SENS_CLR 0x1c0
|
||||
#define CIRQ_POL_SET 0x240
|
||||
#define CIRQ_POL_CLR 0x280
|
||||
#define CIRQ_CONTROL 0x300
|
||||
enum mtk_cirq_regoffs_index {
|
||||
CIRQ_STA,
|
||||
CIRQ_ACK,
|
||||
CIRQ_MASK_SET,
|
||||
CIRQ_MASK_CLR,
|
||||
CIRQ_SENS_SET,
|
||||
CIRQ_SENS_CLR,
|
||||
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_EDGE 0x2
|
||||
@ -32,18 +59,32 @@ struct mtk_cirq_chip_data {
|
||||
void __iomem *base;
|
||||
unsigned int ext_irq_start;
|
||||
unsigned int ext_irq_end;
|
||||
const u32 *offsets;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
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;
|
||||
unsigned int cirq_num = data->hwirq;
|
||||
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)
|
||||
@ -160,6 +201,7 @@ static const struct irq_domain_ops cirq_domain_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mtk_cirq_suspend(void)
|
||||
{
|
||||
void __iomem *reg;
|
||||
u32 value, mask;
|
||||
unsigned int irq, hwirq_num;
|
||||
bool pending, masked;
|
||||
@ -200,31 +242,34 @@ static int mtk_cirq_suspend(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
reg = mtk_cirq_irq_reg(cirq_data, CIRQ_ACK, i);
|
||||
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 */
|
||||
/* 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);
|
||||
writel_relaxed(value, cirq_data->base + CIRQ_CONTROL);
|
||||
writel_relaxed(value, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_cirq_resume(void)
|
||||
{
|
||||
void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
|
||||
u32 value;
|
||||
|
||||
/* flush recorded interrupts, will send signals to parent controller */
|
||||
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
|
||||
writel_relaxed(value | CIRQ_FLUSH, cirq_data->base + CIRQ_CONTROL);
|
||||
value = readl_relaxed(reg);
|
||||
writel_relaxed(value | CIRQ_FLUSH, reg);
|
||||
|
||||
/* disable cirq */
|
||||
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
|
||||
value = readl_relaxed(reg);
|
||||
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 = {
|
||||
@ -240,10 +285,19 @@ static void mtk_cirq_syscore_init(void)
|
||||
static inline void mtk_cirq_syscore_init(void) {}
|
||||
#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,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *domain, *domain_parent;
|
||||
const struct of_device_id *match;
|
||||
unsigned int irq_num;
|
||||
int ret;
|
||||
|
||||
@ -274,6 +328,13 @@ static int __init mtk_cirq_of_init(struct device_node *node,
|
||||
if (ret)
|
||||
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;
|
||||
domain = irq_domain_add_hierarchy(domain_parent, 0,
|
||||
irq_num, node,
|
||||
|
@ -187,7 +187,8 @@ static struct irq_chip plic_edge_chip = {
|
||||
.irq_set_affinity = plic_set_affinity,
|
||||
#endif
|
||||
.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 = {
|
||||
@ -201,7 +202,8 @@ static struct irq_chip plic_chip = {
|
||||
.irq_set_affinity = plic_set_affinity,
|
||||
#endif
|
||||
.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)
|
||||
|
@ -65,8 +65,7 @@ static int sl28cpld_intc_probe(struct platform_device *pdev)
|
||||
irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs);
|
||||
irqchip->chip.num_regs = 1;
|
||||
irqchip->chip.status_base = base + INTC_IP;
|
||||
irqchip->chip.mask_base = base + INTC_IE;
|
||||
irqchip->chip.mask_invert = true;
|
||||
irqchip->chip.unmask_base = base + INTC_IE;
|
||||
irqchip->chip.ack_base = base + INTC_IP;
|
||||
|
||||
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)
|
||||
static int st_irq_syscfg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *match;
|
||||
struct st_irq_syscfg *ddata;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_device(st_irq_syscfg_match, &pdev->dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
ddata->syscfg = (unsigned int)match->data;
|
||||
ddata->syscfg = (unsigned int) device_get_match_data(&pdev->dev);
|
||||
|
||||
ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
|
||||
if (IS_ERR(ddata->regmap)) {
|
||||
|
@ -146,6 +146,7 @@ static int __init wpcm450_aic_of_init(struct device_node *node,
|
||||
aic->regs = of_iomap(node, 0);
|
||||
if (!aic->regs) {
|
||||
pr_err("Failed to map WPCM450 AIC registers\n");
|
||||
kfree(aic);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user