Commit 25e34b44 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by Thomas Gleixner

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: default avatarOleksij Rempel <linux@rempel-privat.de>
Tested-by: default avatarShawn 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.deSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent e59a8451
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment