summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorGuo Ren <ren_guo@c-sky.com>2019-06-06 03:37:31 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2019-06-11 07:28:13 -0400
commit648f835a028f4f7f031a89bc099e363d4292e5b9 (patch)
tree7f6b13c4dd10d1b1f6a129ebd0a0c2342c5148f9 /drivers/irqchip
parent17c88892094973acd7176b794eff21abf24779fc (diff)
irqchip/irq-csky-mpintc: Add triger type
Support 4 triger types: - IRQ_TYPE_LEVEL_HIGH - IRQ_TYPE_LEVEL_LOW - IRQ_TYPE_EDGE_RISING - IRQ_TYPE_EDGE_FALLING All of above could be set in DeviceTree file and it still compatible with the old DeviceTree format. Signed-off-by: Guo Ren <ren_guo@c-sky.com> Cc: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/irq-csky-mpintc.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c
index c67c961ab6cc..4457722cdd18 100644
--- a/drivers/irqchip/irq-csky-mpintc.c
+++ b/drivers/irqchip/irq-csky-mpintc.c
@@ -32,6 +32,7 @@ static void __iomem *INTCL_base;
32#define INTCG_CIDSTR 0x1000 32#define INTCG_CIDSTR 0x1000
33 33
34#define INTCL_PICTLR 0x0 34#define INTCL_PICTLR 0x0
35#define INTCL_CFGR 0x14
35#define INTCL_SIGR 0x60 36#define INTCL_SIGR 0x60
36#define INTCL_HPPIR 0x68 37#define INTCL_HPPIR 0x68
37#define INTCL_RDYIR 0x6c 38#define INTCL_RDYIR 0x6c
@@ -41,6 +42,35 @@ static void __iomem *INTCL_base;
41 42
42static DEFINE_PER_CPU(void __iomem *, intcl_reg); 43static DEFINE_PER_CPU(void __iomem *, intcl_reg);
43 44
45static unsigned long *__trigger;
46
47#define IRQ_OFFSET(irq) ((irq < COMM_IRQ_BASE) ? irq : (irq - COMM_IRQ_BASE))
48
49#define TRIG_BYTE_OFFSET(i) ((((i) * 2) / 32) * 4)
50#define TRIG_BIT_OFFSET(i) (((i) * 2) % 32)
51
52#define TRIG_VAL(trigger, irq) (trigger << TRIG_BIT_OFFSET(IRQ_OFFSET(irq)))
53#define TRIG_VAL_MSK(irq) (~(3 << TRIG_BIT_OFFSET(IRQ_OFFSET(irq))))
54
55#define TRIG_BASE(irq) \
56 (TRIG_BYTE_OFFSET(IRQ_OFFSET(irq)) + ((irq < COMM_IRQ_BASE) ? \
57 (this_cpu_read(intcl_reg) + INTCL_CFGR) : (INTCG_base + INTCG_CICFGR)))
58
59static DEFINE_SPINLOCK(setup_lock);
60static void setup_trigger(unsigned long irq, unsigned long trigger)
61{
62 unsigned int tmp;
63
64 spin_lock(&setup_lock);
65
66 /* setup trigger */
67 tmp = readl_relaxed(TRIG_BASE(irq)) & TRIG_VAL_MSK(irq);
68
69 writel_relaxed(tmp | TRIG_VAL(trigger, irq), TRIG_BASE(irq));
70
71 spin_unlock(&setup_lock);
72}
73
44static void csky_mpintc_handler(struct pt_regs *regs) 74static void csky_mpintc_handler(struct pt_regs *regs)
45{ 75{
46 void __iomem *reg_base = this_cpu_read(intcl_reg); 76 void __iomem *reg_base = this_cpu_read(intcl_reg);
@@ -56,6 +86,8 @@ static void csky_mpintc_enable(struct irq_data *d)
56{ 86{
57 void __iomem *reg_base = this_cpu_read(intcl_reg); 87 void __iomem *reg_base = this_cpu_read(intcl_reg);
58 88
89 setup_trigger(d->hwirq, __trigger[d->hwirq]);
90
59 writel_relaxed(d->hwirq, reg_base + INTCL_SENR); 91 writel_relaxed(d->hwirq, reg_base + INTCL_SENR);
60} 92}
61 93
@@ -73,6 +105,28 @@ static void csky_mpintc_eoi(struct irq_data *d)
73 writel_relaxed(d->hwirq, reg_base + INTCL_CACR); 105 writel_relaxed(d->hwirq, reg_base + INTCL_CACR);
74} 106}
75 107
108static int csky_mpintc_set_type(struct irq_data *d, unsigned int type)
109{
110 switch (type & IRQ_TYPE_SENSE_MASK) {
111 case IRQ_TYPE_LEVEL_HIGH:
112 __trigger[d->hwirq] = 0;
113 break;
114 case IRQ_TYPE_LEVEL_LOW:
115 __trigger[d->hwirq] = 1;
116 break;
117 case IRQ_TYPE_EDGE_RISING:
118 __trigger[d->hwirq] = 2;
119 break;
120 case IRQ_TYPE_EDGE_FALLING:
121 __trigger[d->hwirq] = 3;
122 break;
123 default:
124 return -EINVAL;
125 }
126
127 return 0;
128}
129
76#ifdef CONFIG_SMP 130#ifdef CONFIG_SMP
77static int csky_irq_set_affinity(struct irq_data *d, 131static int csky_irq_set_affinity(struct irq_data *d,
78 const struct cpumask *mask_val, 132 const struct cpumask *mask_val,
@@ -105,6 +159,7 @@ static struct irq_chip csky_irq_chip = {
105 .irq_eoi = csky_mpintc_eoi, 159 .irq_eoi = csky_mpintc_eoi,
106 .irq_enable = csky_mpintc_enable, 160 .irq_enable = csky_mpintc_enable,
107 .irq_disable = csky_mpintc_disable, 161 .irq_disable = csky_mpintc_disable,
162 .irq_set_type = csky_mpintc_set_type,
108#ifdef CONFIG_SMP 163#ifdef CONFIG_SMP
109 .irq_set_affinity = csky_irq_set_affinity, 164 .irq_set_affinity = csky_irq_set_affinity,
110#endif 165#endif
@@ -125,9 +180,26 @@ static int csky_irqdomain_map(struct irq_domain *d, unsigned int irq,
125 return 0; 180 return 0;
126} 181}
127 182
183static int csky_irq_domain_xlate_cells(struct irq_domain *d,
184 struct device_node *ctrlr, const u32 *intspec,
185 unsigned int intsize, unsigned long *out_hwirq,
186 unsigned int *out_type)
187{
188 if (WARN_ON(intsize < 1))
189 return -EINVAL;
190
191 *out_hwirq = intspec[0];
192 if (intsize > 1)
193 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
194 else
195 *out_type = IRQ_TYPE_LEVEL_HIGH;
196
197 return 0;
198}
199
128static const struct irq_domain_ops csky_irqdomain_ops = { 200static const struct irq_domain_ops csky_irqdomain_ops = {
129 .map = csky_irqdomain_map, 201 .map = csky_irqdomain_map,
130 .xlate = irq_domain_xlate_onecell, 202 .xlate = csky_irq_domain_xlate_cells,
131}; 203};
132 204
133#ifdef CONFIG_SMP 205#ifdef CONFIG_SMP
@@ -161,6 +233,10 @@ csky_mpintc_init(struct device_node *node, struct device_node *parent)
161 if (ret < 0) 233 if (ret < 0)
162 nr_irq = INTC_IRQS; 234 nr_irq = INTC_IRQS;
163 235
236 __trigger = kcalloc(nr_irq, sizeof(unsigned long), GFP_KERNEL);
237 if (__trigger == NULL)
238 return -ENXIO;
239
164 if (INTCG_base == NULL) { 240 if (INTCG_base == NULL) {
165 INTCG_base = ioremap(mfcr("cr<31, 14>"), 241 INTCG_base = ioremap(mfcr("cr<31, 14>"),
166 INTCL_SIZE*nr_cpu_ids + INTCG_SIZE); 242 INTCL_SIZE*nr_cpu_ids + INTCG_SIZE);