Commit 0bdf0621 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'irq-core-2024-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq subsystem updates from Ingo Molnar:

 - Add support for the IA55 interrupt controller on RZ/G3S SoC's

 - Update/fix the Qualcom MPM Interrupt Controller driver's register
   enumeration within the somewhat exotic "RPM Message RAM" MMIO-mapped
   shared memory region that is used for other purposes as well

 - Clean up the Xtensa built-in Programmable Interrupt Controller driver
   (xtensa-pic) a bit

* tag 'irq-core-2024-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  irqchip/irq-xtensa-pic: Clean up
  irqchip/qcom-mpm: Support passing a slice of SRAM as reg space
  dt-bindings: interrupt-controller: mpm: Pass MSG RAM slice through phandle
  dt-bindings: interrupt-controller: renesas,rzg2l-irqc: Document RZ/G3S
  irqchip/renesas-rzg2l: Add support for suspend to RAM
  irqchip/renesas-rzg2l: Add macro to retrieve TITSR register offset based on register's index
  irqchip/renesas-rzg2l: Implement restriction when writing ISCR register
  irqchip/renesas-rzg2l: Document structure members
  irqchip/renesas-rzg2l: Align struct member names to tabs
  irqchip/renesas-rzg2l: Use tabs instead of spaces
parents f24dc33f 69ffab9b
Loading
Loading
Loading
Loading
+36 −18
Original line number Diff line number Diff line
@@ -29,6 +29,12 @@ properties:
    maxItems: 1
    description:
      Specifies the base address and size of vMPM registers in RPM MSG RAM.
    deprecated: true

  qcom,rpm-msg-ram:
    $ref: /schemas/types.yaml#/definitions/phandle
    description:
      Phandle to the APSS MPM slice of the RPM Message RAM

  interrupts:
    maxItems: 1
@@ -67,23 +73,35 @@ properties:

required:
  - compatible
  - reg
  - interrupts
  - mboxes
  - interrupt-controller
  - '#interrupt-cells'
  - qcom,mpm-pin-count
  - qcom,mpm-pin-map
  - qcom,rpm-msg-ram

additionalProperties: false

