lkml.org 
[lkml]   [2015]   [Oct]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[tip:irq/core] irqchip/mxs: Prepare driver for hardware with different offsets
Commit-ID:  25e34b44313b61d7a87819498ccfd0129441604a
Gitweb: http://git.kernel.org/tip/25e34b44313b61d7a87819498ccfd0129441604a
Author: Oleksij Rempel <linux@rempel-privat.de>
AuthorDate: Mon, 12 Oct 2015 21:15:33 +0200
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Wed, 14 Oct 2015 09:37:47 +0200

irqchip/mxs: Prepare driver for hardware with different offsets

Alphascale asm9260 has similar functionality but different register
offsets. To support asm9260 in the mxs driver we need to rework the
hardcoded access mechanisms.

- Define SET_REG and CLR_REG. These controllers support seperate CLR and
SET offsets for each register.

- Reimplement HW_ICOLL_INTERRUPT with SET_REG and CLR_REG to make it
usable for both cases.

- Instead of using icoll_base and adding the offsets at runtime,
create a new data structure which contains base pointers to all
required regitsters and use it.

- Split out functionality, which is required for the init code of mxs
and asm9260, into helper functions

[ tglx: Massaged changelog and moved the return value change to the
previous patch ]

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Tested-by: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: marc.zyngier@arm.com
Cc: jason@lakedaemon.net
Link: http://lkml.kernel.org/r/1444677334-12242-5-git-send-email-linux@rempel-privat.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
drivers/irqchip/irq-mxs.c | 78 +++++++++++++++++++++++++++++++++++------------
1 file changed, 59 insertions(+), 19 deletions(-)

diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 96148a7..eaab5a6 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -28,18 +28,36 @@
#include <linux/stmp_device.h>
#include <asm/exception.h>

+/*
+ * this device provide 4 offsets for each register:
+ * 0x0 - plain read write mode
+ * 0x4 - set mode, OR logic.
+ * 0x8 - clr mode, XOR logic.
+ * 0xc - togle mode.
+ */
+#define SET_REG 4
+#define CLR_REG 8
+
#define HW_ICOLL_VECTOR 0x0000
#define HW_ICOLL_LEVELACK 0x0010
#define HW_ICOLL_CTRL 0x0020
#define HW_ICOLL_STAT_OFFSET 0x0070
-#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10)
-#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10)
-#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004
+#define HW_ICOLL_INTERRUPT0 0x0120
+#define HW_ICOLL_INTERRUPTn(n) ((n) * 0x10)
+#define BM_ICOLL_INTR_ENABLE BIT(2)
#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1

#define ICOLL_NUM_IRQS 128

-static void __iomem *icoll_base;
+struct icoll_priv {
+ void __iomem *vector;
+ void __iomem *levelack;
+ void __iomem *ctrl;
+ void __iomem *stat;
+ void __iomem *intr;
+};
+
+static struct icoll_priv icoll_priv;
static struct irq_domain *icoll_domain;

static void icoll_ack_irq(struct irq_data *d)
@@ -50,19 +68,19 @@ static void icoll_ack_irq(struct irq_data *d)
* BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally.
*/
__raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0,
- icoll_base + HW_ICOLL_LEVELACK);
+ icoll_priv.levelack);
}

static void icoll_mask_irq(struct irq_data *d)
{
- __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
- icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->hwirq));
+ __raw_writel(BM_ICOLL_INTR_ENABLE,
+ icoll_priv.intr + CLR_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
}

static void icoll_unmask_irq(struct irq_data *d)
{
- __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
- icoll_base + HW_ICOLL_INTERRUPTn_SET(d->hwirq));
+ __raw_writel(BM_ICOLL_INTR_ENABLE,
+ icoll_priv.intr + SET_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
}

static struct irq_chip mxs_icoll_chip = {
@@ -75,8 +93,8 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
{
u32 irqnr;

- irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
- __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
+ irqnr = __raw_readl(icoll_priv.stat);
+ __raw_writel(irqnr, icoll_priv.vector);
handle_domain_irq(icoll_domain, irqnr, regs);
}

@@ -93,23 +111,45 @@ static const struct irq_domain_ops icoll_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};

-static int __init icoll_of_init(struct device_node *np,
- struct device_node *interrupt_parent)
+static void __init icoll_add_domain(struct device_node *np,
+ int num)
+{
+ icoll_domain = irq_domain_add_linear(np, num,
+ &icoll_irq_domain_ops, NULL);
+
+ if (!icoll_domain)
+ panic("%s: unable to create irq domain", np->full_name);
+}
+
+static void __iomem * __init icoll_init_iobase(struct device_node *np)
{
- icoll_base = of_iomap(np, 0);
+ void __iomem *icoll_base;
+
+ icoll_base = of_io_request_and_map(np, 0, np->name);
if (!icoll_base)
panic("%s: unable to map resource", np->full_name);
+ return icoll_base;
+}
+
+static int __init icoll_of_init(struct device_node *np,
+ struct device_node *interrupt_parent)
+{
+ void __iomem *icoll_base;
+
+ icoll_base = icoll_init_iobase(np);
+ icoll_priv.vector = icoll_base + HW_ICOLL_VECTOR;
+ icoll_priv.levelack = icoll_base + HW_ICOLL_LEVELACK;
+ icoll_priv.ctrl = icoll_base + HW_ICOLL_CTRL;
+ icoll_priv.stat = icoll_base + HW_ICOLL_STAT_OFFSET;
+ icoll_priv.intr = icoll_base + HW_ICOLL_INTERRUPT0;

/*
* Interrupt Collector reset, which initializes the priority
* for each irq to level 0.
*/
- stmp_reset_block(icoll_base + HW_ICOLL_CTRL);
+ stmp_reset_block(icoll_priv.ctrl);

- icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
- &icoll_irq_domain_ops, NULL);
- if (!icoll_domain)
- panic("%s: unable to create irqdomain", np->full_name);
+ icoll_add_domain(np, ICOLL_NUM_IRQS);

return 0;
}

\
 
 \ /
  Last update: 2015-10-14 10:01    [W:0.060 / U:0.648 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site