blob: 98728955802446e0fde2dedd5f6758b0757b7d32 [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
Paul Burtone83f7e02017-08-12 19:49:41 -070020#include <asm/mips-cps.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;
Paul Burton582e2b42017-08-12 21:36:10 -070027void __iomem *mips_gic_base;
Steven J. Hill98b67c32012-08-31 16:18:49 -050028
Jeffrey Deans822350b2014-07-17 09:20:53 +010029struct gic_pcpu_mask {
Andrew Brestickerfbd55242014-09-18 14:47:25 -070030 DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
Jeffrey Deans822350b2014-07-17 09:20:53 +010031};
32
Alex Smithc0a9f722015-10-12 10:40:43 +010033static unsigned long __gic_base_addr;
Steven J. Hill0b271f52012-08-31 16:05:37 -050034static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
Andrew Bresticker95150ae2014-09-18 14:47:21 -070035static DEFINE_SPINLOCK(gic_lock);
Andrew Brestickerc49581a2014-09-18 14:47:23 -070036static struct irq_domain *gic_irq_domain;
Qais Yousef2af70a92015-12-08 13:20:23 +000037static struct irq_domain *gic_ipi_domain;
Andrew Brestickerfbd55242014-09-18 14:47:25 -070038static int gic_shared_intrs;
Andrew Brestickere9de6882014-09-18 14:47:27 -070039static int gic_vpes;
Andrew Bresticker3263d082014-09-18 14:47:28 -070040static unsigned int gic_cpu_pin;
James Hogan1b6af712015-01-19 15:38:24 +000041static unsigned int timer_cpu_pin;
Andrew Bresticker4a6a3ea32014-09-18 14:47:26 -070042static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
Qais Yousef2af70a92015-12-08 13:20:23 +000043DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
Paul Burtonf8dcd9e2017-04-20 10:07:34 +010044DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
Ralf Baechle39b8d522008-04-28 17:14:26 +010045
Andrew Bresticker18743d22014-09-18 14:47:24 -070046static void __gic_irq_dispatch(void);
47
Markos Chandrasc3f57f02015-07-14 10:26:09 +010048static inline u32 gic_read32(unsigned int reg)
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070049{
Paul Burton582e2b42017-08-12 21:36:10 -070050 return __raw_readl(mips_gic_base + reg);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070051}
52
Markos Chandrasc3f57f02015-07-14 10:26:09 +010053static inline u64 gic_read64(unsigned int reg)
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070054{
Paul Burton582e2b42017-08-12 21:36:10 -070055 return __raw_readq(mips_gic_base + reg);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070056}
57
Markos Chandrasc3f57f02015-07-14 10:26:09 +010058static inline unsigned long gic_read(unsigned int reg)
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070059{
Markos Chandrasc3f57f02015-07-14 10:26:09 +010060 if (!mips_cm_is64)
61 return gic_read32(reg);
62 else
63 return gic_read64(reg);
64}
65
66static inline void gic_write32(unsigned int reg, u32 val)
67{
Paul Burton582e2b42017-08-12 21:36:10 -070068 return __raw_writel(val, mips_gic_base + reg);
Markos Chandrasc3f57f02015-07-14 10:26:09 +010069}
70
71static inline void gic_write64(unsigned int reg, u64 val)
72{
Paul Burton582e2b42017-08-12 21:36:10 -070073 return __raw_writeq(val, mips_gic_base + reg);
Markos Chandrasc3f57f02015-07-14 10:26:09 +010074}
75
76static inline void gic_write(unsigned int reg, unsigned long val)
77{
78 if (!mips_cm_is64)
79 return gic_write32(reg, (u32)val);
80 else
81 return gic_write64(reg, (u64)val);
82}
83
84static inline void gic_update_bits(unsigned int reg, unsigned long mask,
85 unsigned long val)
86{
87 unsigned long regval;
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070088
89 regval = gic_read(reg);
90 regval &= ~mask;
91 regval |= val;
92 gic_write(reg, regval);
93}
94
Andrew Bresticker5f68fea2014-10-20 12:03:52 -070095static inline void gic_set_trigger(unsigned int intr, unsigned int trig)
96{
97 gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) +
Markos Chandrasc3f57f02015-07-14 10:26:09 +010098 GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
99 (unsigned long)trig << GIC_INTR_BIT(intr));
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700100}
101
102static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual)
103{
104 gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr),
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100105 1ul << GIC_INTR_BIT(intr),
106 (unsigned long)dual << GIC_INTR_BIT(intr));
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700107}
108
109static inline void gic_map_to_pin(unsigned int intr, unsigned int pin)
110{
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100111 gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) +
112 GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700113}
114
115static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe)
116{
117 gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_VPE_BASE) +
118 GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe),
119 GIC_SH_MAP_TO_VPE_REG_BIT(vpe));
120}
121
Andrew Brestickere9de6882014-09-18 14:47:27 -0700122static bool gic_local_irq_is_routable(int intr)
123{
124 u32 vpe_ctl;
125
126 /* All local interrupts are routable in EIC mode. */
127 if (cpu_has_veic)
128 return true;
129
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100130 vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL));
Andrew Brestickere9de6882014-09-18 14:47:27 -0700131 switch (intr) {
132 case GIC_LOCAL_INT_TIMER:
133 return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
134 case GIC_LOCAL_INT_PERFCTR:
135 return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
136 case GIC_LOCAL_INT_FDC:
137 return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
138 case GIC_LOCAL_INT_SWINT0:
139 case GIC_LOCAL_INT_SWINT1:
140 return vpe_ctl & GIC_VPE_CTL_SWINT_RTBL_MSK;
141 default:
142 return true;
143 }
144}
145
Andrew Bresticker3263d082014-09-18 14:47:28 -0700146static void gic_bind_eic_interrupt(int irq, int set)
Steven J. Hill98b67c32012-08-31 16:18:49 -0500147{
148 /* Convert irq vector # to hw int # */
149 irq -= GIC_PIN_TO_VEC_OFFSET;
150
151 /* Set irq to use shadow set */
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700152 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_EIC_SHADOW_SET_BASE) +
153 GIC_VPE_EIC_SS(irq), set);
Steven J. Hill98b67c32012-08-31 16:18:49 -0500154}
155
Qais Yousefbb11cff2015-12-08 13:20:28 +0000156static void gic_send_ipi(struct irq_data *d, unsigned int cpu)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100157{
Qais Yousefbb11cff2015-12-08 13:20:28 +0000158 irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d));
159
160 gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(hwirq));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100161}
162
Andrew Brestickere9de6882014-09-18 14:47:27 -0700163int gic_get_c0_compare_int(void)
164{
165 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER))
166 return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
167 return irq_create_mapping(gic_irq_domain,
168 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER));
169}
170
171int gic_get_c0_perfcount_int(void)
172{
173 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) {
James Hogan7e3e6cb2015-01-27 21:45:50 +0000174 /* Is the performance counter shared with the timer? */
Andrew Brestickere9de6882014-09-18 14:47:27 -0700175 if (cp0_perfcount_irq < 0)
176 return -1;
177 return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
178 }
179 return irq_create_mapping(gic_irq_domain,
180 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
181}
182
James Hogan6429e2b2015-01-29 11:14:09 +0000183int gic_get_c0_fdc_int(void)
184{
185 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_FDC)) {
186 /* Is the FDC IRQ even present? */
187 if (cp0_fdc_irq < 0)
188 return -1;
189 return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
190 }
191
James Hogan6429e2b2015-01-29 11:14:09 +0000192 return irq_create_mapping(gic_irq_domain,
193 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
194}
195
Alex Smithc0a9f722015-10-12 10:40:43 +0100196int gic_get_usm_range(struct resource *gic_usm_res)
197{
198 if (!gic_present)
199 return -1;
200
201 gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS;
202 gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1);
203
204 return 0;
205}
206
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200207static void gic_handle_shared_int(bool chained)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100208{
Paul Burtone98fcb22017-08-12 21:36:16 -0700209 unsigned int intr, virq;
Andrew Bresticker8f5ee792014-10-20 12:03:56 -0700210 unsigned long *pcpu_mask;
Andrew Bresticker8f5ee792014-10-20 12:03:56 -0700211 DECLARE_BITMAP(pending, GIC_MAX_INTRS);
212 DECLARE_BITMAP(intrmask, GIC_MAX_INTRS);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100213
214 /* Get per-cpu bitmaps */
Ralf Baechle39b8d522008-04-28 17:14:26 +0100215 pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
216
Paul Burtone98fcb22017-08-12 21:36:16 -0700217 if (mips_cm_is64) {
218 __ioread64_copy(pending, addr_gic_pend(),
219 DIV_ROUND_UP(gic_shared_intrs, 64));
220 __ioread64_copy(intrmask, addr_gic_mask(),
221 DIV_ROUND_UP(gic_shared_intrs, 64));
222 } else {
223 __ioread32_copy(pending, addr_gic_pend(),
224 DIV_ROUND_UP(gic_shared_intrs, 32));
225 __ioread32_copy(intrmask, addr_gic_mask(),
226 DIV_ROUND_UP(gic_shared_intrs, 32));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100227 }
228
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700229 bitmap_and(pending, pending, intrmask, gic_shared_intrs);
230 bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100231
Paul Burtoncae750b2016-08-19 18:11:19 +0100232 for_each_set_bit(intr, pending, gic_shared_intrs) {
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000233 virq = irq_linear_revmap(gic_irq_domain,
234 GIC_SHARED_TO_HWIRQ(intr));
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200235 if (chained)
236 generic_handle_irq(virq);
237 else
238 do_IRQ(virq);
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000239 }
Ralf Baechle39b8d522008-04-28 17:14:26 +0100240}
241
Thomas Gleixner161d0492011-03-23 21:08:58 +0000242static void gic_mask_irq(struct irq_data *d)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100243{
Paul Burton87554b02017-08-12 21:36:18 -0700244 write_gic_rmask(BIT(GIC_HWIRQ_TO_SHARED(d->hwirq)));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100245}
246
Thomas Gleixner161d0492011-03-23 21:08:58 +0000247static void gic_unmask_irq(struct irq_data *d)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100248{
Paul Burton87554b02017-08-12 21:36:18 -0700249 write_gic_smask(BIT(GIC_HWIRQ_TO_SHARED(d->hwirq)));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100250}
251
Andrew Bresticker5561c9e2014-09-18 14:47:20 -0700252static void gic_ack_irq(struct irq_data *d)
253{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700254 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700255
Andrew Bresticker53a7bc82014-10-20 12:03:57 -0700256 gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_CLR(irq));
Andrew Bresticker5561c9e2014-09-18 14:47:20 -0700257}
258
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700259static int gic_set_type(struct irq_data *d, unsigned int type)
260{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700261 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700262 unsigned long flags;
263 bool is_edge;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100264
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700265 spin_lock_irqsave(&gic_lock, flags);
266 switch (type & IRQ_TYPE_SENSE_MASK) {
267 case IRQ_TYPE_EDGE_FALLING:
Paul Burton80e5f9c2017-08-12 21:36:19 -0700268 change_gic_pol(irq, GIC_POL_FALLING_EDGE);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700269 gic_set_trigger(irq, GIC_TRIG_EDGE);
270 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700271 is_edge = true;
272 break;
273 case IRQ_TYPE_EDGE_RISING:
Paul Burton80e5f9c2017-08-12 21:36:19 -0700274 change_gic_pol(irq, GIC_POL_RISING_EDGE);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700275 gic_set_trigger(irq, GIC_TRIG_EDGE);
276 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700277 is_edge = true;
278 break;
279 case IRQ_TYPE_EDGE_BOTH:
280 /* polarity is irrelevant in this case */
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700281 gic_set_trigger(irq, GIC_TRIG_EDGE);
282 gic_set_dual_edge(irq, GIC_TRIG_DUAL_ENABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700283 is_edge = true;
284 break;
285 case IRQ_TYPE_LEVEL_LOW:
Paul Burton80e5f9c2017-08-12 21:36:19 -0700286 change_gic_pol(irq, GIC_POL_ACTIVE_LOW);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700287 gic_set_trigger(irq, GIC_TRIG_LEVEL);
288 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700289 is_edge = false;
290 break;
291 case IRQ_TYPE_LEVEL_HIGH:
292 default:
Paul Burton80e5f9c2017-08-12 21:36:19 -0700293 change_gic_pol(irq, GIC_POL_ACTIVE_HIGH);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700294 gic_set_trigger(irq, GIC_TRIG_LEVEL);
295 gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700296 is_edge = false;
297 break;
298 }
299
Thomas Gleixnera595fc52015-06-23 14:41:25 +0200300 if (is_edge)
301 irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller,
302 handle_edge_irq, NULL);
303 else
304 irq_set_chip_handler_name_locked(d, &gic_level_irq_controller,
305 handle_level_irq, NULL);
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700306 spin_unlock_irqrestore(&gic_lock, flags);
307
308 return 0;
309}
310
311#ifdef CONFIG_SMP
Thomas Gleixner161d0492011-03-23 21:08:58 +0000312static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
313 bool force)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100314{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700315 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100316 cpumask_t tmp = CPU_MASK_NONE;
317 unsigned long flags;
318 int i;
319
Rusty Russell0de26522008-12-13 21:20:26 +1030320 cpumask_and(&tmp, cpumask, cpu_online_mask);
Rusty Russellf9b531f2015-03-05 10:49:16 +1030321 if (cpumask_empty(&tmp))
Andrew Bresticker14d160a2014-09-18 14:47:22 -0700322 return -EINVAL;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100323
324 /* Assumption : cpumask refers to a single CPU */
325 spin_lock_irqsave(&gic_lock, flags);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100326
Tony Wuc214c032013-06-21 10:13:08 +0000327 /* Re-route this IRQ */
Paul Burtonab41f6c2015-09-22 11:29:10 -0700328 gic_map_to_vpe(irq, mips_cm_vp_id(cpumask_first(&tmp)));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100329
Tony Wuc214c032013-06-21 10:13:08 +0000330 /* Update the pcpu_masks */
Paul Burton91951f92016-04-21 11:31:54 +0100331 for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
Tony Wuc214c032013-06-21 10:13:08 +0000332 clear_bit(irq, pcpu_masks[i].pcpu_mask);
Rusty Russellf9b531f2015-03-05 10:49:16 +1030333 set_bit(irq, pcpu_masks[cpumask_first(&tmp)].pcpu_mask);
Tony Wuc214c032013-06-21 10:13:08 +0000334
Jiang Liu72f86db2015-06-01 16:05:38 +0800335 cpumask_copy(irq_data_get_affinity_mask(d), cpumask);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100336 spin_unlock_irqrestore(&gic_lock, flags);
337
Thomas Gleixner161d0492011-03-23 21:08:58 +0000338 return IRQ_SET_MASK_OK_NOCOPY;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100339}
340#endif
341
Andrew Bresticker4a6a3ea32014-09-18 14:47:26 -0700342static struct irq_chip gic_level_irq_controller = {
343 .name = "MIPS GIC",
344 .irq_mask = gic_mask_irq,
345 .irq_unmask = gic_unmask_irq,
346 .irq_set_type = gic_set_type,
347#ifdef CONFIG_SMP
348 .irq_set_affinity = gic_set_affinity,
349#endif
350};
351
352static struct irq_chip gic_edge_irq_controller = {
Thomas Gleixner161d0492011-03-23 21:08:58 +0000353 .name = "MIPS GIC",
Andrew Bresticker5561c9e2014-09-18 14:47:20 -0700354 .irq_ack = gic_ack_irq,
Thomas Gleixner161d0492011-03-23 21:08:58 +0000355 .irq_mask = gic_mask_irq,
Thomas Gleixner161d0492011-03-23 21:08:58 +0000356 .irq_unmask = gic_unmask_irq,
Andrew Bresticker95150ae2014-09-18 14:47:21 -0700357 .irq_set_type = gic_set_type,
Ralf Baechle39b8d522008-04-28 17:14:26 +0100358#ifdef CONFIG_SMP
Thomas Gleixner161d0492011-03-23 21:08:58 +0000359 .irq_set_affinity = gic_set_affinity,
Ralf Baechle39b8d522008-04-28 17:14:26 +0100360#endif
Qais Yousefbb11cff2015-12-08 13:20:28 +0000361 .ipi_send_single = gic_send_ipi,
Ralf Baechle39b8d522008-04-28 17:14:26 +0100362};
363
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200364static void gic_handle_local_int(bool chained)
Andrew Brestickere9de6882014-09-18 14:47:27 -0700365{
366 unsigned long pending, masked;
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000367 unsigned int intr, virq;
Andrew Brestickere9de6882014-09-18 14:47:27 -0700368
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100369 pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
370 masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK));
Andrew Brestickere9de6882014-09-18 14:47:27 -0700371
372 bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
373
Paul Burton0f4ed152016-09-13 17:54:27 +0100374 for_each_set_bit(intr, &pending, GIC_NUM_LOCAL_INTRS) {
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000375 virq = irq_linear_revmap(gic_irq_domain,
376 GIC_LOCAL_TO_HWIRQ(intr));
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200377 if (chained)
378 generic_handle_irq(virq);
379 else
380 do_IRQ(virq);
Qais Yousefd7eb4f22015-01-19 11:51:29 +0000381 }
Andrew Brestickere9de6882014-09-18 14:47:27 -0700382}
383
384static void gic_mask_local_irq(struct irq_data *d)
385{
386 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
387
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100388 gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700389}
390
391static void gic_unmask_local_irq(struct irq_data *d)
392{
393 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
394
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100395 gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700396}
397
398static struct irq_chip gic_local_irq_controller = {
399 .name = "MIPS GIC Local",
400 .irq_mask = gic_mask_local_irq,
401 .irq_unmask = gic_unmask_local_irq,
402};
403
404static void gic_mask_local_irq_all_vpes(struct irq_data *d)
405{
406 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
407 int i;
408 unsigned long flags;
409
410 spin_lock_irqsave(&gic_lock, flags);
411 for (i = 0; i < gic_vpes; i++) {
Paul Burtond46812b2016-02-03 03:15:27 +0000412 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
413 mips_cm_vp_id(i));
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100414 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700415 }
416 spin_unlock_irqrestore(&gic_lock, flags);
417}
418
419static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
420{
421 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
422 int i;
423 unsigned long flags;
424
425 spin_lock_irqsave(&gic_lock, flags);
426 for (i = 0; i < gic_vpes; i++) {
Paul Burtond46812b2016-02-03 03:15:27 +0000427 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
428 mips_cm_vp_id(i));
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100429 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700430 }
431 spin_unlock_irqrestore(&gic_lock, flags);
432}
433
434static struct irq_chip gic_all_vpes_local_irq_controller = {
435 .name = "MIPS GIC Local",
436 .irq_mask = gic_mask_local_irq_all_vpes,
437 .irq_unmask = gic_unmask_local_irq_all_vpes,
438};
439
Andrew Bresticker18743d22014-09-18 14:47:24 -0700440static void __gic_irq_dispatch(void)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100441{
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200442 gic_handle_local_int(false);
443 gic_handle_shared_int(false);
Andrew Bresticker18743d22014-09-18 14:47:24 -0700444}
445
Thomas Gleixnerbd0b9ac2015-09-14 10:42:37 +0200446static void gic_irq_dispatch(struct irq_desc *desc)
Andrew Bresticker18743d22014-09-18 14:47:24 -0700447{
Rabin Vincent1b3ed362015-06-12 10:01:56 +0200448 gic_handle_local_int(true);
449 gic_handle_shared_int(true);
Andrew Bresticker18743d22014-09-18 14:47:24 -0700450}
451
Andrew Brestickere9de6882014-09-18 14:47:27 -0700452static void __init gic_basic_init(void)
Andrew Bresticker18743d22014-09-18 14:47:24 -0700453{
454 unsigned int i;
Steven J. Hill98b67c32012-08-31 16:18:49 -0500455
456 board_bind_eic_interrupt = &gic_bind_eic_interrupt;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100457
458 /* Setup defaults */
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700459 for (i = 0; i < gic_shared_intrs; i++) {
Paul Burton80e5f9c2017-08-12 21:36:19 -0700460 change_gic_pol(i, GIC_POL_ACTIVE_HIGH);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700461 gic_set_trigger(i, GIC_TRIG_LEVEL);
Paul Burton87554b02017-08-12 21:36:18 -0700462 write_gic_rmask(BIT(i));
Ralf Baechle39b8d522008-04-28 17:14:26 +0100463 }
464
Andrew Brestickere9de6882014-09-18 14:47:27 -0700465 for (i = 0; i < gic_vpes; i++) {
466 unsigned int j;
467
Paul Burtond46812b2016-02-03 03:15:27 +0000468 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
469 mips_cm_vp_id(i));
Andrew Brestickere9de6882014-09-18 14:47:27 -0700470 for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
471 if (!gic_local_irq_is_routable(j))
472 continue;
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100473 gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700474 }
475 }
Ralf Baechle39b8d522008-04-28 17:14:26 +0100476}
477
Andrew Brestickere9de6882014-09-18 14:47:27 -0700478static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
479 irq_hw_number_t hw)
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700480{
Andrew Brestickere9de6882014-09-18 14:47:27 -0700481 int intr = GIC_HWIRQ_TO_LOCAL(hw);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700482 int i;
483 unsigned long flags;
Paul Burtona0dc5cb52017-08-12 21:36:17 -0700484 u32 val;
Andrew Brestickere9de6882014-09-18 14:47:27 -0700485
486 if (!gic_local_irq_is_routable(intr))
487 return -EPERM;
488
Paul Burtona0dc5cb52017-08-12 21:36:17 -0700489 if (intr > GIC_LOCAL_INT_FDC) {
490 pr_err("Invalid local IRQ %d\n", intr);
491 return -EINVAL;
492 }
493
494 if (intr == GIC_LOCAL_INT_TIMER) {
495 /* CONFIG_MIPS_CMP workaround (see __gic_init) */
496 val = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
497 } else {
498 val = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
499 }
500
Andrew Brestickere9de6882014-09-18 14:47:27 -0700501 spin_lock_irqsave(&gic_lock, flags);
502 for (i = 0; i < gic_vpes; i++) {
Paul Burtona0dc5cb52017-08-12 21:36:17 -0700503 write_gic_vl_other(mips_cm_vp_id(i));
504 write_gic_vo_map(intr, val);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700505 }
506 spin_unlock_irqrestore(&gic_lock, flags);
507
Paul Burtona0dc5cb52017-08-12 21:36:17 -0700508 return 0;
Andrew Brestickere9de6882014-09-18 14:47:27 -0700509}
510
511static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
Qais Yousef2af70a92015-12-08 13:20:23 +0000512 irq_hw_number_t hw, unsigned int vpe)
Andrew Brestickere9de6882014-09-18 14:47:27 -0700513{
514 int intr = GIC_HWIRQ_TO_SHARED(hw);
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700515 unsigned long flags;
Qais Yousef78930f02015-12-08 13:20:26 +0000516 int i;
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700517
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700518 spin_lock_irqsave(&gic_lock, flags);
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700519 gic_map_to_pin(intr, gic_cpu_pin);
Paul Burton99ec8a32016-07-05 14:25:59 +0100520 gic_map_to_vpe(intr, mips_cm_vp_id(vpe));
Paul Burton91951f92016-04-21 11:31:54 +0100521 for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
Qais Yousef78930f02015-12-08 13:20:26 +0000522 clear_bit(intr, pcpu_masks[i].pcpu_mask);
Qais Yousef2af70a92015-12-08 13:20:23 +0000523 set_bit(intr, pcpu_masks[vpe].pcpu_mask);
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700524 spin_unlock_irqrestore(&gic_lock, flags);
525
526 return 0;
527}
528
Paul Burtonb87281e2017-04-20 10:07:35 +0100529static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
Qais Yousefc98c18222015-12-08 13:20:24 +0000530 const u32 *intspec, unsigned int intsize,
531 irq_hw_number_t *out_hwirq,
532 unsigned int *out_type)
533{
534 if (intsize != 3)
535 return -EINVAL;
536
537 if (intspec[0] == GIC_SHARED)
538 *out_hwirq = GIC_SHARED_TO_HWIRQ(intspec[1]);
539 else if (intspec[0] == GIC_LOCAL)
540 *out_hwirq = GIC_LOCAL_TO_HWIRQ(intspec[1]);
541 else
542 return -EINVAL;
543 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
544
545 return 0;
546}
547
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100548static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
549 irq_hw_number_t hwirq)
Qais Yousefc98c18222015-12-08 13:20:24 +0000550{
Paul Burtonb87281e2017-04-20 10:07:35 +0100551 int err;
Qais Yousefc98c18222015-12-08 13:20:24 +0000552
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100553 if (hwirq >= GIC_SHARED_HWIRQ_BASE) {
Paul Burtonb87281e2017-04-20 10:07:35 +0100554 /* verify that shared irqs don't conflict with an IPI irq */
555 if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv))
556 return -EBUSY;
Qais Yousefc98c18222015-12-08 13:20:24 +0000557
Paul Burtonb87281e2017-04-20 10:07:35 +0100558 err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
559 &gic_level_irq_controller,
560 NULL);
561 if (err)
562 return err;
563
564 return gic_shared_irq_domain_map(d, virq, hwirq, 0);
Qais Yousefc98c18222015-12-08 13:20:24 +0000565 }
566
Paul Burtonb87281e2017-04-20 10:07:35 +0100567 switch (GIC_HWIRQ_TO_LOCAL(hwirq)) {
568 case GIC_LOCAL_INT_TIMER:
569 case GIC_LOCAL_INT_PERFCTR:
570 case GIC_LOCAL_INT_FDC:
571 /*
572 * HACK: These are all really percpu interrupts, but
573 * the rest of the MIPS kernel code does not use the
574 * percpu IRQ API for them.
575 */
576 err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
577 &gic_all_vpes_local_irq_controller,
578 NULL);
579 if (err)
580 return err;
581
582 irq_set_handler(virq, handle_percpu_irq);
583 break;
584
585 default:
586 err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
587 &gic_local_irq_controller,
588 NULL);
589 if (err)
590 return err;
591
592 irq_set_handler(virq, handle_percpu_devid_irq);
593 irq_set_percpu_devid(virq);
594 break;
595 }
596
597 return gic_local_irq_domain_map(d, virq, hwirq);
Qais Yousefc98c18222015-12-08 13:20:24 +0000598}
599
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100600static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
601 unsigned int nr_irqs, void *arg)
602{
603 struct irq_fwspec *fwspec = arg;
604 irq_hw_number_t hwirq;
605
606 if (fwspec->param[0] == GIC_SHARED)
607 hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]);
608 else
609 hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]);
610
611 return gic_irq_domain_map(d, virq, hwirq);
612}
613
Paul Burtonb87281e2017-04-20 10:07:35 +0100614void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
Qais Yousefc98c18222015-12-08 13:20:24 +0000615 unsigned int nr_irqs)
616{
Qais Yousefc98c18222015-12-08 13:20:24 +0000617}
618
Paul Burtonb87281e2017-04-20 10:07:35 +0100619static const struct irq_domain_ops gic_irq_domain_ops = {
620 .xlate = gic_irq_domain_xlate,
621 .alloc = gic_irq_domain_alloc,
622 .free = gic_irq_domain_free,
Matt Redfearn8ada00a2017-04-20 10:07:36 +0100623 .map = gic_irq_domain_map,
Qais Yousef2af70a92015-12-08 13:20:23 +0000624};
625
626static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
627 const u32 *intspec, unsigned int intsize,
628 irq_hw_number_t *out_hwirq,
629 unsigned int *out_type)
630{
631 /*
632 * There's nothing to translate here. hwirq is dynamically allocated and
633 * the irq type is always edge triggered.
634 * */
635 *out_hwirq = 0;
636 *out_type = IRQ_TYPE_EDGE_RISING;
637
638 return 0;
639}
640
641static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq,
642 unsigned int nr_irqs, void *arg)
643{
644 struct cpumask *ipimask = arg;
Paul Burtonb87281e2017-04-20 10:07:35 +0100645 irq_hw_number_t hwirq, base_hwirq;
646 int cpu, ret, i;
Qais Yousef2af70a92015-12-08 13:20:23 +0000647
Paul Burtonb87281e2017-04-20 10:07:35 +0100648 base_hwirq = find_first_bit(ipi_available, gic_shared_intrs);
649 if (base_hwirq == gic_shared_intrs)
650 return -ENOMEM;
Qais Yousef2af70a92015-12-08 13:20:23 +0000651
Paul Burtonb87281e2017-04-20 10:07:35 +0100652 /* check that we have enough space */
653 for (i = base_hwirq; i < nr_irqs; i++) {
654 if (!test_bit(i, ipi_available))
655 return -EBUSY;
656 }
657 bitmap_clear(ipi_available, base_hwirq, nr_irqs);
658
659 /* map the hwirq for each cpu consecutively */
660 i = 0;
661 for_each_cpu(cpu, ipimask) {
662 hwirq = GIC_SHARED_TO_HWIRQ(base_hwirq + i);
663
664 ret = irq_domain_set_hwirq_and_chip(d, virq + i, hwirq,
665 &gic_edge_irq_controller,
666 NULL);
667 if (ret)
668 goto error;
669
670 ret = irq_domain_set_hwirq_and_chip(d->parent, virq + i, hwirq,
Qais Yousef2af70a92015-12-08 13:20:23 +0000671 &gic_edge_irq_controller,
672 NULL);
673 if (ret)
674 goto error;
675
676 ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING);
677 if (ret)
678 goto error;
Paul Burtonb87281e2017-04-20 10:07:35 +0100679
680 ret = gic_shared_irq_domain_map(d, virq + i, hwirq, cpu);
681 if (ret)
682 goto error;
683
684 i++;
Qais Yousef2af70a92015-12-08 13:20:23 +0000685 }
686
687 return 0;
688error:
Paul Burtonb87281e2017-04-20 10:07:35 +0100689 bitmap_set(ipi_available, base_hwirq, nr_irqs);
Qais Yousef2af70a92015-12-08 13:20:23 +0000690 return ret;
691}
692
693void gic_ipi_domain_free(struct irq_domain *d, unsigned int virq,
694 unsigned int nr_irqs)
695{
Paul Burtonb87281e2017-04-20 10:07:35 +0100696 irq_hw_number_t base_hwirq;
697 struct irq_data *data;
698
699 data = irq_get_irq_data(virq);
700 if (!data)
701 return;
702
703 base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data));
704 bitmap_set(ipi_available, base_hwirq, nr_irqs);
Qais Yousef2af70a92015-12-08 13:20:23 +0000705}
706
707int gic_ipi_domain_match(struct irq_domain *d, struct device_node *node,
708 enum irq_domain_bus_token bus_token)
709{
710 bool is_ipi;
711
712 switch (bus_token) {
713 case DOMAIN_BUS_IPI:
714 is_ipi = d->bus_token == bus_token;
Paul Burton547aefc2016-07-05 14:26:00 +0100715 return (!node || to_of_node(d->fwnode) == node) && is_ipi;
Qais Yousef2af70a92015-12-08 13:20:23 +0000716 break;
717 default:
718 return 0;
719 }
720}
721
Tobias Klauser0b7e8152017-06-02 10:20:56 +0200722static const struct irq_domain_ops gic_ipi_domain_ops = {
Qais Yousef2af70a92015-12-08 13:20:23 +0000723 .xlate = gic_ipi_domain_xlate,
724 .alloc = gic_ipi_domain_alloc,
725 .free = gic_ipi_domain_free,
726 .match = gic_ipi_domain_match,
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700727};
728
Andrew Brestickera7057272014-11-12 11:43:38 -0800729static void __init __gic_init(unsigned long gic_base_addr,
730 unsigned long gic_addrspace_size,
731 unsigned int cpu_vec, unsigned int irqbase,
732 struct device_node *node)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100733{
Paul Burtonba01cf02016-05-17 15:31:06 +0100734 unsigned int gicconfig, cpu;
Qais Yousef16a80832015-12-08 13:20:30 +0000735 unsigned int v[2];
Ralf Baechle39b8d522008-04-28 17:14:26 +0100736
Alex Smithc0a9f722015-10-12 10:40:43 +0100737 __gic_base_addr = gic_base_addr;
738
Paul Burton582e2b42017-08-12 21:36:10 -0700739 mips_gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100740
Andrew Bresticker5f68fea2014-10-20 12:03:52 -0700741 gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700742 gic_shared_intrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
Ralf Baechle39b8d522008-04-28 17:14:26 +0100743 GIC_SH_CONFIG_NUMINTRS_SHF;
Andrew Brestickerfbd55242014-09-18 14:47:25 -0700744 gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100745
Andrew Brestickere9de6882014-09-18 14:47:27 -0700746 gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
Ralf Baechle39b8d522008-04-28 17:14:26 +0100747 GIC_SH_CONFIG_NUMVPES_SHF;
Andrew Brestickere9de6882014-09-18 14:47:27 -0700748 gic_vpes = gic_vpes + 1;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100749
Andrew Bresticker18743d22014-09-18 14:47:24 -0700750 if (cpu_has_veic) {
Paul Burtonba01cf02016-05-17 15:31:06 +0100751 /* Set EIC mode for all VPEs */
752 for_each_present_cpu(cpu) {
753 gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
754 mips_cm_vp_id(cpu));
755 gic_write(GIC_REG(VPE_OTHER, GIC_VPE_CTL),
756 GIC_VPE_CTL_EIC_MODE_MSK);
757 }
758
Andrew Bresticker18743d22014-09-18 14:47:24 -0700759 /* Always use vector 1 in EIC mode */
760 gic_cpu_pin = 0;
James Hogan1b6af712015-01-19 15:38:24 +0000761 timer_cpu_pin = gic_cpu_pin;
Andrew Bresticker18743d22014-09-18 14:47:24 -0700762 set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
763 __gic_irq_dispatch);
764 } else {
765 gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
766 irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
767 gic_irq_dispatch);
James Hogan1b6af712015-01-19 15:38:24 +0000768 /*
769 * With the CMP implementation of SMP (deprecated), other CPUs
770 * are started by the bootloader and put into a timer based
771 * waiting poll loop. We must not re-route those CPU's local
772 * timer interrupts as the wait instruction will never finish,
773 * so just handle whatever CPU interrupt it is routed to by
774 * default.
775 *
776 * This workaround should be removed when CMP support is
777 * dropped.
778 */
779 if (IS_ENABLED(CONFIG_MIPS_CMP) &&
780 gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) {
Markos Chandrasc3f57f02015-07-14 10:26:09 +0100781 timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL,
James Hogan1b6af712015-01-19 15:38:24 +0000782 GIC_VPE_TIMER_MAP)) &
783 GIC_MAP_MSK;
784 irq_set_chained_handler(MIPS_CPU_IRQ_BASE +
785 GIC_CPU_PIN_OFFSET +
786 timer_cpu_pin,
787 gic_irq_dispatch);
788 } else {
789 timer_cpu_pin = gic_cpu_pin;
790 }
Andrew Bresticker18743d22014-09-18 14:47:24 -0700791 }
792
Andrew Brestickera7057272014-11-12 11:43:38 -0800793 gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +
Andrew Brestickere9de6882014-09-18 14:47:27 -0700794 gic_shared_intrs, irqbase,
Andrew Brestickerc49581a2014-09-18 14:47:23 -0700795 &gic_irq_domain_ops, NULL);
796 if (!gic_irq_domain)
797 panic("Failed to add GIC IRQ domain");
Steven J. Hill0b271f52012-08-31 16:05:37 -0500798
Qais Yousef2af70a92015-12-08 13:20:23 +0000799 gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
800 IRQ_DOMAIN_FLAG_IPI_PER_CPU,
801 GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
802 node, &gic_ipi_domain_ops, NULL);
803 if (!gic_ipi_domain)
804 panic("Failed to add GIC IPI domain");
805
Marc Zyngier96f0d932017-06-22 11:42:50 +0100806 irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI);
Qais Yousef2af70a92015-12-08 13:20:23 +0000807
Qais Yousef16a80832015-12-08 13:20:30 +0000808 if (node &&
809 !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) {
810 bitmap_set(ipi_resrv, v[0], v[1]);
811 } else {
812 /* Make the last 2 * gic_vpes available for IPIs */
813 bitmap_set(ipi_resrv,
814 gic_shared_intrs - 2 * gic_vpes,
815 2 * gic_vpes);
816 }
Qais Yousef2af70a92015-12-08 13:20:23 +0000817
Paul Burtonf8dcd9e2017-04-20 10:07:34 +0100818 bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
Andrew Brestickere9de6882014-09-18 14:47:27 -0700819 gic_basic_init();
Ralf Baechle39b8d522008-04-28 17:14:26 +0100820}
Andrew Brestickera7057272014-11-12 11:43:38 -0800821
822void __init gic_init(unsigned long gic_base_addr,
823 unsigned long gic_addrspace_size,
824 unsigned int cpu_vec, unsigned int irqbase)
825{
826 __gic_init(gic_base_addr, gic_addrspace_size, cpu_vec, irqbase, NULL);
827}
828
829static int __init gic_of_init(struct device_node *node,
830 struct device_node *parent)
831{
832 struct resource res;
833 unsigned int cpu_vec, i = 0, reserved = 0;
834 phys_addr_t gic_base;
835 size_t gic_len;
836
837 /* Find the first available CPU vector. */
838 while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors",
839 i++, &cpu_vec))
840 reserved |= BIT(cpu_vec);
841 for (cpu_vec = 2; cpu_vec < 8; cpu_vec++) {
842 if (!(reserved & BIT(cpu_vec)))
843 break;
844 }
845 if (cpu_vec == 8) {
846 pr_err("No CPU vectors available for GIC\n");
847 return -ENODEV;
848 }
849
850 if (of_address_to_resource(node, 0, &res)) {
851 /*
852 * Probe the CM for the GIC base address if not specified
853 * in the device-tree.
854 */
855 if (mips_cm_present()) {
856 gic_base = read_gcr_gic_base() &
Paul Burton93c5bba52017-08-12 19:49:27 -0700857 ~CM_GCR_GIC_BASE_GICEN;
Andrew Brestickera7057272014-11-12 11:43:38 -0800858 gic_len = 0x20000;
859 } else {
860 pr_err("Failed to get GIC memory range\n");
861 return -ENODEV;
862 }
863 } else {
864 gic_base = res.start;
865 gic_len = resource_size(&res);
866 }
867
James Hogana0ffec32017-08-12 21:36:09 -0700868 if (mips_cm_present()) {
Paul Burton93c5bba52017-08-12 19:49:27 -0700869 write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN);
James Hogana0ffec32017-08-12 21:36:09 -0700870 /* Ensure GIC region is enabled before trying to access it */
871 __sync();
872 }
Andrew Brestickera7057272014-11-12 11:43:38 -0800873 gic_present = true;
874
875 __gic_init(gic_base, gic_len, cpu_vec, 0, node);
876
877 return 0;
878}
879IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init);