summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-mxs.c
diff options
context:
space:
mode:
authorOleksij Rempel <linux@rempel-privat.de>2015-10-12 15:15:33 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-10-14 03:37:47 -0400
commit25e34b44313b61d7a87819498ccfd0129441604a (patch)
tree06c4e9632efdda8e1122bba41fde5a0069a8fb82 /drivers/irqchip/irq-mxs.c
parente59a8451be1162d5a10a33e40092f1796cb8fdca (diff)
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>
Diffstat (limited to 'drivers/irqchip/irq-mxs.c')
-rw-r--r--drivers/irqchip/irq-mxs.c78
1 files changed, 59 insertions, 19 deletions
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 96148a7beba1..eaab5a67e536 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -28,18 +28,36 @@
28#include <linux/stmp_device.h> 28#include <linux/stmp_device.h>
29#include <asm/exception.h> 29#include <asm/exception.h>
30 30
31/*
32 * this device provide 4 offsets for each register:
33 * 0x0 - plain read write mode
34 * 0x4 - set mode, OR logic.
35 * 0x8 - clr mode, XOR logic.
36 * 0xc - togle mode.
37 */
38#define SET_REG 4
39#define CLR_REG 8
40
31#define HW_ICOLL_VECTOR 0x0000 41#define HW_ICOLL_VECTOR 0x0000
32#define HW_ICOLL_LEVELACK 0x0010 42#define HW_ICOLL_LEVELACK 0x0010
33#define HW_ICOLL_CTRL 0x0020 43#define HW_ICOLL_CTRL 0x0020
34#define HW_ICOLL_STAT_OFFSET 0x0070 44#define HW_ICOLL_STAT_OFFSET 0x0070
35#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10) 45#define HW_ICOLL_INTERRUPT0 0x0120
36#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10) 46#define HW_ICOLL_INTERRUPTn(n) ((n) * 0x10)
37#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004 47#define BM_ICOLL_INTR_ENABLE BIT(2)
38#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1 48#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1
39 49
40#define ICOLL_NUM_IRQS 128 50#define ICOLL_NUM_IRQS 128
41 51
42static void __iomem *icoll_base; 52struct icoll_priv {
53 void __iomem *vector;
54 void __iomem *levelack;
55 void __iomem *ctrl;
56 void __iomem *stat;
57 void __iomem *intr;
58};
59
60static struct icoll_priv icoll_priv;
43static struct irq_domain *icoll_domain; 61static struct irq_domain *icoll_domain;
44 62
45static void icoll_ack_irq(struct irq_data *d) 63static void icoll_ack_irq(struct irq_data *d)
@@ -50,19 +68,19 @@ static void icoll_ack_irq(struct irq_data *d)
50 * BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally. 68 * BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally.
51 */ 69 */
52 __raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0, 70 __raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0,
53 icoll_base + HW_ICOLL_LEVELACK); 71 icoll_priv.levelack);
54} 72}
55 73
56static void icoll_mask_irq(struct irq_data *d) 74static void icoll_mask_irq(struct irq_data *d)
57{ 75{
58 __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, 76 __raw_writel(BM_ICOLL_INTR_ENABLE,
59 icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->hwirq)); 77 icoll_priv.intr + CLR_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
60} 78}
61 79
62static void icoll_unmask_irq(struct irq_data *d) 80static void icoll_unmask_irq(struct irq_data *d)
63{ 81{
64 __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, 82 __raw_writel(BM_ICOLL_INTR_ENABLE,
65 icoll_base + HW_ICOLL_INTERRUPTn_SET(d->hwirq)); 83 icoll_priv.intr + SET_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
66} 84}
67 85
68static struct irq_chip mxs_icoll_chip = { 86static struct irq_chip mxs_icoll_chip = {
@@ -75,8 +93,8 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
75{ 93{
76 u32 irqnr; 94 u32 irqnr;
77 95
78 irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET); 96 irqnr = __raw_readl(icoll_priv.stat);
79 __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR); 97 __raw_writel(irqnr, icoll_priv.vector);
80 handle_domain_irq(icoll_domain, irqnr, regs); 98 handle_domain_irq(icoll_domain, irqnr, regs);
81} 99}
82 100
@@ -93,23 +111,45 @@ static const struct irq_domain_ops icoll_irq_domain_ops = {
93 .xlate = irq_domain_xlate_onecell, 111 .xlate = irq_domain_xlate_onecell,
94}; 112};
95 113
96static int __init icoll_of_init(struct device_node *np, 114static void __init icoll_add_domain(struct device_node *np,
97 struct device_node *interrupt_parent) 115 int num)
116{
117 icoll_domain = irq_domain_add_linear(np, num,
118 &icoll_irq_domain_ops, NULL);
119
120 if (!icoll_domain)
121 panic("%s: unable to create irq domain", np->full_name);
122}
123
124static void __iomem * __init icoll_init_iobase(struct device_node *np)
98{ 125{
99 icoll_base = of_iomap(np, 0); 126 void __iomem *icoll_base;
127
128 icoll_base = of_io_request_and_map(np, 0, np->name);
100 if (!icoll_base) 129 if (!icoll_base)
101 panic("%s: unable to map resource", np->full_name); 130 panic("%s: unable to map resource", np->full_name);
131 return icoll_base;
132}
133
134static int __init icoll_of_init(struct device_node *np,
135 struct device_node *interrupt_parent)
136{
137 void __iomem *icoll_base;
138
139 icoll_base = icoll_init_iobase(np);
140 icoll_priv.vector = icoll_base + HW_ICOLL_VECTOR;
141 icoll_priv.levelack = icoll_base + HW_ICOLL_LEVELACK;
142 icoll_priv.ctrl = icoll_base + HW_ICOLL_CTRL;
143 icoll_priv.stat = icoll_base + HW_ICOLL_STAT_OFFSET;
144 icoll_priv.intr = icoll_base + HW_ICOLL_INTERRUPT0;
102 145
103 /* 146 /*
104 * Interrupt Collector reset, which initializes the priority 147 * Interrupt Collector reset, which initializes the priority
105 * for each irq to level 0. 148 * for each irq to level 0.
106 */ 149 */
107 stmp_reset_block(icoll_base + HW_ICOLL_CTRL); 150 stmp_reset_block(icoll_priv.ctrl);
108 151
109 icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS, 152 icoll_add_domain(np, ICOLL_NUM_IRQS);
110 &icoll_irq_domain_ops, NULL);
111 if (!icoll_domain)
112 panic("%s: unable to create irqdomain", np->full_name);
113 153
114 return 0; 154 return 0;
115} 155}