All of lore.kernel.org
 help / color / mirror / Atom feed
From: joel@jms.id.au (Joel Stanley)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 05/11] irqchip: Add irq controller for Aspeed
Date: Thu, 21 Apr 2016 17:34:03 +0930	[thread overview]
Message-ID: <1461225849-28074-6-git-send-email-joel@jms.id.au> (raw)
In-Reply-To: <1461225849-28074-1-git-send-email-joel@jms.id.au>

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
 drivers/irqchip/Makefile         |   1 +
 drivers/irqchip/irq-aspeed-vic.c | 238 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 239 insertions(+)
 create mode 100644 drivers/irqchip/irq-aspeed-vic.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index b03cfcbbac6b..ec82e6e15a38 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -65,3 +65,4 @@ obj-$(CONFIG_INGENIC_IRQ)		+= irq-ingenic.o
 obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
 obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
 obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
+obj-$(CONFIG_ARCH_ASPEED)		+= irq-aspeed-vic.o
diff --git a/drivers/irqchip/irq-aspeed-vic.c b/drivers/irqchip/irq-aspeed-vic.c
new file mode 100644
index 000000000000..db15fc3e831a
--- /dev/null
+++ b/drivers/irqchip/irq-aspeed-vic.c
@@ -0,0 +1,238 @@
+/*
+ *  Copyright (C) 2015 - Ben Herrenschmidt, IBM Corp.
+ *
+ *  Driver for Aspeed "new" VIC as found in SoC generation 3 and later
+ *
+ *  Based on irq-vic.c:
+ *
+ *  Copyright (C) 1999 - 2003 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/syscore_ops.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include <asm/exception.h>
+#include <asm/irq.h>
+
+/* These definitions correspond to the "new mapping" of the
+ * register set that interleaves "high" and "low". The offsets
+ * below are for the "low" register, add 4 to get to the high one
+ */
+#define AVIC_IRQ_STATUS		0x00
+#define AVIC_FIQ_STATUS		0x08
+#define AVIC_RAW_STATUS		0x10
+#define AVIC_INT_SELECT		0x18
+#define AVIC_INT_ENABLE		0x20
+#define AVIC_INT_ENABLE_CLR	0x28
+#define AVIC_INT_TRIGGER	0x30
+#define AVIC_INT_TRIGGER_CLR	0x38
+#define AVIC_INT_SENSE		0x40
+#define AVIC_INT_DUAL_EDGE	0x48
+#define AVIC_INT_EVENT		0x50
+#define AVIC_EDGE_CLR		0x58
+#define AVIC_EDGE_STATUS	0x60
+
+struct aspeed_vic {
+	void __iomem		*base;
+	u32			valid_sources[2];
+	u32			edge_sources[2];
+	struct irq_domain	*dom;
+};
+static struct aspeed_vic *system_avic;
+
+static void vic_init_hw(struct aspeed_vic *vic)
+{
+	u32 sense;
+
+	/* Disable all interrupts */
+	writel(0xffffffff, vic->base + AVIC_INT_ENABLE_CLR);
+	writel(0xffffffff, vic->base + AVIC_INT_ENABLE_CLR + 4);
+
+	/* Make sure no soft trigger is on */
+	writel(0xffffffff, vic->base + AVIC_INT_TRIGGER_CLR);
+	writel(0xffffffff, vic->base + AVIC_INT_TRIGGER_CLR + 4);
+
+	/* Set everything to be IRQ */
+	writel(0, vic->base + AVIC_INT_SELECT);
+	writel(0, vic->base + AVIC_INT_SELECT + 4);
+
+	/* Some interrupts have a programable high/low level trigger
+	 * (4 GPIO direct inputs), for now we assume this was configured
+	 * by firmware. We read which ones are edge now.
+	 */
+	sense = readl(vic->base + AVIC_INT_SENSE);
+	vic->edge_sources[0] = ~sense;
+	sense = readl(vic->base + AVIC_INT_SENSE + 4);
+	vic->edge_sources[1] = ~sense;
+
+	/* Clear edge detection latches */
+	writel(0xffffffff, vic->base + AVIC_EDGE_CLR);
+	writel(0xffffffff, vic->base + AVIC_EDGE_CLR + 4);
+}
+
+static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
+{
+	struct aspeed_vic *vic = system_avic;
+	u32 stat, irq;
+
+	for (;;) {
+		irq = 0;
+		stat = readl_relaxed(vic->base + AVIC_IRQ_STATUS);
+		if (!stat) {
+			stat = readl_relaxed(vic->base + AVIC_IRQ_STATUS + 4);
+			irq = 32;
+		}
+		if (stat == 0)
+			break;
+		irq += ffs(stat) - 1;
+		handle_domain_irq(vic->dom, irq, regs);
+	}
+}
+
+static void avic_ack_irq(struct irq_data *d)
+{
+	struct aspeed_vic *vic = irq_data_get_irq_chip_data(d);
+	unsigned int sidx = d->hwirq >> 5;
+	unsigned int sbit = 1u << (d->hwirq & 0x1f);
+
+	/* Clear edge latch for edge interrupts, nop for level */
+	if (vic->edge_sources[sidx] & sbit)
+		writel(sbit, vic->base + AVIC_EDGE_CLR + sidx * 4);
+}
+
+static void avic_mask_irq(struct irq_data *d)
+{
+	struct aspeed_vic *vic = irq_data_get_irq_chip_data(d);
+	unsigned int sidx = d->hwirq >> 5;
+	unsigned int sbit = 1u << (d->hwirq & 0x1f);
+
+	writel(sbit, vic->base + AVIC_INT_ENABLE_CLR + sidx * 4);
+}
+
+static void avic_unmask_irq(struct irq_data *d)
+{
+	struct aspeed_vic *vic = irq_data_get_irq_chip_data(d);
+	unsigned int sidx = d->hwirq >> 5;
+	unsigned int sbit = 1u << (d->hwirq & 0x1f);
+
+	writel(sbit, vic->base + AVIC_INT_ENABLE + sidx * 4);
+}
+
+/* For level irq, faster than going through a nop "ack" and mask */
+static void avic_mask_ack_irq(struct irq_data *d)
+{
+	struct aspeed_vic *vic = irq_data_get_irq_chip_data(d);
+	unsigned int sidx = d->hwirq >> 5;
+	unsigned int sbit = 1u << (d->hwirq & 0x1f);
+
+	/* First mask */
+	writel(sbit, vic->base + AVIC_INT_ENABLE_CLR + sidx * 4);
+
+	/* Then clear edge latch for edge interrupts */
+	if (vic->edge_sources[sidx] & sbit)
+		writel(sbit, vic->base + AVIC_EDGE_CLR + sidx * 4);
+}
+
+static struct irq_chip avic_chip = {
+	.name		= "AVIC",
+	.irq_ack	= avic_ack_irq,
+	.irq_mask	= avic_mask_irq,
+	.irq_unmask	= avic_unmask_irq,
+	.irq_mask_ack	= avic_mask_ack_irq,
+};
+
+static int avic_map(struct irq_domain *d, unsigned int irq,
+		    irq_hw_number_t hwirq)
+{
+	struct aspeed_vic *vic = d->host_data;
+	unsigned int sidx = hwirq >> 5;
+	unsigned int sbit = 1u << (hwirq & 0x1f);
+
+	/* Check if interrupt exists */
+	if (sidx > 1 || !(vic->valid_sources[sidx] & sbit))
+		return -EPERM;
+
+	if (vic->edge_sources[sidx] & sbit)
+		irq_set_chip_and_handler(irq, &avic_chip, handle_edge_irq);
+	else
+		irq_set_chip_and_handler(irq, &avic_chip, handle_level_irq);
+	irq_set_chip_data(irq, vic);
+	irq_set_probe(irq);
+	return 0;
+}
+
+static struct irq_domain_ops avic_dom_ops = {
+	.map = avic_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+static int __init avic_of_init(struct device_node *node,
+			       struct device_node *parent)
+{
+	void __iomem *regs;
+	struct aspeed_vic *vic;
+	int nirqs;
+
+	if (WARN(parent, "non-root Aspeed VIC not supported"))
+		return -EINVAL;
+	if (WARN(system_avic, "duplicate Aspeed VIC not supported"))
+		return -EINVAL;
+
+	regs = of_iomap(node, 0);
+	if (WARN_ON(!regs))
+		return -EIO;
+
+	vic = kzalloc(sizeof(struct aspeed_vic), GFP_KERNEL);
+	if (WARN_ON(!vic)) {
+		iounmap(regs);
+		return -ENOMEM;
+	}
+	vic->base = regs;
+
+	of_property_read_u32_index(node, "valid-sources", 0,
+				   &vic->valid_sources[0]);
+	of_property_read_u32_index(node, "valid-sources", 1,
+				   &vic->valid_sources[1]);
+
+	nirqs = hweight32(vic->valid_sources[0]) +
+		hweight32(vic->valid_sources[1]);
+
+	/* Initialize soures, all masked */
+	vic_init_hw(vic);
+
+	/* Ready to receive interrupts */
+	system_avic = vic;
+	set_handle_irq(avic_handle_irq);
+
+	/* Register our domain */
+	vic->dom = irq_domain_add_simple(node, nirqs, 0,
+					 &avic_dom_ops, vic);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(aspeed_new_vic, "aspeed,ast2400-vic", avic_of_init);
-- 
2.7.4

  parent reply	other threads:[~2016-04-21  8:04 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-14  9:47 [PATCH 0/9] Aspeed AST2400 BMC support Joel Stanley
2016-04-14  9:47 ` Joel Stanley
2016-04-14  9:47 ` [PATCH 1/9] doc/devicetree: Add Aspeed and Tyan to vendor-prefixes Joel Stanley
2016-04-14  9:47 ` [PATCH 2/9] doc/devicetree: Add Aspeed VIC bindings Joel Stanley
2016-04-14  9:47 ` [PATCH 3/9] doc/devicetree: Add Aspeed clock bindings Joel Stanley
2016-04-14  9:47 ` [PATCH 4/9] clocksource/moxart: Generalise timer for use on other socs Joel Stanley
2016-04-14  9:47 ` [PATCH 5/9] irqchip: Add irq controller for Aspeed Joel Stanley
2016-04-14  9:47 ` [PATCH 6/9] drivers/clk: Add Aspeed clock driver Joel Stanley
2016-04-14  9:47 ` [PATCH 7/9] arm/dts: Add aspeed device trees Joel Stanley
2016-04-14  9:47 ` [PATCH 8/9] arm: Add Aspeed AST2400 machine Joel Stanley
2016-04-14  9:47 ` [PATCH 9/9] arm/configs: Add aspeed defconfig Joel Stanley
2016-04-21  8:03 ` [PATCH v2 00/11] Aspeed AST2400 and AST2500 BMC support Joel Stanley
2016-04-21  8:03   ` [PATCH v2 01/11] doc/devicetree: Add Aspeed and Tyan to vendor-prefixes Joel Stanley
2016-04-21  8:04   ` [PATCH v2 02/11] doc/devicetree: Add Aspeed VIC bindings Joel Stanley
2016-04-21  8:04   ` [PATCH v2 03/11] doc/devicetree: Add Aspeed clock bindings Joel Stanley
2016-04-21 11:20     ` Heiko Stübner
2016-04-21 11:20       ` Heiko Stübner
2016-04-27  8:31       ` Joel Stanley
2016-04-27  8:31         ` Joel Stanley
2016-04-27  9:12         ` Heiko Stübner
2016-04-27  9:12           ` Heiko Stübner
2016-04-28  6:50           ` Joel Stanley
2016-04-28  6:50             ` Joel Stanley
2016-04-28  7:25             ` Heiko Stübner
2016-04-28  7:25               ` Heiko Stübner
2016-04-28  8:38           ` Benjamin Herrenschmidt
2016-04-28  8:38             ` Benjamin Herrenschmidt
2016-04-21  8:04   ` [PATCH v2 04/11] clocksource/moxart: Generalise timer for use on other socs Joel Stanley
2016-04-21  8:22     ` Arnd Bergmann
2016-04-22  1:06       ` Joel Stanley
2016-04-22 17:30     ` Daniel Lezcano
2016-04-22 23:55       ` Benjamin Herrenschmidt
2016-05-03  5:56       ` Joel Stanley
2016-05-03 13:36         ` Daniel Lezcano
2016-05-06 14:50           ` Jonas Jensen
2016-04-21  8:04   ` Joel Stanley [this message]
2016-04-21  8:04   ` [PATCH v2 06/11] clk: Add driver for Aspeed fourth gen SoCs Joel Stanley
2016-04-21  8:04   ` [PATCH v2 07/11] clk: Add driver for Aspeed fifth " Joel Stanley
2016-04-21  8:04   ` [PATCH v2 08/11] arm/dts: Add Aspeed ast2400 device tree Joel Stanley
2016-04-21  8:25     ` Arnd Bergmann
2016-04-21  8:04   ` [PATCH v2 09/11] arm/dst: Add Aspeed ast2500 " Joel Stanley
2016-05-05 23:11     ` Xo Wang
2016-05-06  7:28       ` Joel Stanley
2016-04-21  8:04   ` [PATCH v2 10/11] arm: Add Aspeed machine Joel Stanley
2016-04-21  8:35     ` Arnd Bergmann
2016-04-21 22:28       ` Benjamin Herrenschmidt
2016-04-21 23:02         ` Benjamin Herrenschmidt
2016-04-22  5:20           ` Afzal Mohammed
2016-04-22  5:32             ` Joel Stanley
2016-04-22 16:37               ` Arnd Bergmann
2016-04-21  8:04   ` [PATCH v2 11/11] arm/configs: Add aspeed defconfig Joel Stanley
2016-04-21  8:44     ` Arnd Bergmann
2016-04-21  8:54   ` [PATCH v2 00/11] Aspeed AST2400 and AST2500 BMC support Arnd Bergmann

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=1461225849-28074-6-git-send-email-joel@jms.id.au \
    --to=joel@jms.id.au \
    --cc=linux-arm-kernel@lists.infradead.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.