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:
+34
@@ -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,
|
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)
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
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 {
|
|||||||
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 = {
|
|||||||
.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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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;
|
|||||||
|
|
||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
#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;
|
|||||||
|
|
||||||
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,18 +92,34 @@ 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,
|
||||||
const unsigned long end)
|
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;
|
struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)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,
|
|||||||
|
|
||||||
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,
|
|||||||
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 @@
|
|||||||
#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,9 +302,39 @@ 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,
|
{
|
||||||
const unsigned long end)
|
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;
|
struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
|
||||||
unsigned int node = (pchpic_entry->address >> 44) & 0xf;
|
unsigned int node = (pchpic_entry->address >> 44) & 0xf;
|
||||||
@@ -315,9 +346,8 @@ 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;
|
||||||
struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group);
|
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)
|
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,
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
/* Setup IRQ domain */
|
||||||
err = -ENOMEM;
|
priv->htvec_domain = irq_domain_create_linear(domain_handle,
|
||||||
goto free_priv;
|
(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 */
|
/* Interrupt may come from any of the 8 interrupt lines */
|
||||||
for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
|
for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
|
||||||
parent_irq[i] = irq_of_parse_and_map(node, i);
|
parent_irq[i] = irq_of_parse_and_map(node, i);
|
||||||
if (parent_irq[i] <= 0)
|
if (parent_irq[i] <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
priv->num_parents++;
|
num_parents++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!priv->num_parents) {
|
err = htvec_init(res.start, resource_size(&res),
|
||||||
pr_err("Failed to get parent irqs\n");
|
num_parents, parent_irq, of_node_to_fwnode(node));
|
||||||
err = -ENODEV;
|
if (err < 0)
|
||||||
goto iounmap_base;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return 0;
|
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);
|
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))
|
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;
|
||||||
*out_type = IRQ_TYPE_NONE;
|
|
||||||
|
if (intsize > 1)
|
||||||
|
*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
|
||||||
|
else
|
||||||
|
*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,
|
|||||||
"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);
|
|||||||
#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
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
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)
|
|||||||
(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,
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
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 = {
|
|||||||
.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,15 +160,21 @@ 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)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (of_node) {
|
if (of_node) {
|
||||||
|
if (fwspec->param_count < 2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
*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;
|
||||||
*type = IRQ_TYPE_NONE;
|
if (fwspec->param_count > 1)
|
||||||
|
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
|
||||||
|
else
|
||||||
|
*type = IRQ_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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,
|
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,
|
|||||||
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,9 +378,8 @@ 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,
|
|||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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,
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
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 = {
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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 = {
|
|||||||
.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 = {
|
|||||||
.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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user