examples:
  - |
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    mpm: interrupt-controller@45f01b8 {

    remoteproc-rpm {
        compatible = "qcom,msm8998-rpm-proc", "qcom,rpm-proc";

        glink-edge {
            compatible = "qcom,glink-rpm";

            interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
            qcom,rpm-msg-ram = <&rpm_msg_ram>;
            mboxes = <&apcs_glb 0>;
        };

        mpm: interrupt-controller {
            compatible = "qcom,mpm";
            qcom,rpm-msg-ram = <&apss_mpm>;
            interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>;
        reg = <0x45f01b8 0x1000>;
            mboxes = <&apcs_glb 1>;
            interrupt-controller;
            #interrupt-cells = <2>;
@@ -94,7 +112,7 @@ examples:
                               <12 422>,
                               <24 79>,
                               <86 183>,
                           <90 260>,
                               <91 260>;
            #power-domain-cells = <0>;
        };
    };
+4 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ properties:
          - renesas,r9a07g043u-irqc   # RZ/G2UL
          - renesas,r9a07g044-irqc    # RZ/G2{L,LC}
          - renesas,r9a07g054-irqc    # RZ/V2L
          - renesas,r9a08g045-irqc    # RZ/G3S
      - const: renesas,rzg2l-irqc

  '#interrupt-cells':
@@ -167,7 +168,9 @@ allOf:
      properties:
        compatible:
          contains:
            const: renesas,r9a07g043u-irqc
            enum:
              - renesas,r9a07g043u-irqc
              - renesas,r9a08g045-irqc
    then:
      properties:
        interrupts:
+23 −3
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
@@ -322,8 +323,10 @@ static int qcom_mpm_init(struct device_node *np, struct device_node *parent)
	struct device *dev = &pdev->dev;
	struct irq_domain *parent_domain;
	struct generic_pm_domain *genpd;
	struct device_node *msgram_np;
	struct qcom_mpm_priv *priv;
	unsigned int pin_cnt;
	struct resource res;
	int i, irq;
	int ret;

@@ -374,9 +377,26 @@ static int qcom_mpm_init(struct device_node *np, struct device_node *parent)

	raw_spin_lock_init(&priv->lock);

	/* If we have a handle to an RPM message ram partition, use it. */
	msgram_np = of_parse_phandle(np, "qcom,rpm-msg-ram", 0);
	if (msgram_np) {
		ret = of_address_to_resource(msgram_np, 0, &res);
		if (ret) {
			of_node_put(msgram_np);
			return ret;
		}

		/* Don't use devm_ioremap_resource, as we're accessing a shared region. */
		priv->base = devm_ioremap(dev, res.start, resource_size(&res));
		of_node_put(msgram_np);
		if (IS_ERR(priv->base))
			return PTR_ERR(priv->base);
	} else {
		/* Otherwise, fall back to simple MMIO. */
		priv->base = devm_platform_ioremap_resource(pdev, 0);
		if (IS_ERR(priv->base))
			return PTR_ERR(priv->base);
	}

	for (i = 0; i < priv->reg_stride; i++) {
		qcom_mpm_write(priv, MPM_REG_ENABLE, i, 0);
+83 −27
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/syscore_ops.h>

#define IRQC_IRQ_START			1
#define IRQC_IRQ_COUNT			8
@@ -28,8 +29,7 @@
#define ISCR				0x10
#define IITSR				0x14
#define TSCR				0x20
#define TITSR0				0x24
#define TITSR1				0x28
#define TITSR(n)			(0x24 + (n) * 4)
#define TITSR0_MAX_INT			16
#define TITSEL_WIDTH			0x2
#define TSSR(n)				(0x30 + ((n) * 4))
@@ -56,11 +56,29 @@
#define TINT_EXTRACT_HWIRQ(x)		FIELD_GET(GENMASK(15, 0), (x))
#define TINT_EXTRACT_GPIOINT(x)		FIELD_GET(GENMASK(31, 16), (x))

struct rzg2l_irqc_priv {
/**
 * struct rzg2l_irqc_reg_cache - registers cache (necessary for suspend/resume)
 * @iitsr: IITSR register
 * @titsr: TITSR registers
 */
struct rzg2l_irqc_reg_cache {
	u32	iitsr;
	u32	titsr[2];
};

/**
 * struct rzg2l_irqc_priv - IRQ controller private data structure
 * @base:	Controller's base address
 * @fwspec:	IRQ firmware specific data
 * @lock:	Lock to serialize access to hardware registers
 * @cache:	Registers cache for suspend/resume
 */
static struct rzg2l_irqc_priv {
	void __iomem			*base;
	struct irq_fwspec		fwspec[IRQC_NUM_IRQ];
	raw_spinlock_t			lock;
};
	struct rzg2l_irqc_reg_cache	cache;
} *rzg2l_irqc_data;

static struct rzg2l_irqc_priv *irq_data_to_priv(struct irq_data *data)
{
@@ -72,11 +90,17 @@ static void rzg2l_irq_eoi(struct irq_data *d)
	unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
	struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
	u32 bit = BIT(hw_irq);
	u32 reg;
	u32 iitsr, iscr;

	reg = readl_relaxed(priv->base + ISCR);
	if (reg & bit)
		writel_relaxed(reg & ~bit, priv->base + ISCR);
	iscr = readl_relaxed(priv->base + ISCR);
	iitsr = readl_relaxed(priv->base + IITSR);

	/*
	 * ISCR can only be cleared if the type is falling-edge, rising-edge or
	 * falling/rising-edge.
	 */
	if ((iscr & bit) && (iitsr & IITSR_IITSEL_MASK(hw_irq)))
		writel_relaxed(iscr & ~bit, priv->base + ISCR);
}

static void rzg2l_tint_eoi(struct irq_data *d)
@@ -188,8 +212,7 @@ static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
	struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
	unsigned int hwirq = irqd_to_hwirq(d);
	u32 titseln = hwirq - IRQC_TINT_START;
	u32 offset;
	u8 sense;
	u8 index, sense;
	u32 reg;

	switch (type & IRQ_TYPE_SENSE_MASK) {
@@ -205,17 +228,17 @@ static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
		return -EINVAL;
	}

	offset = TITSR0;
	index = 0;
	if (titseln >= TITSR0_MAX_INT) {
		titseln -= TITSR0_MAX_INT;
		offset = TITSR1;
		index = 1;
	}

	raw_spin_lock(&priv->lock);
	reg = readl_relaxed(priv->base + offset);
	reg = readl_relaxed(priv->base + TITSR(index));
	reg &= ~(IRQ_MASK << (titseln * TITSEL_WIDTH));
	reg |= sense << (titseln * TITSEL_WIDTH);
	writel_relaxed(reg, priv->base + offset);
	writel_relaxed(reg, priv->base + TITSR(index));
	raw_spin_unlock(&priv->lock);

	return 0;
@@ -236,6 +259,38 @@ static int rzg2l_irqc_set_type(struct irq_data *d, unsigned int type)
	return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
}

static int rzg2l_irqc_irq_suspend(void)
{
	struct rzg2l_irqc_reg_cache *cache = &rzg2l_irqc_data->cache;
	void __iomem *base = rzg2l_irqc_data->base;

	cache->iitsr = readl_relaxed(base + IITSR);
	for (u8 i = 0; i < 2; i++)
		cache->titsr[i] = readl_relaxed(base + TITSR(i));

	return 0;
}

static void rzg2l_irqc_irq_resume(void)
{
	struct rzg2l_irqc_reg_cache *cache = &rzg2l_irqc_data->cache;
	void __iomem *base = rzg2l_irqc_data->base;

	/*
	 * Restore only interrupt type. TSSRx will be restored at the
	 * request of pin controller to avoid spurious interrupts due
	 * to invalid PIN states.
	 */
	for (u8 i = 0; i < 2; i++)
		writel_relaxed(cache->titsr[i], base + TITSR(i));
	writel_relaxed(cache->iitsr, base + IITSR);
}

static struct syscore_ops rzg2l_irqc_syscore_ops = {
	.suspend	= rzg2l_irqc_irq_suspend,
	.resume		= rzg2l_irqc_irq_resume,
};

static const struct irq_chip irqc_chip = {
	.name			= "rzg2l-irqc",
	.irq_eoi		= rzg2l_irqc_eoi,
@@ -321,7 +376,6 @@ static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent)
	struct irq_domain *irq_domain, *parent_domain;
	struct platform_device *pdev;
	struct reset_control *resetn;
	struct rzg2l_irqc_priv *priv;
	int ret;

	pdev = of_find_device_by_node(node);
@@ -334,15 +388,15 @@ static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent)
		return -ENODEV;
	}

	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
	rzg2l_irqc_data = devm_kzalloc(&pdev->dev, sizeof(*rzg2l_irqc_data), GFP_KERNEL);
	if (!rzg2l_irqc_data)
		return -ENOMEM;

	priv->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
	if (IS_ERR(priv->base))
		return PTR_ERR(priv->base);
	rzg2l_irqc_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
	if (IS_ERR(rzg2l_irqc_data->base))
		return PTR_ERR(rzg2l_irqc_data->base);

	ret = rzg2l_irqc_parse_interrupts(priv, node);
	ret = rzg2l_irqc_parse_interrupts(rzg2l_irqc_data, node);
	if (ret) {
		dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret);
		return ret;
