All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alex Elder <elder@riscstar.com>
To: tglx@kernel.org, radu@rendec.net, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org
Cc: Daniel Thompson <daniel@riscstar.com>,
	p.zabel@pengutronix.de, mohd.anwar@oss.qualcomm.com,
	lorenzo.bianconi@oss.qualcomm.com, danielt@kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 2/2] irqchip: introduce TC9564 SoC MSIGEN support
Date: Mon, 12 Oct 2026 14:02:44 -0500	[thread overview]
Message-ID: <20261012190245.3988619-3-elder@riscstar.com> (raw)
In-Reply-To: <20261012190245.3988619-1-elder@riscstar.com>

From: Daniel Thompson <daniel@riscstar.com>

Define a new irqchip platform driver that represents the MSIGEN
functionality present in the TC9564 SoC.

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
Co-developed-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Alex Elder <elder@riscstar.com>
---
 MAINTAINERS                         |   1 +
 drivers/irqchip/Kconfig             |  10 ++
 drivers/irqchip/Makefile            |   1 +
 drivers/irqchip/irq-tc9564-msigen.c | 203 ++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+)
 create mode 100644 drivers/irqchip/irq-tc9564-msigen.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9e73a912f0c0f..5b0ed7c1ab40a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -28178,6 +28178,7 @@ M:	Alex Elder <elder@kernel.org>
 M:	Daniel Thompson <danielt@kernel.org>
 S:	Maintained
 F:	Documentation/devicetree/bindings/interrupt-controller/toshiba,tc9564-msigen.yaml
+F:	drivers/irqchip/irq-tc9564-msigen.c
 
 TOSHIBA TC9564 PCI DRIVER
 M:	Alex Elder <elder@kernel.org>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index a8f8c423b7957..205b5a167c805 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -842,4 +842,14 @@ config SUNPLUS_SP7021_INTC
 	  chained controller, routing all interrupt source in P-Chip to
 	  the primary controller on C-Chip.
 
+config TC9564_MSIGEN
+	tristate "Toshiba TC9564 MSI distributor"
+	depends on TC9564_PCI
+	depends on GENERIC_IRQ_CHIP
+	default TC9564_PCI
+	help
+	  This enables support for the "MSIGEN" MSI distributor embedded
+	  in the Toshiba TC9564.  This device receives wired interrupts
+	  within the TC9564 and raises them to the host using MSI.
+
 endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index ab33cccd84719..c82e00802c2b4 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -135,3 +135,4 @@ obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
 obj-$(CONFIG_MCHP_EIC)			+= irq-mchp-eic.o
 obj-$(CONFIG_SOPHGO_SG2042_MSI)		+= irq-sg2042-msi.o
 obj-$(CONFIG_SUNPLUS_SP7021_INTC)	+= irq-sp7021-intc.o
