Commit 36de4f94 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'irqchip-6.1' of...

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

Pull irqchip updates from Marc Zyngier:

 - A new driver for the FSL MU widget that provides platform MSI

 - An update for the Realtek RTL irqchip to use a DT binding that
   actually describes the hardware

 - A handful of DT updates, as well as minor code and spelling fixes

Link: https://lore.kernel.org/r/20221002125554.3902840-1-maz@kernel.org
parents 94ec234a 732d69c8
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interrupt-controller/fsl,mu-msi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale/NXP i.MX Messaging Unit (MU) work as msi controller
maintainers:
- Frank Li <Frank.Li@nxp.com>
description: |
The Messaging Unit module enables two processors within the SoC to
communicate and coordinate by passing messages (e.g. data, status
and control) through the MU interface. The MU also provides the ability
for one processor (A side) to signal the other processor (B side) using
interrupts.
Because the MU manages the messaging between processors, the MU uses
different clocks (from each side of the different peripheral buses).
Therefore, the MU must synchronize the accesses from one side to the
other. The MU accomplishes synchronization using two sets of matching
registers (Processor A-side, Processor B-side).
MU can work as msi interrupt controller to do doorbell
allOf:
- $ref: /schemas/interrupt-controller/msi-controller.yaml#
properties:
compatible:
enum:
- fsl,imx6sx-mu-msi
- fsl,imx7ulp-mu-msi
- fsl,imx8ulp-mu-msi
- fsl,imx8ulp-mu-msi-s4
reg:
items:
- description: a side register base address
- description: b side register base address
reg-names:
items:
- const: processor-a-side
- const: processor-b-side
interrupts:
description: a side interrupt number.
maxItems: 1
clocks:
maxItems: 1
power-domains:
items:
- description: a side power domain
- description: b side power domain
power-domain-names:
items:
- const: processor-a-side
- const: processor-b-side
interrupt-controller: true
msi-controller: true
"#msi-cells":
const: 0
required:
- compatible
- reg
- interrupts
- interrupt-controller
- msi-controller
- "#msi-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/firmware/imx/rsrc.h>
msi-controller@5d270000 {
compatible = "fsl,imx6sx-mu-msi";
msi-controller;
#msi-cells = <0>;
interrupt-controller;
reg = <0x5d270000 0x10000>, /* A side */
<0x5d300000 0x10000>; /* B side */
reg-names = "processor-a-side", "processor-b-side";
interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&pd IMX_SC_R_MU_12A>,
<&pd IMX_SC_R_MU_12B>;
power-domain-names = "processor-a-side", "processor-b-side";
};
......@@ -6,6 +6,14 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek RTL SoC interrupt controller devicetree bindings
description:
Interrupt controller and router for Realtek MIPS SoCs, allowing each SoC
interrupt to be routed to one parent CPU (hardware) interrupt, or left
disconnected.
All connected input lines from SoC peripherals can be masked individually,
and an interrupt status register is present to indicate which interrupts are
pending.
maintainers:
- Birger Koblitz <mail@birger-koblitz.de>
- Bert Vermeulen <bert@biot.com>
......@@ -13,23 +21,33 @@ maintainers:
properties:
compatible:
const: realtek,rtl-intc
oneOf:
- items:
- enum:
- realtek,rtl8380-intc
- const: realtek,rtl-intc
- const: realtek,rtl-intc
deprecated: true
"#interrupt-cells":
description:
SoC interrupt line index.
const: 1
reg:
maxItems: 1
interrupts:
maxItems: 1
minItems: 1
maxItems: 15
description:
List of parent interrupts, in the order that they are connected to this
interrupt router's outputs, starting at the first output.
interrupt-controller: true
"#address-cells":
const: 0
interrupt-map:
deprecated: true
description: Describes mapping from SoC interrupts to CPU interrupts
required:
......@@ -37,21 +55,33 @@ required:
- reg
- "#interrupt-cells"
- interrupt-controller
- "#address-cells"
- interrupt-map
allOf:
- if:
properties:
compatible:
const: realtek,rtl-intc
then:
properties:
"#address-cells":
const: 0
required:
- "#address-cells"
- interrupt-map
else:
required:
- interrupts
additionalProperties: false
examples:
- |
intc: interrupt-controller@3000 {
compatible = "realtek,rtl-intc";
interrupt-controller@3000 {
compatible = "realtek,rtl8380-intc", "realtek,rtl-intc";
#interrupt-cells = <1>;
interrupt-controller;
reg = <0x3000 0x20>;
#address-cells = <0>;
interrupt-map =
<31 &cpuintc 2>,
<30 &cpuintc 1>,
<29 &cpuintc 5>;
reg = <0x3000 0x18>;
interrupt-parent = <&cpuintc>;
interrupts = <2>, <3>, <4>, <5>, <6>;
};
......@@ -37,6 +37,7 @@ properties:
- renesas,intc-ex-r8a77990 # R-Car E3
- renesas,intc-ex-r8a77995 # R-Car D3
- renesas,intc-ex-r8a779a0 # R-Car V3U
- renesas,intc-ex-r8a779g0 # R-Car V4H
- const: renesas,irqc
'#interrupt-cells':
......
......@@ -59,6 +59,9 @@ properties:
interrupt-controller: true
'#interrupt-cells':
const: 0
msi-controller: true
ti,interrupt-ranges:
......
......@@ -58,6 +58,9 @@ properties:
1 = If intr supports edge triggered interrupts.
4 = If intr supports level triggered interrupts.
reg:
maxItems: 1
interrupt-controller: true
'#interrupt-cells':
......
......@@ -138,6 +138,7 @@ struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
return domain;
}
EXPORT_SYMBOL_GPL(platform_msi_create_irq_domain);
static int platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec,
irq_write_msi_msg_t write_msi_msg)
......
......@@ -3,7 +3,7 @@ menu "IRQ chip support"
config IRQCHIP
def_bool y
depends on OF_IRQ
depends on (OF_IRQ || ACPI_GENERIC_GSI)
config ARM_GIC
bool
......@@ -481,6 +481,20 @@ config IMX_INTMUX
help
Support for the i.MX INTMUX interrupt multiplexer.
config IMX_MU_MSI
tristate "i.MX MU used as MSI controller"
depends on OF && HAS_IOMEM
default m if ARCH_MXC
select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
select GENERIC_MSI_IRQ_DOMAIN
help
Provide a driver for the MU block used as a CPU-to-CPU MSI
controller. This requires a specially crafted DT to make use
of this driver.
If unsure, say N
config LS1X_IRQ
bool "Loongson-1 Interrupt Controller"
depends on MACH_LOONGSON32
......
......@@ -99,6 +99,7 @@ obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o
obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o
obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o
obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
......
......@@ -978,7 +978,7 @@ static int __gic_update_rdist_properties(struct redist_region *region,
u64 typer = gic_read_typer(ptr + GICR_TYPER);
u32 ctlr = readl_relaxed(ptr + GICR_CTLR);
/* Boot-time cleanip */
/* Boot-time cleanup */
if ((typer & GICR_TYPER_VLPIS) && (typer & GICR_TYPER_RVPEID)) {
u64 val;
......
This diff is collapsed.
......@@ -21,11 +21,33 @@
#define RTL_ICTL_IRR2 0x10
#define RTL_ICTL_IRR3 0x14
#define RTL_ICTL_NUM_INPUTS 32
#define REG(x) (realtek_ictl_base + x)
static DEFINE_RAW_SPINLOCK(irq_lock);
static void __iomem *realtek_ictl_base;
/*
* IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
* placing IRQ 31 in the first four bits. A routing value of '0' means the
* interrupt is left disconnected. Routing values {1..15} connect to output
* lines {0..14}.
*/
#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
#define IRR_SHIFT(idx) ((idx * 4) % 32)
static void write_irr(void __iomem *irr0, int idx, u32 value)
{
unsigned int offset = IRR_OFFSET(idx);
unsigned int shift = IRR_SHIFT(idx);
u32 irr;
irr = readl(irr0 + offset) & ~(0xf << shift);
irr |= (value & 0xf) << shift;
writel(irr, irr0 + offset);
}
static void realtek_ictl_unmask_irq(struct irq_data *i)
{
unsigned long flags;
......@@ -62,8 +84,14 @@ static struct irq_chip realtek_ictl_irq = {
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
unsigned long flags;
irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
raw_spin_lock_irqsave(&irq_lock, flags);
write_irr(REG(RTL_ICTL_IRR0), hw, 1);
raw_spin_unlock_irqrestore(&irq_lock, flags);
return 0;
}
......@@ -95,90 +123,50 @@ static void realtek_irq_dispatch(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
/*
* SoC interrupts are cascaded to MIPS CPU interrupts according to the
* interrupt-map in the device tree. Each SoC interrupt gets 4 bits for
* the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts
* thus go into 4 IRRs. A routing value of '0' means the interrupt is left
* disconnected. Routing values {1..15} connect to output lines {0..14}.
*/
static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
{
struct device_node *cpu_ictl;
const __be32 *imap;
u32 imaplen, soc_int, cpu_int, tmp, regs[4];
int ret, i, irr_regs[] = {
RTL_ICTL_IRR3,
RTL_ICTL_IRR2,
RTL_ICTL_IRR1,
RTL_ICTL_IRR0,
};
u8 mips_irqs_set;
ret = of_property_read_u32(node, "#address-cells", &tmp);
if (ret || tmp)
return -EINVAL;
imap = of_get_property(node, "interrupt-map", &imaplen);
if (!imap || imaplen % 3)
return -EINVAL;
mips_irqs_set = 0;
memset(regs, 0, sizeof(regs));
for (i = 0; i < imaplen; i += 3 * sizeof(u32)) {
soc_int = be32_to_cpup(imap);
if (soc_int > 31)
return -EINVAL;
cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1));
if (!cpu_ictl)
return -EINVAL;
ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp);
of_node_put(cpu_ictl);
if (ret || tmp != 1)
return -EINVAL;
cpu_int = be32_to_cpup(imap + 2);
if (cpu_int > 7 || cpu_int < 2)
return -EINVAL;
if (!(mips_irqs_set & BIT(cpu_int))) {
irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch,
domain);
mips_irqs_set |= BIT(cpu_int);
}
/* Use routing values (1..6) for CPU interrupts (2..7) */
regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32;
imap += 3;
}
for (i = 0; i < 4; i++)
writel(regs[i], REG(irr_regs[i]));
return 0;
}
static int __init realtek_rtl_of_init(struct device_node *node, struct device_node *parent)
{
struct of_phandle_args oirq;
struct irq_domain *domain;
int ret;
unsigned int soc_irq;
int parent_irq;
realtek_ictl_base = of_iomap(node, 0);
if (!realtek_ictl_base)
return -ENXIO;
/* Disable all cascaded interrupts */
/* Disable all cascaded interrupts and clear routing */
writel(0, REG(RTL_ICTL_GIMR));
for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0);
if (WARN_ON(!of_irq_count(node))) {
/*
* If DT contains no parent interrupts, assume MIPS CPU IRQ 2
* (HW0) is connected to the first output. This is the case for
* all known hardware anyway. "interrupt-map" is deprecated, so
* don't bother trying to parse that.
*/
oirq.np = of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-controller");
oirq.args_count = 1;
oirq.args[0] = 2;
parent_irq = irq_create_of_mapping(&oirq);
of_node_put(oirq.np);
} else {
parent_irq = of_irq_get(node, 0);
}
domain = irq_domain_add_simple(node, 32, 0,
&irq_domain_ops, NULL);
if (parent_irq < 0)
return parent_irq;
else if (!parent_irq)
return -ENODEV;
ret = map_interrupts(node, domain);
if (ret) {
pr_err("invalid interrupt map\n");
return ret;
}
domain = irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_ops, NULL);
if (!domain)
return -ENOMEM;
irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, domain);
return 0;
}
......
......@@ -44,7 +44,8 @@ static const struct of_device_id drv_name##_irqchip_match_table[] = {
#define IRQCHIP_MATCH(compat, fn) { .compatible = compat, \
.data = typecheck_irq_init_cb(fn), },
#define IRQCHIP_PLATFORM_DRIVER_END(drv_name) \
#define IRQCHIP_PLATFORM_DRIVER_END(drv_name, ...) \
{}, \
}; \
MODULE_DEVICE_TABLE(of, drv_name##_irqchip_match_table); \
......@@ -56,6 +57,7 @@ static struct platform_driver drv_name##_driver = { \
.owner = THIS_MODULE, \
.of_match_table = drv_name##_irqchip_match_table, \
.suppress_bind_attrs = true, \
__VA_ARGS__ \
}, \
}; \
builtin_platform_driver(drv_name##_driver)
......
......@@ -37,9 +37,8 @@ extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data);
extern int of_irq_to_resource(struct device_node *dev, int index,
struct resource *r);
extern void of_irq_init(const struct of_device_id *matches);
#ifdef CONFIG_OF_IRQ
extern void of_irq_init(const struct of_device_id *matches);
extern int of_irq_parse_one(struct device_node *device, int index,
struct of_phandle_args *out_irq);
extern int of_irq_count(struct device_node *dev);
......@@ -57,6 +56,9 @@ extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev,
extern void of_msi_configure(struct device *dev, struct device_node *np);
u32 of_msi_map_id(struct device *dev, struct device_node *msi_np, u32 id_in);
#else
static inline void of_irq_init(const struct of_device_id *matches)
{
}
static inline int of_irq_parse_one(struct device_node *device, int index,
struct of_phandle_args *out_irq)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment