blob: 832ebf4062f7016ae5a808325b7199021f3e6e47 [file] [log] [blame]
Steven J. Hill2299c492012-08-31 16:13:07 -05001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org)
7 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
8 */
Ralf Baechle39b8d522008-04-28 17:14:26 +01009#include <linux/bitmap.h>
Andrew Brestickerfb8f7be12014-10-20 12:03:55 -070010#include <linux/clocksource.h>
Ralf Baechle39b8d522008-04-28 17:14:26 +010011#include <linux/init.h>
Andrew Bresticker18743d22014-09-18 14:47:24 -070012#include <linux/interrupt.h>
Andrew Brestickerfb8f7be12014-10-20 12:03:55 -070013#include <linux/irq.h>
Joel Porquet41a83e02015-07-07 17:11:46 -040014#include <linux/irqchip.h>
Andrew Bresticker4060bbe2014-10-20 12:03:53 -070015#include <linux/irqchip/mips-gic.h>
Andrew Brestickera7057272014-11-12 11:43:38 -080016#include <linux/of_address.h>
Andrew Bresticker18743d22014-09-18 14:47:24 -070017#include <linux/sched.h>
Ralf Baechle631330f2009-06-19 14:05:26 +010018#include <linux/smp.h>
Ralf Baechle39b8d522008-04-28 17:14:26 +010019
Andrew Brestickera7057272014-11-12 11:43:38 -080020#include <asm/mips-cm.h>
Steven J. Hill98b67c32012-08-31 16:18:49 -050021#include <asm/setup.h>
22#include <asm/traps.h>
Ralf Baechle39b8d522008-04-28 17:14:26 +010023
Andrew Brestickera7057272014-11-12 11:43:38 -080024#include <dt-bindings/interrupt-controller/mips-gic.h>
25
Steven J. Hillff867142013-04-10 16:27:04 -050026unsigned int gic_present;
Steven J. Hill98b67c32012-08-31 16:18:49 -050027
Jeffrey Deans822350b2014-07-17 09:20:53 +010028struct gic_pcpu_mask {
Andrew Brestickerfbd55242014-09-18 14:47:25 -070029 DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
Jeffrey Deans822350b2014-07-17 09:20:53 +010030};
31
Alex Smithc0a9f722015-10-12 10:40:43 +010032static unsigned long __gic_base_addr;
Qais Yousef2af70a92015-12-08 13:20:23 +000033
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070034static void __iomem *gic_base;
Steven J. Hill0b271f52012-08-31 16:05:37 -050035static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
Andrew Bresticker95150ae2014-09-18 14:47:21 -070036static DEFINE_SPINLOCK(gic_lock);
Andrew Brestickerc49581a2014-09-18 14:47:23 -070037static struct irq_domain *gic_irq_domain;
Qais Yousef2af70a92015-12-08 13:20:23 +000038static struct irq_domain *gic_ipi_domain;
Andrew Brestickerfbd55242014-09-18 14:47:25 -070039static int gic_shared_intrs;
Andrew Brestickere9de6882014-09-18 14:47:27 -070040static int gic_vpes;
Andrew Bresticker3263d082014-09-18 14:47:28 -070041static unsigned int gic_cpu_pin;
James Hogan1b6af712015-01-19 15:38:24 +000042static unsigned int timer_cpu_pin;
Andrew Bresticker4a6a3ea32014-09-18 14:47:26 -070043static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
Qais Yousef2af70a92015-12-08 13:20:23 +000044DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
Paul Burtonf8dcd9e2017-04-20 10:07:34 +010045DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
Ralf Baechle39b8d522008-04-28 17:14:26 +010046
Andrew Bresticker18743d22014-09-18 14:47:24 -070047static void __gic_irq_dispatch(void);
48
Markos Chandrasc3f57f02015-07-14 10:26:09 +010049static inline u32 gic_read32(unsigned int reg)
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070050{
51 return __raw_readl(gic_base + reg);
52}
53
Markos Chandrasc3f57f02015-07-14 10:26:09 +010054static inline u64 gic_read64(unsigned int reg)
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070055{
Markos Chandrasc3f57f02015-07-14 10:26:09 +010056 return __raw_readq(gic_base + reg);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070057}
58
Markos Chandrasc3f57f02015-07-14 10:26:09 +010059static inline unsigned long gic_read(unsigned int reg)
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070060{
Markos Chandrasc3f57f02015-07-14 10:26:09 +010061 if (!mips_cm_is64)
62 return gic_read32(reg);
63 else
64 return gic_read64(reg);
65}
66
67static inline void gic_write32(unsigned int reg, u32 val)
68{
69 return __raw_writel(val, gic_base + reg);
70}
71
72static inline void gic_write64(unsigned int reg, u64 val)
73{
74 return __raw_writeq(val, gic_base + reg);
75}
76
77static inline void gic_write(unsigned int reg, unsigned long val)
78{
79 if (!mips_cm_is64)
80 return gic_write32(reg, (u32)val);
81 else
82 return gic_write64(reg, (u64)val);
83}
84
85static inline void gic_update_bits(unsigned int reg, unsigned long mask,
86 unsigned long val)
87{
88 unsigned long regval;
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070089
90 regval = gic_read(reg);
91 regval &= ~mask;
92 regval |= val;
93 gic_write(reg, regval);
94}
95
96static inline void gic_reset_mask(unsigned int intr)
97{
98 gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr),
Markos Chandrasc3f57f02015-07-14 10:26:09 +010099 1ul << GIC_INTR_BIT(intr));
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700100}
101
102static inline void gic_set_mask(unsigned int intr)
103{
104 gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr),
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100105 1ul << GIC_INTR_BIT(intr));
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700106}
107
108static inline void gic_set_polarity(unsigned int intr, unsigned int pol)
109{
110 gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) +
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100111 GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
112 (unsigned long)pol << GIC_INTR_BIT(intr));
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700113}
114
115static inline void gic_set_trigger(unsigned int intr, unsigned int trig)
116{
117 gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) +
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100118 GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
119 (unsigned long)trig << GIC_INTR_BIT(intr));
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700120}
121
122static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual)
123{
124 gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr),
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100125 1ul << GIC_INTR_BIT(intr),
126 (unsigned long)dual << GIC_INTR_BIT(intr));
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700127}
128
129static inline void gic_map_to_pin(unsigned int intr, unsigned int pin)
130{
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100131 gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) +
132 GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700133}
134
135static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe)
136{
137 gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_VPE_BASE) +
138 GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe),
139 GIC_SH_MAP_TO_VPE_REG_BIT(vpe));
140}
141
Andrew Brestickera331ce62014-10-20 12:03:59 -0700142#ifdef CONFIG_CLKSRC_MIPS_GIC
Marcin Nowakowski9f93d872017-06-09 09:04:05 +0200143u64 notrace gic_read_count(void)
Steven J. Hilldfa762e2013-04-10 16:28:36 -0500144{
145 unsigned int hi, hi2, lo;
146
Markos Chandras6f50c832015-07-09 10:40:49 +0100147 if (mips_cm_is64)
Thomas Gleixnera5a1d1c2016-12-21 20:32:01 +0100148 return (u64)gic_read(GIC_REG(SHARED, GIC_SH_COUNTER));
Markos Chandras6f50c832015-07-09 10:40:49 +0100149
Steven J. Hilldfa762e2013-04-10 16:28:36 -0500150 do {
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100151 hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32));
152 lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00));
153 hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32));
Steven J. Hilldfa762e2013-04-10 16:28:36 -0500154 } while (hi2 != hi);
155
Thomas Gleixnera5a1d1c2016-12-21 20:32:01 +0100156 return (((u64) hi) << 32) + lo;
Steven J. Hilldfa762e2013-04-10 16:28:36 -0500157}
Raghu Gandham0ab2b7d2013-04-10 16:30:12 -0500158
Andrew Bresticker387904f2014-10-20 12:03:49 -0700159unsigned int gic_get_count_width(void)
160{
161 unsigned int bits, config;
162
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700163 config = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
Andrew Bresticker387904f2014-10-20 12:03:49 -0700164 bits = 32 + 4 * ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >>
165 GIC_SH_CONFIG_COUNTBITS_SHF);
166
167 return bits;
168}
169
Marcin Nowakowski9f93d872017-06-09 09:04:05 +0200170void notrace gic_write_compare(u64 cnt)
Raghu Gandham0ab2b7d2013-04-10 16:30:12 -0500171{
Markos Chandras6f50c832015-07-09 10:40:49 +0100172 if (mips_cm_is64) {
173 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt);
174 } else {
175 gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
176 (int)(cnt >> 32));
177 gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
178 (int)(cnt & 0xffffffff));
179 }
Raghu Gandham0ab2b7d2013-04-10 16:30:12 -0500180}
181
Marcin Nowakowski9f93d872017-06-09 09:04:05 +0200182void notrace gic_write_cpu_compare(u64 cnt, int cpu)
Paul Burton414408d02014-03-05 11:35:53 +0000183{
184 unsigned long flags;
185
186 local_irq_save(flags);
187
Paul Burtond46812b2016-02-03 03:15:27 +0000188 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), mips_cm_vp_id(cpu));
Markos Chandras6f50c832015-07-09 10:40:49 +0100189
190 if (mips_cm_is64) {
191 gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt);
192 } else {
193 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI),
194 (int)(cnt >> 32));
195 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO),
196 (int)(cnt & 0xffffffff));
197 }
Paul Burton414408d02014-03-05 11:35:53 +0000198
199 local_irq_restore(flags);
200}
201
Thomas Gleixnera5a1d1c2016-12-21 20:32:01 +0100202u64 gic_read_compare(void)
Raghu Gandham0ab2b7d2013-04-10 16:30:12 -0500203{
204 unsigned int hi, lo;
205
Markos Chandras6f50c832015-07-09 10:40:49 +0100206 if (mips_cm_is64)
Thomas Gleixnera5a1d1c2016-12-21 20:32:01 +0100207 return (u64)gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE));
Markos Chandras6f50c832015-07-09 10:40:49 +0100208
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100209 hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI));
210 lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO));
Raghu Gandham0ab2b7d2013-04-10 16:30:12 -0500211
Thomas Gleixnera5a1d1c2016-12-21 20:32:01 +0100212 return (((u64) hi) << 32) + lo;
Raghu Gandham0ab2b7d2013-04-10 16:30:12 -0500213}
Markos Chandras8fa4b932015-03-23 12:32:01 +0000214
215void gic_start_count(void)
216{
217 u32 gicconfig;
218
219 /* Start the counter */
220 gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
221 gicconfig &= ~(1 << GIC_SH_CONFIG_COUNTSTOP_SHF);
222 gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
223}
224
225void gic_stop_count(void)
226{
227 u32 gicconfig;
228
229 /* Stop the counter */
230 gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
231 gicconfig |= 1 << GIC_SH_CONFIG_COUNTSTOP_SHF;
232 gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
233}
234
Steven J. Hilldfa762e2013-04-10 16:28:36 -0500235#endif
236
Paul Burton835d2b42016-02-03 03:15:28 +0000237unsigned gic_read_local_vp_id(void)
238{
239 unsigned long ident;
240
241 ident = gic_read(GIC_REG(VPE_LOCAL, GIC_VP_IDENT));
242 return ident & GIC_VP_IDENT_VCNUM_MSK;
243}
244
Andrew Brestickere9de6882014-09-18 14:47:27 -0700245static bool gic_local_irq_is_routable(int intr)
246{
247 u32 vpe_ctl;
248
249 /* All local interrupts are routable in EIC mode. */
250 if (cpu_has_veic)
251 return true;
252
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100253 vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL));
Andrew Brestickere9de6882014-09-18 14:47:27 -0700254 switch (intr) {
255 case GIC_LOCAL_INT_TIMER:
256 return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
257 case GIC_LOCAL_INT_PERFCTR:
258 return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
259 case GIC_LOCAL_INT_FDC:
260 return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
261 case GIC_LOCAL_INT_SWINT0:
262 case GIC_LOCAL_INT_SWINT1:
263 return vpe_ctl & GIC_VPE_CTL_SWINT_RTBL_MSK;
264 default:
265 return true;
266 }
267}
268
Andrew Bresticker3263d082014-09-18 14:47:28 -0700269static void gic_bind_eic_interrupt(int irq, int set)
Steven J. Hill98b67c32012-08-31 16:18:49 -0500270{
271 /* Convert irq vector # to hw int # */
272 irq -= GIC_PIN_TO_VEC_OFFSET;
273
274 /* Set irq to use shadow set */
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700275 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_EIC_SHADOW_SET_BASE) +
276 GIC_VPE_EIC_SS(irq), set);
Steven J. Hill98b67c32012-08-31 16:18:49 -0500277}
278
Qais Yousefbb11cff2015-12-08 13:20:28 +0000279static void gic_send_ipi(struct irq_data *d, unsigned int cpu)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100280{
Qais Yousefbb11cff2015-12-08 13:20:28 +0000281 irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d));
282
283 gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(hwirq));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100284}
285
Andrew Brestickere9de6882014-09-18 14:47:27 -0700286int gic_get_c0_compare_int(void)
287{
288 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER))
289 return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
290 return irq_create_mapping(gic_irq_domain,
291 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER));
292}
293
294int gic_get_c0_perfcount_int(void)
295{
296 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) {
James Hogan7e3e6cb2015-01-27 21:45:50 +0000297 /* Is the performance counter shared with the timer? */
Andrew Brestickere9de6882014-09-18 14:47:27 -0700298 if (cp0_perfcount_irq < 0)
299 return -1;
300 return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
301 }
302 return irq_create_mapping(gic_irq_domain,
303 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
304}
305
James Hogan6429e2b2015-01-29 11:14:09 +0000306int gic_get_c0_fdc_int(void)
307{
308 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_FDC)) {
309 /* Is the FDC IRQ even present? */
310 if (cp0_fdc_irq < 0)
311 return -1;
312 return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
313 }
314
James Hogan6429e2b2015-01-29 11:14:09 +0000315 return irq_create_mapping(gic_irq_domain,
316 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
317}
318
Alex Smithc0a9f722015-10-12 10:40:43 +0100319int gic_get_usm_range(struct resource *gic_usm_res)
320{
321 if (!gic_present)
322 return -1;
323
324 gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS;
325 gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1);
326
327 return 0;
328}
329
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200330static void gic_handle_shared_int(bool chained)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100331{
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100332 unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4;
Andrew Bresticker8f5ee792014-10-20 12:03:56 -0700333 unsigned long *pcpu_mask;
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700334 unsigned long pending_reg, intrmask_reg;
Andrew Bresticker8f5ee792014-10-20 12:03:56 -0700335 DECLARE_BITMAP(pending, GIC_MAX_INTRS);
336 DECLARE_BITMAP(intrmask, GIC_MAX_INTRS);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100337
338 /* Get per-cpu bitmaps */
Ralf Baechle39b8d522008-04-28 17:14:26 +0100339 pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
340
Andrew Bresticker824f3f72014-10-20 12:03:54 -0700341 pending_reg = GIC_REG(SHARED, GIC_SH_PEND);
342 intrmask_reg = GIC_REG(SHARED, GIC_SH_MASK);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100343
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700344 for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) {
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700345 pending[i] = gic_read(pending_reg);
346 intrmask[i] = gic_read(intrmask_reg);
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100347 pending_reg += gic_reg_step;
348 intrmask_reg += gic_reg_step;
Paul Burtond77d5ac2015-09-22 11:29:11 -0700349
Masahiro Yamada97f26452016-08-03 13:45:50 -0700350 if (!IS_ENABLED(CONFIG_64BIT) || mips_cm_is64)
Paul Burtond77d5ac2015-09-22 11:29:11 -0700351 continue;
352
353 pending[i] |= (u64)gic_read(pending_reg) << 32;
354 intrmask[i] |= (u64)gic_read(intrmask_reg) << 32;
355 pending_reg += gic_reg_step;
356 intrmask_reg += gic_reg_step;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100357 }
358
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700359 bitmap_and(pending, pending, intrmask, gic_shared_intrs);
360 bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100361
Paul Burtoncae750b2016-08-19 18:11:19 +0100362 for_each_set_bit(intr, pending, gic_shared_intrs) {
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000363 virq = irq_linear_revmap(gic_irq_domain,
364 GIC_SHARED_TO_HWIRQ(intr));
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200365 if (chained)
366 generic_handle_irq(virq);
367 else
368 do_IRQ(virq);
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000369 }
Ralf Baechle39b8d522008-04-28 17:14:26 +0100370}
371
Thomas Gleixner161d0492011-03-23 21:08:58 +0000372static void gic_mask_irq(struct irq_data *d)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100373{
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700374 gic_reset_mask(GIC_HWIRQ_TO_SHARED(d->hwirq));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100375}
376
Thomas Gleixner161d0492011-03-23 21:08:58 +0000377static void gic_unmask_irq(struct irq_data *d)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100378{
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700379 gic_set_mask(GIC_HWIRQ_TO_SHARED(d->hwirq));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100380}
381
Andrew Bresticker5561c9e2014-09-18 14:47:20 -0700382static void gic_ack_irq(struct irq_data *d)
383{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700384 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700385
Andrew Bresticker53a7bc82014-10-20 12:03:57 -0700386 gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_CLR(irq));
Andrew Bresticker5561c9e2014-09-18 14:47:20 -0700387}
388
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700389static int gic_set_type(struct irq_data *d, unsigned int type)
390{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700391 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700392 unsigned long flags;
393 bool is_edge;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100394
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700395 spin_lock_irqsave(&gic_lock, flags);
396 switch (type & IRQ_TYPE_SENSE_MASK) {
397 case IRQ_TYPE_EDGE_FALLING:
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700398 gic_set_polarity(irq, GIC_POL_NEG);
399 gic_set_trigger(irq, GIC_TRIG_EDGE);
400 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700401 is_edge = true;
402 break;
403 case IRQ_TYPE_EDGE_RISING:
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700404 gic_set_polarity(irq, GIC_POL_POS);
405 gic_set_trigger(irq, GIC_TRIG_EDGE);
406 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700407 is_edge = true;
408 break;
409 case IRQ_TYPE_EDGE_BOTH:
410 /* polarity is irrelevant in this case */
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700411 gic_set_trigger(irq, GIC_TRIG_EDGE);
412 gic_set_dual_edge(irq, GIC_TRIG_DUAL_ENABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700413 is_edge = true;
414 break;
415 case IRQ_TYPE_LEVEL_LOW:
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700416 gic_set_polarity(irq, GIC_POL_NEG);
417 gic_set_trigger(irq, GIC_TRIG_LEVEL);
418 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700419 is_edge = false;
420 break;
421 case IRQ_TYPE_LEVEL_HIGH:
422 default:
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700423 gic_set_polarity(irq, GIC_POL_POS);
424 gic_set_trigger(irq, GIC_TRIG_LEVEL);
425 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700426 is_edge = false;
427 break;
428 }
429
Thomas Gleixnera595fc52015-06-23 14:41:25 +0200430 if (is_edge)
431 irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller,
432 handle_edge_irq, NULL);
433 else
434 irq_set_chip_handler_name_locked(d, &gic_level_irq_controller,
435 handle_level_irq, NULL);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700436 spin_unlock_irqrestore(&gic_lock, flags);
437
438 return 0;
439}
440
441#ifdef CONFIG_SMP
Thomas Gleixner161d0492011-03-23 21:08:58 +0000442static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
443 bool force)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100444{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700445 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100446 cpumask_t tmp = CPU_MASK_NONE;
447 unsigned long flags;
448 int i;
449
Rusty Russell0de26522008-12-13 21:20:26 +1030450 cpumask_and(&tmp, cpumask, cpu_online_mask);
Rusty Russellf9b531f2015-03-05 10:49:16 +1030451 if (cpumask_empty(&tmp))
Andrew Bresticker14d160a2014-09-18 14:47:22 -0700452 return -EINVAL;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100453
454 /* Assumption : cpumask refers to a single CPU */
455 spin_lock_irqsave(&gic_lock, flags);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100456
Tony Wuc214c032013-06-21 10:13:08 +0000457 /* Re-route this IRQ */
Paul Burtonab41f6c2015-09-22 11:29:10 -0700458 gic_map_to_vpe(irq, mips_cm_vp_id(cpumask_first(&tmp)));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100459
Tony Wuc214c032013-06-21 10:13:08 +0000460 /* Update the pcpu_masks */
Paul Burton91951f92016-04-21 11:31:54 +0100461 for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
Tony Wuc214c032013-06-21 10:13:08 +0000462 clear_bit(irq, pcpu_masks[i].pcpu_mask);
Rusty Russellf9b531f2015-03-05 10:49:16 +1030463 set_bit(irq, pcpu_masks[cpumask_first(&tmp)].pcpu_mask);
Tony Wuc214c032013-06-21 10:13:08 +0000464
Jiang Liu72f86db2015-06-01 16:05:38 +0800465 cpumask_copy(irq_data_get_affinity_mask(d), cpumask);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100466 spin_unlock_irqrestore(&gic_lock, flags);
467
Thomas Gleixner161d0492011-03-23 21:08:58 +0000468 return IRQ_SET_MASK_OK_NOCOPY;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100469}
470#endif
471
Andrew Bresticker4a6a3ea32014-09-18 14:47:26 -0700472static struct irq_chip gic_level_irq_controller = {
473 .name = "MIPS GIC",
474 .irq_mask = gic_mask_irq,
475 .irq_unmask = gic_unmask_irq,
476 .irq_set_type = gic_set_type,
477#ifdef CONFIG_SMP
478 .irq_set_affinity = gic_set_affinity,
479#endif
480};
481
482static struct irq_chip gic_edge_irq_controller = {
Thomas Gleixner161d0492011-03-23 21:08:58 +0000483 .name = "MIPS GIC",
Andrew Bresticker5561c9e2014-09-18 14:47:20 -0700484 .irq_ack = gic_ack_irq,
Thomas Gleixner161d0492011-03-23 21:08:58 +0000485 .irq_mask = gic_mask_irq,
Thomas Gleixner161d0492011-03-23 21:08:58 +0000486 .irq_unmask = gic_unmask_irq,
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700487 .irq_set_type = gic_set_type,
Ralf Baechle39b8d522008-04-28 17:14:26 +0100488#ifdef CONFIG_SMP
Thomas Gleixner161d0492011-03-23 21:08:58 +0000489 .irq_set_affinity = gic_set_affinity,
Ralf Baechle39b8d522008-04-28 17:14:26 +0100490#endif
Qais Yousefbb11cff2015-12-08 13:20:28 +0000491 .ipi_send_single = gic_send_ipi,
Ralf Baechle39b8d522008-04-28 17:14:26 +0100492};
493
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200494static void gic_handle_local_int(bool chained)
Andrew Brestickere9de6882014-09-18 14:47:27 -0700495{
496 unsigned long pending, masked;
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000497 unsigned int intr, virq;
Andrew Brestickere9de6882014-09-18 14:47:27 -0700498
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100499 pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
500 masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK));
Andrew Brestickere9de6882014-09-18 14:47:27 -0700501
502 bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
503
Paul Burton0f4ed152016-09-13 17:54:27 +0100504 for_each_set_bit(intr, &pending, GIC_NUM_LOCAL_INTRS) {
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000505 virq = irq_linear_revmap(gic_irq_domain,
506 GIC_LOCAL_TO_HWIRQ(intr));
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200507 if (chained)
508 generic_handle_irq(virq);
509 else
510 do_IRQ(virq);
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000511 }
Andrew Brestickere9de6882014-09-18 14:47:27 -0700512}
513
514static void gic_mask_local_irq(struct irq_data *d)
515{
516 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
517
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100518 gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700519}
520
521static void gic_unmask_local_irq(struct irq_data *d)
522{
523 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
524
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100525 gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700526}
527
528static struct irq_chip gic_local_irq_controller = {
529 .name = "MIPS GIC Local",
530 .irq_mask = gic_mask_local_irq,
531 .irq_unmask = gic_unmask_local_irq,
532};
533
534static void gic_mask_local_irq_all_vpes(struct irq_data *d)
535{
536 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
537 int i;
538 unsigned long flags;
539
540 spin_lock_irqsave(&gic_lock, flags);
541 for (i = 0; i < gic_vpes; i++) {
Paul Burtond46812b2016-02-03 03:15:27 +0000542 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
543 mips_cm_vp_id(i));
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100544 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700545 }
546 spin_unlock_irqrestore(&gic_lock, flags);
547}
548
549static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
550{
551 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
552 int i;
553 unsigned long flags;
554
555 spin_lock_irqsave(&gic_lock, flags);
556 for (i = 0; i < gic_vpes; i++) {
Paul Burtond46812b2016-02-03 03:15:27 +0000557 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
558 mips_cm_vp_id(i));
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100559 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700560 }
561 spin_unlock_irqrestore(&gic_lock, flags);
562}
563
564static struct irq_chip gic_all_vpes_local_irq_controller = {
565 .name = "MIPS GIC Local",
566 .irq_mask = gic_mask_local_irq_all_vpes,
567 .irq_unmask = gic_unmask_local_irq_all_vpes,
568};
569
Andrew Bresticker18743d22014-09-18 14:47:24 -0700570static void __gic_irq_dispatch(void)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100571{
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200572 gic_handle_local_int(false);
573 gic_handle_shared_int(false);
Andrew Bresticker18743d22014-09-18 14:47:24 -0700574}
575
Thomas Gleixnerbd0b9ac2015-09-14 10:42:37 +0200576static void gic_irq_dispatch(struct irq_desc *desc)
Andrew Bresticker18743d22014-09-18 14:47:24 -0700577{
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200578 gic_handle_local_int(true);
579 gic_handle_shared_int(true);
Andrew Bresticker18743d22014-09-18 14:47:24 -0700580}
581
Andrew Brestickere9de6882014-09-18 14:47:27 -0700582static void __init gic_basic_init(void)
Andrew Bresticker18743d22014-09-18 14:47:24 -0700583{
584 unsigned int i;
Steven J. Hill98b67c32012-08-31 16:18:49 -0500585
586 board_bind_eic_interrupt = &gic_bind_eic_interrupt;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100587
588 /* Setup defaults */
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700589 for (i = 0; i < gic_shared_intrs; i++) {
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700590 gic_set_polarity(i, GIC_POL_POS);
591 gic_set_trigger(i, GIC_TRIG_LEVEL);
592 gic_reset_mask(i);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100593 }
594
Andrew Brestickere9de6882014-09-18 14:47:27 -0700595 for (i = 0; i < gic_vpes; i++) {
596 unsigned int j;
597
Paul Burtond46812b2016-02-03 03:15:27 +0000598 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
599 mips_cm_vp_id(i));
Andrew Brestickere9de6882014-09-18 14:47:27 -0700600 for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
601 if (!gic_local_irq_is_routable(j))
602 continue;
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100603 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700604 }
605 }
Ralf Baechle39b8d522008-04-28 17:14:26 +0100606}
607
Andrew Brestickere9de6882014-09-18 14:47:27 -0700608static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
609 irq_hw_number_t hw)
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700610{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700611 int intr = GIC_HWIRQ_TO_LOCAL(hw);
612 int ret = 0;
613 int i;
614 unsigned long flags;
615
616 if (!gic_local_irq_is_routable(intr))
617 return -EPERM;
618
Andrew Brestickere9de6882014-09-18 14:47:27 -0700619 spin_lock_irqsave(&gic_lock, flags);
620 for (i = 0; i < gic_vpes; i++) {
621 u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin;
622
Paul Burtond46812b2016-02-03 03:15:27 +0000623 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
624 mips_cm_vp_id(i));
Andrew Brestickere9de6882014-09-18 14:47:27 -0700625
626 switch (intr) {
627 case GIC_LOCAL_INT_WD:
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100628 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700629 break;
630 case GIC_LOCAL_INT_COMPARE:
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100631 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP),
632 val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700633 break;
634 case GIC_LOCAL_INT_TIMER:
James Hogan1b6af712015-01-19 15:38:24 +0000635 /* CONFIG_MIPS_CMP workaround (see __gic_init) */
636 val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin;
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100637 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
638 val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700639 break;
640 case GIC_LOCAL_INT_PERFCTR:
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100641 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
642 val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700643 break;
644 case GIC_LOCAL_INT_SWINT0:
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100645 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP),
646 val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700647 break;
648 case GIC_LOCAL_INT_SWINT1:
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100649 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP),
650 val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700651 break;
652 case GIC_LOCAL_INT_FDC:
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100653 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700654 break;
655 default:
656 pr_err("Invalid local IRQ %d\n", intr);
657 ret = -EINVAL;
658 break;
659 }
660 }
661 spin_unlock_irqrestore(&gic_lock, flags);
662
663 return ret;
664}
665
666static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
Qais Yousef2af70a92015-12-08 13:20:23 +0000667 irq_hw_number_t hw, unsigned int vpe)
Andrew Brestickere9de6882014-09-18 14:47:27 -0700668{
669 int intr = GIC_HWIRQ_TO_SHARED(hw);
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700670 unsigned long flags;
Qais Yousef78930f02015-12-08 13:20:26 +0000671 int i;
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700672
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700673 spin_lock_irqsave(&gic_lock, flags);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700674 gic_map_to_pin(intr, gic_cpu_pin);
Paul Burton99ec8a32016-07-05 14:25:59 +0100675 gic_map_to_vpe(intr, mips_cm_vp_id(vpe));
Paul Burton91951f92016-04-21 11:31:54 +0100676 for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
Qais Yousef78930f02015-12-08 13:20:26 +0000677 clear_bit(intr, pcpu_masks[i].pcpu_mask);
Qais Yousef2af70a92015-12-08 13:20:23 +0000678 set_bit(intr, pcpu_masks[vpe].pcpu_mask);
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700679 spin_unlock_irqrestore(&gic_lock, flags);
680
681 return 0;
682}
683
Paul Burtonb87281e2017-04-20 10:07:35 +0100684static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
Qais Yousefc98c18222015-12-08 13:20:24 +0000685 const u32 *intspec, unsigned int intsize,
686 irq_hw_number_t *out_hwirq,
687 unsigned int *out_type)
688{
689 if (intsize != 3)
690 return -EINVAL;
691
692 if (intspec[0] == GIC_SHARED)
693 *out_hwirq = GIC_SHARED_TO_HWIRQ(intspec[1]);
694 else if (intspec[0] == GIC_LOCAL)
695 *out_hwirq = GIC_LOCAL_TO_HWIRQ(intspec[1]);
696 else
697 return -EINVAL;
698 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
699
700 return 0;
701}
702
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100703static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
704 irq_hw_number_t hwirq)
Qais Yousefc98c18222015-12-08 13:20:24 +0000705{
Paul Burtonb87281e2017-04-20 10:07:35 +0100706 int err;
Qais Yousefc98c18222015-12-08 13:20:24 +0000707
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100708 if (hwirq >= GIC_SHARED_HWIRQ_BASE) {
Paul Burtonb87281e2017-04-20 10:07:35 +0100709 /* verify that shared irqs don't conflict with an IPI irq */
710 if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv))
711 return -EBUSY;
Qais Yousefc98c18222015-12-08 13:20:24 +0000712
Paul Burtonb87281e2017-04-20 10:07:35 +0100713 err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
714 &gic_level_irq_controller,
715 NULL);
716 if (err)
717 return err;
718
719 return gic_shared_irq_domain_map(d, virq, hwirq, 0);
Qais Yousefc98c18222015-12-08 13:20:24 +0000720 }
721
Paul Burtonb87281e2017-04-20 10:07:35 +0100722 switch (GIC_HWIRQ_TO_LOCAL(hwirq)) {
723 case GIC_LOCAL_INT_TIMER:
724 case GIC_LOCAL_INT_PERFCTR:
725 case GIC_LOCAL_INT_FDC:
726 /*
727 * HACK: These are all really percpu interrupts, but
728 * the rest of the MIPS kernel code does not use the
729 * percpu IRQ API for them.
730 */
731 err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
732 &gic_all_vpes_local_irq_controller,
733 NULL);
734 if (err)
735 return err;
736
737 irq_set_handler(virq, handle_percpu_irq);
738 break;
739
740 default:
741 err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
742 &gic_local_irq_controller,
743 NULL);
744 if (err)
745 return err;
746
747 irq_set_handler(virq, handle_percpu_devid_irq);
748 irq_set_percpu_devid(virq);
749 break;
750 }
751
752 return gic_local_irq_domain_map(d, virq, hwirq);
Qais Yousefc98c18222015-12-08 13:20:24 +0000753}
754
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100755static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
756 unsigned int nr_irqs, void *arg)
757{
758 struct irq_fwspec *fwspec = arg;
759 irq_hw_number_t hwirq;
760
761 if (fwspec->param[0] == GIC_SHARED)
762 hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]);
763 else
764 hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]);
765
766 return gic_irq_domain_map(d, virq, hwirq);
767}
768
Paul Burtonb87281e2017-04-20 10:07:35 +0100769void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
Qais Yousefc98c18222015-12-08 13:20:24 +0000770 unsigned int nr_irqs)
771{
Qais Yousefc98c18222015-12-08 13:20:24 +0000772}
773
Paul Burtonb87281e2017-04-20 10:07:35 +0100774static const struct irq_domain_ops gic_irq_domain_ops = {
775 .xlate = gic_irq_domain_xlate,
776 .alloc = gic_irq_domain_alloc,
777 .free = gic_irq_domain_free,
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100778 .map = gic_irq_domain_map,
Qais Yousef2af70a92015-12-08 13:20:23 +0000779};
780
781static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
782 const u32 *intspec, unsigned int intsize,
783 irq_hw_number_t *out_hwirq,
784 unsigned int *out_type)
785{
786 /*
787 * There's nothing to translate here. hwirq is dynamically allocated and
788 * the irq type is always edge triggered.
789 * */
790 *out_hwirq = 0;
791 *out_type = IRQ_TYPE_EDGE_RISING;
792
793 return 0;
794}
795
796static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq,
797 unsigned int nr_irqs, void *arg)
798{
799 struct cpumask *ipimask = arg;
Paul Burtonb87281e2017-04-20 10:07:35 +0100800 irq_hw_number_t hwirq, base_hwirq;
801 int cpu, ret, i;
Qais Yousef2af70a92015-12-08 13:20:23 +0000802
Paul Burtonb87281e2017-04-20 10:07:35 +0100803 base_hwirq = find_first_bit(ipi_available, gic_shared_intrs);
804 if (base_hwirq == gic_shared_intrs)
805 return -ENOMEM;
Qais Yousef2af70a92015-12-08 13:20:23 +0000806
Paul Burtonb87281e2017-04-20 10:07:35 +0100807 /* check that we have enough space */
808 for (i = base_hwirq; i < nr_irqs; i++) {
809 if (!test_bit(i, ipi_available))
810 return -EBUSY;
811 }
812 bitmap_clear(ipi_available, base_hwirq, nr_irqs);
813
814 /* map the hwirq for each cpu consecutively */
815 i = 0;
816 for_each_cpu(cpu, ipimask) {
817 hwirq = GIC_SHARED_TO_HWIRQ(base_hwirq + i);
818
819 ret = irq_domain_set_hwirq_and_chip(d, virq + i, hwirq,
820 &gic_edge_irq_controller,
821 NULL);
822 if (ret)
823 goto error;
824
825 ret = irq_domain_set_hwirq_and_chip(d->parent, virq + i, hwirq,
Qais Yousef2af70a92015-12-08 13:20:23 +0000826 &gic_edge_irq_controller,
827 NULL);
828 if (ret)
829 goto error;
830
831 ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING);
832 if (ret)
833 goto error;
Paul Burtonb87281e2017-04-20 10:07:35 +0100834
835 ret = gic_shared_irq_domain_map(d, virq + i, hwirq, cpu);
836 if (ret)
837 goto error;
838
839 i++;
Qais Yousef2af70a92015-12-08 13:20:23 +0000840 }
841
842 return 0;
843error:
Paul Burtonb87281e2017-04-20 10:07:35 +0100844 bitmap_set(ipi_available, base_hwirq, nr_irqs);
Qais Yousef2af70a92015-12-08 13:20:23 +0000845 return ret;
846}
847
848void gic_ipi_domain_free(struct irq_domain *d, unsigned int virq,
849 unsigned int nr_irqs)
850{
Paul Burtonb87281e2017-04-20 10:07:35 +0100851 irq_hw_number_t base_hwirq;
852 struct irq_data *data;
853
854 data = irq_get_irq_data(virq);
855 if (!data)
856 return;
857
858 base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data));
859 bitmap_set(ipi_available, base_hwirq, nr_irqs);
Qais Yousef2af70a92015-12-08 13:20:23 +0000860}
861
862int gic_ipi_domain_match(struct irq_domain *d, struct device_node *node,
863 enum irq_domain_bus_token bus_token)
864{
865 bool is_ipi;
866
867 switch (bus_token) {
868 case DOMAIN_BUS_IPI:
869 is_ipi = d->bus_token == bus_token;
Paul Burton547aefc2016-07-05 14:26:00 +0100870 return (!node || to_of_node(d->fwnode) == node) && is_ipi;
Qais Yousef2af70a92015-12-08 13:20:23 +0000871 break;
872 default:
873 return 0;
874 }
875}
876
Tobias Klauser0b7e8152017-06-02 10:20:56 +0200877static const struct irq_domain_ops gic_ipi_domain_ops = {
Qais Yousef2af70a92015-12-08 13:20:23 +0000878 .xlate = gic_ipi_domain_xlate,
879 .alloc = gic_ipi_domain_alloc,
880 .free = gic_ipi_domain_free,
881 .match = gic_ipi_domain_match,
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700882};
883
Andrew Brestickera7057272014-11-12 11:43:38 -0800884static void __init __gic_init(unsigned long gic_base_addr,
885 unsigned long gic_addrspace_size,
886 unsigned int cpu_vec, unsigned int irqbase,
887 struct device_node *node)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100888{
Paul Burtonba01cf02016-05-17 15:31:06 +0100889 unsigned int gicconfig, cpu;
Qais Yousef16a80832015-12-08 13:20:30 +0000890 unsigned int v[2];
Ralf Baechle39b8d522008-04-28 17:14:26 +0100891
Alex Smithc0a9f722015-10-12 10:40:43 +0100892 __gic_base_addr = gic_base_addr;
893
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700894 gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100895
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700896 gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700897 gic_shared_intrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
Ralf Baechle39b8d522008-04-28 17:14:26 +0100898 GIC_SH_CONFIG_NUMINTRS_SHF;
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700899 gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100900
Andrew Brestickere9de6882014-09-18 14:47:27 -0700901 gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
Ralf Baechle39b8d522008-04-28 17:14:26 +0100902 GIC_SH_CONFIG_NUMVPES_SHF;
Andrew Brestickere9de6882014-09-18 14:47:27 -0700903 gic_vpes = gic_vpes + 1;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100904
Andrew Bresticker18743d22014-09-18 14:47:24 -0700905 if (cpu_has_veic) {
Paul Burtonba01cf02016-05-17 15:31:06 +0100906 /* Set EIC mode for all VPEs */
907 for_each_present_cpu(cpu) {
908 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
909 mips_cm_vp_id(cpu));
910 gic_write(GIC_REG(VPE_OTHER, GIC_VPE_CTL),
911 GIC_VPE_CTL_EIC_MODE_MSK);
912 }
913
Andrew Bresticker18743d22014-09-18 14:47:24 -0700914 /* Always use vector 1 in EIC mode */
915 gic_cpu_pin = 0;
James Hogan1b6af712015-01-19 15:38:24 +0000916 timer_cpu_pin = gic_cpu_pin;
Andrew Bresticker18743d22014-09-18 14:47:24 -0700917 set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
918 __gic_irq_dispatch);
919 } else {
920 gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
921 irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
922 gic_irq_dispatch);
James Hogan1b6af712015-01-19 15:38:24 +0000923 /*
924 * With the CMP implementation of SMP (deprecated), other CPUs
925 * are started by the bootloader and put into a timer based
926 * waiting poll loop. We must not re-route those CPU's local
927 * timer interrupts as the wait instruction will never finish,
928 * so just handle whatever CPU interrupt it is routed to by
929 * default.
930 *
931 * This workaround should be removed when CMP support is
932 * dropped.
933 */
934 if (IS_ENABLED(CONFIG_MIPS_CMP) &&
935 gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) {
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100936 timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL,
James Hogan1b6af712015-01-19 15:38:24 +0000937 GIC_VPE_TIMER_MAP)) &
938 GIC_MAP_MSK;
939 irq_set_chained_handler(MIPS_CPU_IRQ_BASE +
940 GIC_CPU_PIN_OFFSET +
941 timer_cpu_pin,
942 gic_irq_dispatch);
943 } else {
944 timer_cpu_pin = gic_cpu_pin;
945 }
Andrew Bresticker18743d22014-09-18 14:47:24 -0700946 }
947
Andrew Brestickera7057272014-11-12 11:43:38 -0800948 gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +
Andrew Brestickere9de6882014-09-18 14:47:27 -0700949 gic_shared_intrs, irqbase,
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700950 &gic_irq_domain_ops, NULL);
951 if (!gic_irq_domain)
952 panic("Failed to add GIC IRQ domain");
Harvey Hunt21c57fd2016-05-23 12:07:37 +0100953 gic_irq_domain->name = "mips-gic-irq";
Steven J. Hill0b271f52012-08-31 16:05:37 -0500954
Qais Yousef2af70a92015-12-08 13:20:23 +0000955 gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
956 IRQ_DOMAIN_FLAG_IPI_PER_CPU,
957 GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
958 node, &gic_ipi_domain_ops, NULL);
959 if (!gic_ipi_domain)
960 panic("Failed to add GIC IPI domain");
961
Harvey Hunt21c57fd2016-05-23 12:07:37 +0100962 gic_ipi_domain->name = "mips-gic-ipi";
Marc Zyngier96f0d932017-06-22 11:42:50 +0100963 irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI);
Qais Yousef2af70a92015-12-08 13:20:23 +0000964
Qais Yousef16a80832015-12-08 13:20:30 +0000965 if (node &&
966 !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) {
967 bitmap_set(ipi_resrv, v[0], v[1]);
968 } else {
969 /* Make the last 2 * gic_vpes available for IPIs */
970 bitmap_set(ipi_resrv,
971 gic_shared_intrs - 2 * gic_vpes,
972 2 * gic_vpes);
973 }
Qais Yousef2af70a92015-12-08 13:20:23 +0000974
Paul Burtonf8dcd9e2017-04-20 10:07:34 +0100975 bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700976 gic_basic_init();
Ralf Baechle39b8d522008-04-28 17:14:26 +0100977}
Andrew Brestickera7057272014-11-12 11:43:38 -0800978
979void __init gic_init(unsigned long gic_base_addr,
980 unsigned long gic_addrspace_size,
981 unsigned int cpu_vec, unsigned int irqbase)
982{
983 __gic_init(gic_base_addr, gic_addrspace_size, cpu_vec, irqbase, NULL);
984}
985
986static int __init gic_of_init(struct device_node *node,
987 struct device_node *parent)
988{
989 struct resource res;
990 unsigned int cpu_vec, i = 0, reserved = 0;
991 phys_addr_t gic_base;
992 size_t gic_len;
993
994 /* Find the first available CPU vector. */
995 while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors",
996 i++, &cpu_vec))
997 reserved |= BIT(cpu_vec);
998 for (cpu_vec = 2; cpu_vec < 8; cpu_vec++) {
999 if (!(reserved & BIT(cpu_vec)))
1000 break;
1001 }
1002 if (cpu_vec == 8) {
1003 pr_err("No CPU vectors available for GIC\n");
1004 return -ENODEV;
1005 }
1006
1007 if (of_address_to_resource(node, 0, &res)) {
1008 /*
1009 * Probe the CM for the GIC base address if not specified
1010 * in the device-tree.
1011 */
1012 if (mips_cm_present()) {
1013 gic_base = read_gcr_gic_base() &
1014 ~CM_GCR_GIC_BASE_GICEN_MSK;
1015 gic_len = 0x20000;
1016 } else {
1017 pr_err("Failed to get GIC memory range\n");
1018 return -ENODEV;
1019 }
1020 } else {
1021 gic_base = res.start;
1022 gic_len = resource_size(&res);
1023 }
1024
1025 if (mips_cm_present())
1026 write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK);
1027 gic_present = true;
1028
1029 __gic_init(gic_base, gic_len, cpu_vec, 0, node);
1030
1031 return 0;
1032}
1033IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init);