+obj-$(CONFIG_TC9564_MSIGEN)		+= irq-tc9564-msigen.o
diff --git a/drivers/irqchip/irq-tc9564-msigen.c b/drivers/irqchip/irq-tc9564-msigen.c
new file mode 100644
index 0000000000000..a27edd5859e43
--- /dev/null
+++ b/drivers/irqchip/irq-tc9564-msigen.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/clk.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+/**
+ * struct tc9564_msigen - Context for MSIGEN IRQ domain
+ * @ioaddr:	Pointer to mapped MSIGEN memory
+ * @irq:	IRQ number for MSIGEN
+ */
+struct tc9564_msigen {
+	void __iomem *ioaddr;
+	unsigned int irq;
+};
+
+#define HWIRQ_COUNT			25
+
+#define MSI_OUT_EN_OFFSET		0x0000
+#define MSI_MASK_CLR_OFFSET		0x000c
+#define MSI_MASK_VALUE			BIT(0)
+#define MSI_INT_STS_OFFSET		0x0010
+
+static void tc9564_msigen_irq_handler(struct irq_desc *desc)
+{
+	struct irq_domain *irq_domain = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct irq_chip_generic *gc;
+	unsigned long status;
+	unsigned long hwirq;
+
+	gc = irq_get_domain_generic_chip(irq_domain, 0);
+
+	chained_irq_enter(chip, desc);
+
+	status = irq_reg_readl(gc, MSI_INT_STS_OFFSET);
+	for_each_set_bit(hwirq, &status, HWIRQ_COUNT)
+		generic_handle_domain_irq(irq_domain, hwirq);
+
+	/*
+	 * Clear the MSI flag. Most interrupts within TC9564 are level-high
+	 * type. If any interrupts are still asserted then clearing this flag
+	 * will cause the (edge-triggered) MSI to be regenerated.
+	 */
+	irq_reg_writel(gc, MSI_MASK_VALUE, MSI_MASK_CLR_OFFSET);
+
+	chained_irq_exit(chip, desc);
+}
+
+static int tc9564_msigen_irq_chip_init(struct irq_chip_generic *gc)
+{
+	struct tc9564_msigen *msigen = gc->domain->host_data;
+
+	gc->reg_base = msigen->ioaddr;
+	gc->chip_types[0].regs.mask = MSI_OUT_EN_OFFSET;
+	gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+	gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+	/* Disable all interrupts */
+	irq_reg_writel(gc, 0, MSI_OUT_EN_OFFSET);
+
+	return 0;
+}
+
+static void tc9564_msigen_irq_chip_exit(struct irq_chip_generic *gc)
+{
+	irq_reg_writel(gc, 0, MSI_OUT_EN_OFFSET);
+}
+
+static int tc9564_msigen_irq_domain_init(struct irq_domain *irq_domain)
+{
+	struct tc9564_msigen *msigen = irq_domain->host_data;
+
+	irq_set_chained_handler_and_data(msigen->irq, tc9564_msigen_irq_handler,
+					 irq_domain);
+	return 0;
+}
+
+static void tc9564_msigen_irq_domain_exit(struct irq_domain *irq_domain)
+{
+	struct tc9564_msigen *msigen = irq_domain->host_data;
+
+	irq_set_chained_handler_and_data(msigen->irq, NULL, NULL);
+}
+
+/* Find the PCI device we're associated with (not necessarily the parent) */
+static struct pci_dev *tc9564_msigen_find_pci_dev(struct device *dev)
+{
+	struct device *ancestor;
+
+	for (ancestor = dev->parent; ancestor; ancestor = ancestor->parent) {
+		if (dev_is_pci(ancestor)) {
+			/* We currently only support physical functions */
+			if (!dev_is_pf(ancestor))
+				return ERR_PTR(-EINVAL);
+
+			return to_pci_dev(ancestor);
+		}
+	}
+
+	return ERR_PTR(-ENXIO);
+}
+
+static void tc9564_msigen_free_irq_vectors(void *pci_dev)
+{
+	pci_free_irq_vectors(pci_dev);
+}
+
+static int tc9564_msigen_probe(struct platform_device *pdev)
+{
+	struct irq_domain_chip_generic_info dgc_info;
+	struct device *dev = &pdev->dev;
+	struct irq_domain *irq_domain;
+	struct tc9564_msigen *msigen;
+	struct irq_domain_info info;
+	struct reset_control *reset;
+	struct pci_dev *pci_dev;
+	struct clk *clk;
+	int ret;
+
+	pci_dev = tc9564_msigen_find_pci_dev(dev);
+	if (IS_ERR(pci_dev))
+		return dev_err_probe(dev, PTR_ERR(pci_dev),
+				     "failed to find PCI device\n");
+
+	msigen = devm_kzalloc(dev, sizeof(*msigen), GFP_KERNEL);
+	if (!msigen)
+		return -ENOMEM;
+
+	msigen->ioaddr = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(msigen->ioaddr))
+		return dev_err_probe(dev, PTR_ERR(msigen->ioaddr),
+				     "failed to map registers\n");
+
+	clk = devm_clk_get_enabled(dev, NULL);
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk),
+				     "failed to get/enable clock\n");
+
+	reset = devm_reset_control_get_shared_deasserted(dev, NULL);
+	if (IS_ERR(reset))
+		return dev_err_probe(dev, PTR_ERR(reset),
+				     "failed to get/deassert reset\n");
+
+	ret = pci_alloc_irq_vectors(pci_dev, 1, 1, PCI_IRQ_MSI);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to alloc irq vector\n");
+
+	ret = devm_add_action_or_reset(dev, tc9564_msigen_free_irq_vectors,
+				       pci_dev);
+	if (ret)
+		return ret;
+
+	msigen->irq = pci_irq_vector(pci_dev, 0);
+
+	dgc_info.name = "tc9564-msigen";
+	dgc_info.handler = handle_level_irq;
+	dgc_info.irqs_per_chip = HWIRQ_COUNT;
+	dgc_info.num_ct = 1;
+	dgc_info.init = tc9564_msigen_irq_chip_init;
+	dgc_info.exit = tc9564_msigen_irq_chip_exit;
+
+	info.fwnode = of_fwnode_handle(dev->of_node);
+	info.domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC;
+	info.size = HWIRQ_COUNT;
+	info.hwirq_max = HWIRQ_COUNT;
+	info.ops = &irq_generic_chip_ops;
+	info.host_data = msigen;
+	info.dgc_info = &dgc_info;
+	info.init = tc9564_msigen_irq_domain_init;
+	info.exit = tc9564_msigen_irq_domain_exit;
+
+	irq_domain = devm_irq_domain_instantiate(dev, &info);
+	if (IS_ERR(irq_domain))
+		return dev_err_probe(dev, PTR_ERR(irq_domain),
+				     "failed to instantiate IRQ domain\n");
+
+	return 0;
+}
+
+static const struct of_device_id tc9564_msigen_of_match[] = {
+	{ .compatible = "toshiba,tc9564-msigen" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tc9564_msigen_of_match);
+
+static struct platform_driver tc9564_msigen_driver = {
+	.probe = tc9564_msigen_probe,
+	.driver = {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= tc9564_msigen_of_match,
+	},
+};
+module_platform_driver(tc9564_msigen_driver);
+
+MODULE_AUTHOR("Daniel Thompson <danielt@kernel.org>");
+MODULE_DESCRIPTION("TC9564 MSIGEN IRQ Controller Driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0


  parent reply	other threads:[~2026-10-12 19:02 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-12 19:02 [PATCH 0/2] irqchip: add TC9564 support Alex Elder
2026-10-12 19:02 ` [PATCH 1/2] dt-bindings: interrupt-controller: introduce toshiba,tc9564-msigen.yaml Alex Elder
2026-10-12 19:07   ` sashiko-bot
2026-10-12 19:22     ` Alex Elder
2026-10-12 19:02 ` Alex Elder [this message]
2026-10-12 19:16   ` [PATCH 2/2] irqchip: introduce TC9564 SoC MSIGEN support sashiko-bot
2026-10-12 20:08     ` Alex Elder

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261012190245.3988619-3-elder@riscstar.com \
    --to=elder@riscstar.com \
    --cc=conor+dt@kernel.org \
    --cc=daniel@riscstar.com \
    --cc=danielt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lorenzo.bianconi@oss.qualcomm.com \
    --cc=mohd.anwar@oss.qualcomm.com \
    --cc=p.zabel@pengutronix.de \
    --cc=radu@rendec.net \
    --cc=robh@kernel.org \
    --cc=tglx@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.