@@ -365,17 +419,19 @@ static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent)
		goto pm_disable;
	}

	raw_spin_lock_init(&priv->lock);
	raw_spin_lock_init(&rzg2l_irqc_data->lock);

	irq_domain = irq_domain_add_hierarchy(parent_domain, 0, IRQC_NUM_IRQ,
					      node, &rzg2l_irqc_domain_ops,
					      priv);
					      rzg2l_irqc_data);
	if (!irq_domain) {
		dev_err(&pdev->dev, "failed to add irq domain\n");
		ret = -ENOMEM;
		goto pm_put;
	}

	register_syscore_ops(&rzg2l_irqc_syscore_ops);

	return 0;

pm_put:
+12 −19
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
 * Kevin Chea
 */

#include <linux/bits.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/irq.h>
@@ -19,8 +20,6 @@
#include <linux/irqchip/xtensa-pic.h>
#include <linux/of.h>

unsigned int cached_irq_mask;

/*
 * Device Tree IRQ specifier translation function which works with one or
 * two cell bindings. First cell value maps directly to the hwirq number.
@@ -44,34 +43,30 @@ static const struct irq_domain_ops xtensa_irq_domain_ops = {

static void xtensa_irq_mask(struct irq_data *d)
{
	cached_irq_mask &= ~(1 << d->hwirq);
	xtensa_set_sr(cached_irq_mask, intenable);
}
	u32 irq_mask;

static void xtensa_irq_unmask(struct irq_data *d)
{
	cached_irq_mask |= 1 << d->hwirq;
	xtensa_set_sr(cached_irq_mask, intenable);
	irq_mask = xtensa_get_sr(intenable);
	irq_mask &= ~BIT(d->hwirq);
	xtensa_set_sr(irq_mask, intenable);
}

static void xtensa_irq_enable(struct irq_data *d)
static void xtensa_irq_unmask(struct irq_data *d)
{
	xtensa_irq_unmask(d);
}
	u32 irq_mask;

static void xtensa_irq_disable(struct irq_data *d)
{
	xtensa_irq_mask(d);
	irq_mask = xtensa_get_sr(intenable);
	irq_mask |= BIT(d->hwirq);
	xtensa_set_sr(irq_mask, intenable);
}

static void xtensa_irq_ack(struct irq_data *d)
{
	xtensa_set_sr(1 << d->hwirq, intclear);
	xtensa_set_sr(BIT(d->hwirq), intclear);
}

static int xtensa_irq_retrigger(struct irq_data *d)
{
	unsigned int mask = 1u << d->hwirq;
	unsigned int mask = BIT(d->hwirq);

	if (WARN_ON(mask & ~XCHAL_INTTYPE_MASK_SOFTWARE))
		return 0;
@@ -81,8 +76,6 @@ static int xtensa_irq_retrigger(struct irq_data *d)

static struct irq_chip xtensa_irq_chip = {
	.name		= "xtensa",
	.irq_enable	= xtensa_irq_enable,
	.irq_disable	= xtensa_irq_disable,
	.irq_mask	= xtensa_irq_mask,
	.irq_unmask	= xtensa_irq_unmask,
	.irq_ack	= xtensa_irq_ack,