Signed-off-by: Guo Ren <[email protected]>
---
 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

Reply via email to