[PATCH 19/19] irqchip: add irq-nationalchip.c and irq-csky.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Guo Ren <ren_guo@xxxxxxxxx>
---
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-csky.c         | 151 ++++++++++++++++++++++++++++
 drivers/irqchip/irq-nationalchip.c | 196 +++++++++++++++++++++++++++++++++++++
 3 files changed, 348 insertions(+)
 create mode 100644 drivers/irqchip/irq-csky.c
 create mode 100644 drivers/irqchip/irq-nationalchip.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d27e3e3..7b98917 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -85,3 +85,4 @@ obj-$(CONFIG_IRQ_UNIPHIER_AIDET)	+= irq-uniphier-aidet.o
 obj-$(CONFIG_ARCH_SYNQUACER)		+= irq-sni-exiu.o
 obj-$(CONFIG_MESON_IRQ_GPIO)		+= irq-meson-gpio.o
 obj-$(CONFIG_GOLDFISH_PIC) 		+= irq-goldfish-pic.o
+obj-$(CONFIG_CSKY)			+= irq-csky.o irq-nationalchip.o
diff --git a/drivers/irqchip/irq-csky.c b/drivers/irqchip/irq-csky.c
new file mode 100644
index 0000000..77041e3
--- /dev/null
+++ b/drivers/irqchip/irq-csky.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+static unsigned int intc_reg;
+
+#define CK_VA_INTC_ICR		(void *)(intc_reg + 0x00)	/* Interrupt control register(High 16bits) */
+#define CK_VA_INTC_ISR		(void *)(intc_reg + 0x00)	/* Interrupt status register(Low 16bits) */
+#define CK_VA_INTC_NEN31_00	(void *)(intc_reg + 0x10)	/* Normal interrupt enable register Low */
+#define	CK_VA_INTC_NEN63_32	(void *)(intc_reg + 0x28)	/* Normal interrupt enable register High */
+#define CK_VA_INTC_IFR31_00	(void *)(intc_reg + 0x08)	/* Normal interrupt force register Low */
+#define CK_VA_INTC_IFR63_32	(void *)(intc_reg + 0x20)	/* Normal interrupt force register High */
+#define	CK_VA_INTC_SOURCE	(void *)(intc_reg + 0x40)	/* Proiority Level Select Registers 0 */
+
+static void ck_irq_mask(struct irq_data *d)
+{
+	unsigned int temp, irq;
+
+	irq = d->irq;
+
+	if (irq < 32) {
+		temp = __raw_readl(CK_VA_INTC_NEN31_00);
+		temp &= ~(1 << irq);
+		__raw_writel(temp, CK_VA_INTC_NEN31_00);
+	} else {
+		temp = __raw_readl(CK_VA_INTC_NEN63_32);
+		temp &= ~(1 << (irq -32));
+		__raw_writel(temp, CK_VA_INTC_NEN63_32);
+	}
+}
+
+static void ck_irq_unmask(struct irq_data *d)
+{
+	unsigned int temp, irq;
+
+	irq = d->irq;
+
+	/* set IFR to support rising edge triggering */
+	if (irq < 32) {
+		temp = __raw_readl(CK_VA_INTC_IFR31_00);
+		temp &= ~(1 << irq);
+		__raw_writel(temp, CK_VA_INTC_IFR31_00);
+	} else {
+		temp = __raw_readl(CK_VA_INTC_IFR63_32);
+		temp &= ~(1 << (irq -32));
+		__raw_writel(temp, CK_VA_INTC_IFR63_32);
+	}
+
+	if (irq < 32) {
+		temp = __raw_readl(CK_VA_INTC_NEN31_00);
+		temp |= 1 << irq;
+		__raw_writel(temp, CK_VA_INTC_NEN31_00);
+	} else {
+		temp = __raw_readl(CK_VA_INTC_NEN63_32);
+		temp |= 1 << (irq -32);
+		__raw_writel(temp, CK_VA_INTC_NEN63_32);
+	}
+}
+
+static struct irq_chip ck_irq_chip = {
+	.name		= "csky_intc_v1",
+	.irq_mask	= ck_irq_mask,
+	.irq_unmask	= ck_irq_unmask,
+};
+
+static int ck_irq_map(struct irq_domain *h, unsigned int virq,
+				irq_hw_number_t hw_irq_num)
+{
+	irq_set_chip_and_handler(virq, &ck_irq_chip, handle_level_irq);
+	return 0;
+}
+
+static const struct irq_domain_ops ck_irq_ops = {
+	.map	= ck_irq_map,
+	.xlate	= irq_domain_xlate_onecell,
+};
+
+static unsigned int ck_get_irqno(void)
+{
+	unsigned int temp;
+	temp = __raw_readl(CK_VA_INTC_ISR);
+	return temp & 0x3f;
+};
+
+static int __init
+__intc_init(struct device_node *np, struct device_node *parent, bool ave)
+{
+	struct irq_domain *root_domain;
+	int i;
+
+	csky_get_auto_irqno = ck_get_irqno;
+
+	if (parent)
+		panic("pic not a root intc\n");
+
+	intc_reg = (unsigned int)of_iomap(np, 0);
+	if (!intc_reg)
+		panic("%s, of_iomap err.\n", __func__);
+
+	__raw_writel(0, CK_VA_INTC_NEN31_00);
+	__raw_writel(0,	CK_VA_INTC_NEN63_32);
+
+	if (ave == true)
+		__raw_writel( 0xc0000000, CK_VA_INTC_ICR);
+	else
+		__raw_writel( 0x0, CK_VA_INTC_ICR);
+	/*
+	 * csky irq ctrl has 64 sources.
+	 */
+	#define INTC_IRQS 64
+	for (i=0; i<INTC_IRQS; i=i+4)
+		__raw_writel((i+3)|((i+2)<<8)|((i+1)<<16)|(i<<24),
+				CK_VA_INTC_SOURCE + i);
+
+	root_domain = irq_domain_add_legacy(np, INTC_IRQS, 0, 0, &ck_irq_ops, NULL);
+	if (!root_domain)
+		panic("root irq domain not available\n");
+
+	irq_set_default_host(root_domain);
+
+	return 0;
+}
+
+static int __init
+intc_init(struct device_node *np, struct device_node *parent)
+{
+
+	return __intc_init(np, parent, false);
+}
+IRQCHIP_DECLARE(csky_intc_v1, "csky,intc-v1", intc_init);
+
+/*
+ * use auto vector exceptions 10 for interrupt.
+ */
+static int __init
+intc_init_ave(struct device_node *np, struct device_node *parent)
+{
+	return __intc_init(np, parent, true);
+}
+IRQCHIP_DECLARE(csky_intc_v1_ave, "csky,intc-v1,ave", intc_init_ave);
+
diff --git a/drivers/irqchip/irq-nationalchip.c b/drivers/irqchip/irq-nationalchip.c
new file mode 100644
index 0000000..8c09ebd
--- /dev/null
+++ b/drivers/irqchip/irq-nationalchip.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou NationalChip Science & Technology Co.,Ltd.
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#define NC_VA_INTC_NINT31_00		(void *)(intc_reg + 0x00)
+#define NC_VA_INTC_NINT63_32		(void *)(intc_reg + 0x04)
+#define NC_VA_INTC_NPEND31_00		(void *)(intc_reg + 0x10)
+#define NC_VA_INTC_NPEND63_32		(void *)(intc_reg + 0x14)
+#define NC_VA_INTC_NENSET31_00		(void *)(intc_reg + 0x20)
+#define NC_VA_INTC_NENSET63_32		(void *)(intc_reg + 0x24)
+#define NC_VA_INTC_NENCLR31_00		(void *)(intc_reg + 0x30)
+#define NC_VA_INTC_NENCLR63_32		(void *)(intc_reg + 0x34)
+#define NC_VA_INTC_NEN31_00		(void *)(intc_reg + 0x40)
+#define NC_VA_INTC_NEN63_32		(void *)(intc_reg + 0x44)
+#define NC_VA_INTC_NMASK31_00		(void *)(intc_reg + 0x50)
+#define NC_VA_INTC_NMASK63_32		(void *)(intc_reg + 0x54)
+#define NC_VA_INTC_SOURCE		(void *)(intc_reg + 0x60)
+
+static unsigned int intc_reg;
+
+static void nc_irq_mask(struct irq_data *d)
+{
+	unsigned int mask, irq;
+
+	irq = d->irq;
+
+	if (irq < 32) {
+		mask = __raw_readl(NC_VA_INTC_NMASK31_00);
+		mask |= 1 << irq;
+		__raw_writel(mask, NC_VA_INTC_NMASK31_00);
+	} else {
+		mask = __raw_readl(NC_VA_INTC_NMASK63_32);
+		mask |= 1 << (irq - 32);
+		__raw_writel(mask, NC_VA_INTC_NMASK63_32);
+	}
+}
+
+static void nc_irq_unmask(struct irq_data *d)
+{
+	unsigned int mask, irq;
+
+	irq = d->irq;
+
+	if (irq < 32) {
+		mask = __raw_readl(NC_VA_INTC_NMASK31_00);
+		mask &= ~( 1 << irq);
+		__raw_writel(mask, NC_VA_INTC_NMASK31_00);
+	} else {
+		mask = __raw_readl( NC_VA_INTC_NMASK63_32);
+		mask &= ~(1 << (irq - 32));
+		__raw_writel(mask, NC_VA_INTC_NMASK63_32);
+	}
+}
+
+static void nc_irq_en(struct irq_data *d)
+{
+	unsigned int mask, irq;
+
+	irq = d->irq;
+
+	if (irq < 32) {
+		mask = 1 << irq;
+		__raw_writel(mask, NC_VA_INTC_NENSET31_00);
+	} else {
+		mask = 1 << (irq - 32);
+		__raw_writel(mask, NC_VA_INTC_NENSET63_32);
+	}
+
+	nc_irq_unmask(d);
+}
+
+static void nc_irq_dis(struct irq_data *d)
+{
+	unsigned int mask, irq;
+
+	irq = d->irq;
+
+	if (irq < 32) {
+		mask = 1 << irq;
+		__raw_writel(mask, NC_VA_INTC_NENCLR31_00);
+	} else {
+		mask = 1 << (irq - 32);
+		__raw_writel(mask, NC_VA_INTC_NENCLR63_32);
+	}
+
+	nc_irq_mask(d);
+}
+
+struct irq_chip nc_irq_chip = {
+	.name =		"nationalchip_intc_v1",
+	.irq_mask =	nc_irq_mask,
+	.irq_unmask =	nc_irq_unmask,
+	.irq_enable =	nc_irq_en,
+	.irq_disable =	nc_irq_dis,
+};
+
+inline int ff1_64(unsigned int hi, unsigned int lo)
+{
+	int result;
+	asm volatile(
+		"ff1 %0\n"
+		:"=r"(hi)
+		:"r"(hi)
+		:
+	);
+
+	asm volatile(
+		"ff1 %0\n"
+		:"=r"(lo)
+		:"r"(lo)
+		:
+	);
+	if( lo != 32 )
+		result = 31-lo;
+	else if( hi != 32 ) result = 31-hi + 32;
+	else {
+		printk("nc_get_irqno error hi:%x, lo:%x.\n", hi, lo);
+		result = NR_IRQS;
+	}
+	return result;
+}
+
+unsigned int nc_get_irqno(void)
+{
+	unsigned int nint64hi, nint64lo, irq_no;
+
+	nint64lo = __raw_readl(NC_VA_INTC_NINT31_00);
+	nint64hi = __raw_readl(NC_VA_INTC_NINT63_32);
+	irq_no = ff1_64(nint64hi, nint64lo);
+
+	return irq_no;
+}
+
+static int irq_map(struct irq_domain *h, unsigned int virq,
+				irq_hw_number_t hw_irq_num)
+{
+	irq_set_chip_and_handler(virq, &nc_irq_chip, handle_level_irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops nc_irq_ops = {
+	.map	= irq_map,
+	.xlate	= irq_domain_xlate_onecell,
+};
+
+static int __init
+intc_init(struct device_node *intc, struct device_node *parent)
+{
+	struct irq_domain *root_domain;
+	unsigned int i;
+
+	if (parent)
+		panic("DeviceTree incore intc not a root irq controller\n");
+
+	csky_get_auto_irqno = nc_get_irqno;
+
+	intc_reg = (unsigned int) of_iomap(intc, 0);
+	if (!intc_reg)
+		panic("Nationalchip Intc Reg: %x.\n", intc_reg);
+
+	__raw_writel(0xffffffff, NC_VA_INTC_NENCLR31_00);
+	__raw_writel(0xffffffff, NC_VA_INTC_NENCLR63_32);
+	__raw_writel(0xffffffff, NC_VA_INTC_NMASK31_00);
+	__raw_writel(0xffffffff, NC_VA_INTC_NMASK63_32);
+
+	/*
+	 * nationalchip irq ctrl has 64 sources.
+	 */
+	#define INTC_IRQS 64
+	for (i=0; i<INTC_IRQS; i=i+4)
+		__raw_writel(i|((i+1)<<8)|((i+2)<<16)|((i+3)<<24),
+				NC_VA_INTC_SOURCE + i);
+
+	root_domain = irq_domain_add_legacy(intc, INTC_IRQS, 0, 0,
+			&nc_irq_ops, NULL);
+	if (!root_domain)
+		panic("root irq domain not avail\n");
+
+	irq_set_default_host(root_domain);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(nationalchip_intc_v1_ave, "nationalchip,intc-v1,ave", intc_init);
+
-- 
2.7.4




[Index of Archives]     [Linux Kernel]     [Kernel Newbies]     [x86 Platform Driver]     [Netdev]     [Linux Wireless]     [Netfilter]     [Bugtraq]     [Linux Filesystems]     [Yosemite Discussion]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]

  Powered by Linux