From 87c56d35e6c63ba38b5b4332a6e80d4eff360370 Mon Sep 17 00:00:00 2001
From: handsomeyingyan <handsomeyingyan@github.com>
Date: Sat, 1 May 2021 21:17:35 +0800
Subject: [PATCH 03/17] LIOINTC: Support hw 2.0

---
 drivers/irqchip/irq-loongson-liointc.c | 57 +++++++++++++++++++++++---
 1 file changed, 51 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c
index 9ed1bc473..5feed1421 100644
--- a/drivers/irqchip/irq-loongson-liointc.c
+++ b/drivers/irqchip/irq-loongson-liointc.c
@@ -20,6 +20,7 @@
 
 #define LIOINTC_CHIP_IRQ	32
 #define LIOINTC_NUM_PARENT 4
+#define LIOINTC_NUM_CORES	4
 
 #define LIOINTC_INTC_CHIP_START	0x20
 
@@ -42,8 +43,10 @@ struct liointc_handler_data {
 struct liointc_priv {
 	struct irq_chip_generic		*gc;
 	struct liointc_handler_data	handler[LIOINTC_NUM_PARENT];
+	void __iomem			*core_isr[LIOINTC_NUM_CORES];
 	u8				map_cache[LIOINTC_CHIP_IRQ];
 	bool				has_lpc_irq_errata;
+	bool				has_per_core_isr;
 };
 
 static void liointc_chained_handle_irq(struct irq_desc *desc)
@@ -51,11 +54,12 @@ static void liointc_chained_handle_irq(struct irq_desc *desc)
 	struct liointc_handler_data *handler = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct irq_chip_generic *gc = handler->priv->gc;
+	int core = get_ebase_cpunum() % LIOINTC_NUM_CORES;
 	u32 pending;
 
 	chained_irq_enter(chip, desc);
 
-	pending = readl(gc->reg_base + LIOINTC_REG_INTC_STATUS);
+	pending = readl(handler->priv->core_isr[core]);
 
 	if (!pending) {
 		/* Always blame LPC IRQ if we have that bug */
@@ -141,6 +145,14 @@ static void liointc_resume(struct irq_chip_generic *gc)
 }
 
 static const char * const parent_names[] = {"int0", "int1", "int2", "int3"};
+static const char * const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"};
+
+static void __iomem *liointc_get_reg_byname(struct device_node *node,
+						const char *name)
+{
+	int index = of_property_match_string(node, "reg-names", name);
+	return of_iomap(node, index);
+}
 
 int __init liointc_of_init(struct device_node *node,
 				struct device_node *parent)
@@ -159,12 +171,36 @@ int __init liointc_of_init(struct device_node *node,
 	if (!priv)
 		return -ENOMEM;
 
-	base = of_iomap(node, 0);
+	if (of_device_is_compatible(node, "loongson,liointc-2.0"))
+		priv->has_per_core_isr = true;
+
+	if (!priv->has_per_core_isr)
+		base = of_iomap(node, 0);
+	else
+		base = liointc_get_reg_byname(node, "main");
+
 	if (!base) {
 		err = -ENODEV;
 		goto out_free_priv;
 	}
 
+	if (!priv->has_per_core_isr) {
+		for (i = 0; i < LIOINTC_NUM_CORES; i++) {
+			priv->core_isr[i] =
+				base + LIOINTC_REG_INTC_STATUS;
+		}
+	} else {
+		for (i = 0; i < LIOINTC_NUM_CORES; i++) {
+			priv->core_isr[i] =
+				liointc_get_reg_byname(node, core_reg_names[i]);
+		}
+		if (!priv->core_isr[0]) {
+			err = -ENODEV;
+			goto out_iounmap_base;	
+		}
+
+	}
+
 	for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
 		parent_irq[i] = of_irq_get_byname(node, parent_names[i]);
 		if (parent_irq[i] > 0)
@@ -172,7 +208,7 @@ int __init liointc_of_init(struct device_node *node,
 	}
 	if (!have_parent) {
 		err = -ENODEV;
-		goto out_iounmap;
+		goto out_iounmap_isr;
 	}
 
 	sz = of_property_read_variable_u32_array(node,
@@ -183,7 +219,7 @@ int __init liointc_of_init(struct device_node *node,
 	if (sz < 4) {
 		pr_err("loongson-liointc: No parent_int_map\n");
 		err = -ENODEV;
-		goto out_iounmap;
+		goto out_iounmap_isr;
 	}
 
 	for (i = 0; i < LIOINTC_NUM_PARENT; i++)
@@ -195,7 +231,7 @@ int __init liointc_of_init(struct device_node *node,
 	if (!domain) {
 		pr_err("loongson-liointc: cannot add IRQ domain\n");
 		err = -EINVAL;
-		goto out_iounmap;
+		goto out_iounmap_isr;
 	}
 
 	err = irq_alloc_domain_generic_chips(domain, 32, 1,
@@ -260,7 +296,15 @@ int __init liointc_of_init(struct device_node *node,
 
 out_free_domain:
 	irq_domain_remove(domain);
-out_iounmap:
+out_iounmap_isr:
+	if (priv->has_per_core_isr) {
+		for (i = 0; i < LIOINTC_NUM_CORES; i++) {
+			if (!priv->core_isr[i])
+				continue;
+			iounmap(priv->core_isr[i]);
+		}
+	}
+out_iounmap_base:
 	iounmap(base);
 out_free_priv:
 	kfree(priv);
@@ -270,3 +314,4 @@ int __init liointc_of_init(struct device_node *node,
 
 IRQCHIP_DECLARE(loongson_liointc_1_0, "loongson,liointc-1.0", liointc_of_init);
 IRQCHIP_DECLARE(loongson_liointc_1_0a, "loongson,liointc-1.0a", liointc_of_init);
+IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init); 
-- 
2.17.1

