1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
3*4882a593Smuzhiyun * License. See the file "COPYING" in the main directory of this archive
4*4882a593Smuzhiyun * for more details.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 2004-2016 Cavium, Inc.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/of_address.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/irqdomain.h>
12*4882a593Smuzhiyun #include <linux/bitops.h>
13*4882a593Smuzhiyun #include <linux/of_irq.h>
14*4882a593Smuzhiyun #include <linux/percpu.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun #include <linux/smp.h>
18*4882a593Smuzhiyun #include <linux/of.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <asm/octeon/octeon.h>
21*4882a593Smuzhiyun #include <asm/octeon/cvmx-ciu2-defs.h>
22*4882a593Smuzhiyun #include <asm/octeon/cvmx-ciu3-defs.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun static DEFINE_PER_CPU(unsigned long, octeon_irq_ciu0_en_mirror);
25*4882a593Smuzhiyun static DEFINE_PER_CPU(unsigned long, octeon_irq_ciu1_en_mirror);
26*4882a593Smuzhiyun static DEFINE_PER_CPU(raw_spinlock_t, octeon_irq_ciu_spinlock);
27*4882a593Smuzhiyun static DEFINE_PER_CPU(unsigned int, octeon_irq_ciu3_idt_ip2);
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun static DEFINE_PER_CPU(unsigned int, octeon_irq_ciu3_idt_ip3);
30*4882a593Smuzhiyun static DEFINE_PER_CPU(struct octeon_ciu3_info *, octeon_ciu3_info);
31*4882a593Smuzhiyun #define CIU3_MBOX_PER_CORE 10
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun * The 8 most significant bits of the intsn identify the interrupt major block.
35*4882a593Smuzhiyun * Each major block might use its own interrupt domain. Thus 256 domains are
36*4882a593Smuzhiyun * needed.
37*4882a593Smuzhiyun */
38*4882a593Smuzhiyun #define MAX_CIU3_DOMAINS 256
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun typedef irq_hw_number_t (*octeon_ciu3_intsn2hw_t)(struct irq_domain *, unsigned int);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* Information for each ciu3 in the system */
43*4882a593Smuzhiyun struct octeon_ciu3_info {
44*4882a593Smuzhiyun u64 ciu3_addr;
45*4882a593Smuzhiyun int node;
46*4882a593Smuzhiyun struct irq_domain *domain[MAX_CIU3_DOMAINS];
47*4882a593Smuzhiyun octeon_ciu3_intsn2hw_t intsn2hw[MAX_CIU3_DOMAINS];
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* Each ciu3 in the system uses its own data (one ciu3 per node) */
51*4882a593Smuzhiyun static struct octeon_ciu3_info *octeon_ciu3_info_per_node[4];
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct octeon_irq_ciu_domain_data {
54*4882a593Smuzhiyun int num_sum; /* number of sum registers (2 or 3). */
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* Register offsets from ciu3_addr */
58*4882a593Smuzhiyun #define CIU3_CONST 0x220
59*4882a593Smuzhiyun #define CIU3_IDT_CTL(_idt) ((_idt) * 8 + 0x110000)
60*4882a593Smuzhiyun #define CIU3_IDT_PP(_idt, _idx) ((_idt) * 32 + (_idx) * 8 + 0x120000)
61*4882a593Smuzhiyun #define CIU3_IDT_IO(_idt) ((_idt) * 8 + 0x130000)
62*4882a593Smuzhiyun #define CIU3_DEST_PP_INT(_pp_ip) ((_pp_ip) * 8 + 0x200000)
63*4882a593Smuzhiyun #define CIU3_DEST_IO_INT(_io) ((_io) * 8 + 0x210000)
64*4882a593Smuzhiyun #define CIU3_ISC_CTL(_intsn) ((_intsn) * 8 + 0x80000000)
65*4882a593Smuzhiyun #define CIU3_ISC_W1C(_intsn) ((_intsn) * 8 + 0x90000000)
66*4882a593Smuzhiyun #define CIU3_ISC_W1S(_intsn) ((_intsn) * 8 + 0xa0000000)
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun static __read_mostly int octeon_irq_ciu_to_irq[8][64];
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun struct octeon_ciu_chip_data {
71*4882a593Smuzhiyun union {
72*4882a593Smuzhiyun struct { /* only used for ciu3 */
73*4882a593Smuzhiyun u64 ciu3_addr;
74*4882a593Smuzhiyun unsigned int intsn;
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun struct { /* only used for ciu/ciu2 */
77*4882a593Smuzhiyun u8 line;
78*4882a593Smuzhiyun u8 bit;
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun int gpio_line;
82*4882a593Smuzhiyun int current_cpu; /* Next CPU expected to take this irq */
83*4882a593Smuzhiyun int ciu_node; /* NUMA node number of the CIU */
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun struct octeon_core_chip_data {
87*4882a593Smuzhiyun struct mutex core_irq_mutex;
88*4882a593Smuzhiyun bool current_en;
89*4882a593Smuzhiyun bool desired_en;
90*4882a593Smuzhiyun u8 bit;
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define MIPS_CORE_IRQ_LINES 8
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun static struct octeon_core_chip_data octeon_irq_core_chip_data[MIPS_CORE_IRQ_LINES];
96*4882a593Smuzhiyun
octeon_irq_set_ciu_mapping(int irq,int line,int bit,int gpio_line,struct irq_chip * chip,irq_flow_handler_t handler)97*4882a593Smuzhiyun static int octeon_irq_set_ciu_mapping(int irq, int line, int bit, int gpio_line,
98*4882a593Smuzhiyun struct irq_chip *chip,
99*4882a593Smuzhiyun irq_flow_handler_t handler)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun cd = kzalloc(sizeof(*cd), GFP_KERNEL);
104*4882a593Smuzhiyun if (!cd)
105*4882a593Smuzhiyun return -ENOMEM;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun irq_set_chip_and_handler(irq, chip, handler);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun cd->line = line;
110*4882a593Smuzhiyun cd->bit = bit;
111*4882a593Smuzhiyun cd->gpio_line = gpio_line;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun irq_set_chip_data(irq, cd);
114*4882a593Smuzhiyun octeon_irq_ciu_to_irq[line][bit] = irq;
115*4882a593Smuzhiyun return 0;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
octeon_irq_free_cd(struct irq_domain * d,unsigned int irq)118*4882a593Smuzhiyun static void octeon_irq_free_cd(struct irq_domain *d, unsigned int irq)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun struct irq_data *data = irq_get_irq_data(irq);
121*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data);
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun irq_set_chip_data(irq, NULL);
124*4882a593Smuzhiyun kfree(cd);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
octeon_irq_force_ciu_mapping(struct irq_domain * domain,int irq,int line,int bit)127*4882a593Smuzhiyun static int octeon_irq_force_ciu_mapping(struct irq_domain *domain,
128*4882a593Smuzhiyun int irq, int line, int bit)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun struct device_node *of_node;
131*4882a593Smuzhiyun int ret;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun of_node = irq_domain_get_of_node(domain);
134*4882a593Smuzhiyun if (!of_node)
135*4882a593Smuzhiyun return -EINVAL;
136*4882a593Smuzhiyun ret = irq_alloc_desc_at(irq, of_node_to_nid(of_node));
137*4882a593Smuzhiyun if (ret < 0)
138*4882a593Smuzhiyun return ret;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun return irq_domain_associate(domain, irq, line << 6 | bit);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
octeon_coreid_for_cpu(int cpu)143*4882a593Smuzhiyun static int octeon_coreid_for_cpu(int cpu)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun #ifdef CONFIG_SMP
146*4882a593Smuzhiyun return cpu_logical_map(cpu);
147*4882a593Smuzhiyun #else
148*4882a593Smuzhiyun return cvmx_get_core_num();
149*4882a593Smuzhiyun #endif
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
octeon_cpu_for_coreid(int coreid)152*4882a593Smuzhiyun static int octeon_cpu_for_coreid(int coreid)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun #ifdef CONFIG_SMP
155*4882a593Smuzhiyun return cpu_number_map(coreid);
156*4882a593Smuzhiyun #else
157*4882a593Smuzhiyun return smp_processor_id();
158*4882a593Smuzhiyun #endif
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
octeon_irq_core_ack(struct irq_data * data)161*4882a593Smuzhiyun static void octeon_irq_core_ack(struct irq_data *data)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct octeon_core_chip_data *cd = irq_data_get_irq_chip_data(data);
164*4882a593Smuzhiyun unsigned int bit = cd->bit;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /*
167*4882a593Smuzhiyun * We don't need to disable IRQs to make these atomic since
168*4882a593Smuzhiyun * they are already disabled earlier in the low level
169*4882a593Smuzhiyun * interrupt code.
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun clear_c0_status(0x100 << bit);
172*4882a593Smuzhiyun /* The two user interrupts must be cleared manually. */
173*4882a593Smuzhiyun if (bit < 2)
174*4882a593Smuzhiyun clear_c0_cause(0x100 << bit);
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
octeon_irq_core_eoi(struct irq_data * data)177*4882a593Smuzhiyun static void octeon_irq_core_eoi(struct irq_data *data)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun struct octeon_core_chip_data *cd = irq_data_get_irq_chip_data(data);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /*
182*4882a593Smuzhiyun * We don't need to disable IRQs to make these atomic since
183*4882a593Smuzhiyun * they are already disabled earlier in the low level
184*4882a593Smuzhiyun * interrupt code.
185*4882a593Smuzhiyun */
186*4882a593Smuzhiyun set_c0_status(0x100 << cd->bit);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
octeon_irq_core_set_enable_local(void * arg)189*4882a593Smuzhiyun static void octeon_irq_core_set_enable_local(void *arg)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct irq_data *data = arg;
192*4882a593Smuzhiyun struct octeon_core_chip_data *cd = irq_data_get_irq_chip_data(data);
193*4882a593Smuzhiyun unsigned int mask = 0x100 << cd->bit;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /*
196*4882a593Smuzhiyun * Interrupts are already disabled, so these are atomic.
197*4882a593Smuzhiyun */
198*4882a593Smuzhiyun if (cd->desired_en)
199*4882a593Smuzhiyun set_c0_status(mask);
200*4882a593Smuzhiyun else
201*4882a593Smuzhiyun clear_c0_status(mask);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
octeon_irq_core_disable(struct irq_data * data)205*4882a593Smuzhiyun static void octeon_irq_core_disable(struct irq_data *data)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun struct octeon_core_chip_data *cd = irq_data_get_irq_chip_data(data);
208*4882a593Smuzhiyun cd->desired_en = false;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
octeon_irq_core_enable(struct irq_data * data)211*4882a593Smuzhiyun static void octeon_irq_core_enable(struct irq_data *data)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun struct octeon_core_chip_data *cd = irq_data_get_irq_chip_data(data);
214*4882a593Smuzhiyun cd->desired_en = true;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
octeon_irq_core_bus_lock(struct irq_data * data)217*4882a593Smuzhiyun static void octeon_irq_core_bus_lock(struct irq_data *data)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun struct octeon_core_chip_data *cd = irq_data_get_irq_chip_data(data);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun mutex_lock(&cd->core_irq_mutex);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
octeon_irq_core_bus_sync_unlock(struct irq_data * data)224*4882a593Smuzhiyun static void octeon_irq_core_bus_sync_unlock(struct irq_data *data)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun struct octeon_core_chip_data *cd = irq_data_get_irq_chip_data(data);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (cd->desired_en != cd->current_en) {
229*4882a593Smuzhiyun on_each_cpu(octeon_irq_core_set_enable_local, data, 1);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun cd->current_en = cd->desired_en;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun mutex_unlock(&cd->core_irq_mutex);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_core = {
238*4882a593Smuzhiyun .name = "Core",
239*4882a593Smuzhiyun .irq_enable = octeon_irq_core_enable,
240*4882a593Smuzhiyun .irq_disable = octeon_irq_core_disable,
241*4882a593Smuzhiyun .irq_ack = octeon_irq_core_ack,
242*4882a593Smuzhiyun .irq_eoi = octeon_irq_core_eoi,
243*4882a593Smuzhiyun .irq_bus_lock = octeon_irq_core_bus_lock,
244*4882a593Smuzhiyun .irq_bus_sync_unlock = octeon_irq_core_bus_sync_unlock,
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun .irq_cpu_online = octeon_irq_core_eoi,
247*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_core_ack,
248*4882a593Smuzhiyun .flags = IRQCHIP_ONOFFLINE_ENABLED,
249*4882a593Smuzhiyun };
250*4882a593Smuzhiyun
octeon_irq_init_core(void)251*4882a593Smuzhiyun static void __init octeon_irq_init_core(void)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun int i;
254*4882a593Smuzhiyun int irq;
255*4882a593Smuzhiyun struct octeon_core_chip_data *cd;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun for (i = 0; i < MIPS_CORE_IRQ_LINES; i++) {
258*4882a593Smuzhiyun cd = &octeon_irq_core_chip_data[i];
259*4882a593Smuzhiyun cd->current_en = false;
260*4882a593Smuzhiyun cd->desired_en = false;
261*4882a593Smuzhiyun cd->bit = i;
262*4882a593Smuzhiyun mutex_init(&cd->core_irq_mutex);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun irq = OCTEON_IRQ_SW0 + i;
265*4882a593Smuzhiyun irq_set_chip_data(irq, cd);
266*4882a593Smuzhiyun irq_set_chip_and_handler(irq, &octeon_irq_chip_core,
267*4882a593Smuzhiyun handle_percpu_irq);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
next_cpu_for_irq(struct irq_data * data)271*4882a593Smuzhiyun static int next_cpu_for_irq(struct irq_data *data)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun #ifdef CONFIG_SMP
275*4882a593Smuzhiyun int cpu;
276*4882a593Smuzhiyun struct cpumask *mask = irq_data_get_affinity_mask(data);
277*4882a593Smuzhiyun int weight = cpumask_weight(mask);
278*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun if (weight > 1) {
281*4882a593Smuzhiyun cpu = cd->current_cpu;
282*4882a593Smuzhiyun for (;;) {
283*4882a593Smuzhiyun cpu = cpumask_next(cpu, mask);
284*4882a593Smuzhiyun if (cpu >= nr_cpu_ids) {
285*4882a593Smuzhiyun cpu = -1;
286*4882a593Smuzhiyun continue;
287*4882a593Smuzhiyun } else if (cpumask_test_cpu(cpu, cpu_online_mask)) {
288*4882a593Smuzhiyun break;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun } else if (weight == 1) {
292*4882a593Smuzhiyun cpu = cpumask_first(mask);
293*4882a593Smuzhiyun } else {
294*4882a593Smuzhiyun cpu = smp_processor_id();
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun cd->current_cpu = cpu;
297*4882a593Smuzhiyun return cpu;
298*4882a593Smuzhiyun #else
299*4882a593Smuzhiyun return smp_processor_id();
300*4882a593Smuzhiyun #endif
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
octeon_irq_ciu_enable(struct irq_data * data)303*4882a593Smuzhiyun static void octeon_irq_ciu_enable(struct irq_data *data)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun int cpu = next_cpu_for_irq(data);
306*4882a593Smuzhiyun int coreid = octeon_coreid_for_cpu(cpu);
307*4882a593Smuzhiyun unsigned long *pen;
308*4882a593Smuzhiyun unsigned long flags;
309*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
310*4882a593Smuzhiyun raw_spinlock_t *lock = &per_cpu(octeon_irq_ciu_spinlock, cpu);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun raw_spin_lock_irqsave(lock, flags);
315*4882a593Smuzhiyun if (cd->line == 0) {
316*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu0_en_mirror, cpu);
317*4882a593Smuzhiyun __set_bit(cd->bit, pen);
318*4882a593Smuzhiyun /*
319*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
320*4882a593Smuzhiyun * enabling the irq.
321*4882a593Smuzhiyun */
322*4882a593Smuzhiyun wmb();
323*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), *pen);
324*4882a593Smuzhiyun } else {
325*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu1_en_mirror, cpu);
326*4882a593Smuzhiyun __set_bit(cd->bit, pen);
327*4882a593Smuzhiyun /*
328*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
329*4882a593Smuzhiyun * enabling the irq.
330*4882a593Smuzhiyun */
331*4882a593Smuzhiyun wmb();
332*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), *pen);
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun raw_spin_unlock_irqrestore(lock, flags);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
octeon_irq_ciu_enable_local(struct irq_data * data)337*4882a593Smuzhiyun static void octeon_irq_ciu_enable_local(struct irq_data *data)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun unsigned long *pen;
340*4882a593Smuzhiyun unsigned long flags;
341*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
342*4882a593Smuzhiyun raw_spinlock_t *lock = this_cpu_ptr(&octeon_irq_ciu_spinlock);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun raw_spin_lock_irqsave(lock, flags);
347*4882a593Smuzhiyun if (cd->line == 0) {
348*4882a593Smuzhiyun pen = this_cpu_ptr(&octeon_irq_ciu0_en_mirror);
349*4882a593Smuzhiyun __set_bit(cd->bit, pen);
350*4882a593Smuzhiyun /*
351*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
352*4882a593Smuzhiyun * enabling the irq.
353*4882a593Smuzhiyun */
354*4882a593Smuzhiyun wmb();
355*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2), *pen);
356*4882a593Smuzhiyun } else {
357*4882a593Smuzhiyun pen = this_cpu_ptr(&octeon_irq_ciu1_en_mirror);
358*4882a593Smuzhiyun __set_bit(cd->bit, pen);
359*4882a593Smuzhiyun /*
360*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
361*4882a593Smuzhiyun * enabling the irq.
362*4882a593Smuzhiyun */
363*4882a593Smuzhiyun wmb();
364*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num() * 2 + 1), *pen);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun raw_spin_unlock_irqrestore(lock, flags);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
octeon_irq_ciu_disable_local(struct irq_data * data)369*4882a593Smuzhiyun static void octeon_irq_ciu_disable_local(struct irq_data *data)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun unsigned long *pen;
372*4882a593Smuzhiyun unsigned long flags;
373*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
374*4882a593Smuzhiyun raw_spinlock_t *lock = this_cpu_ptr(&octeon_irq_ciu_spinlock);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun raw_spin_lock_irqsave(lock, flags);
379*4882a593Smuzhiyun if (cd->line == 0) {
380*4882a593Smuzhiyun pen = this_cpu_ptr(&octeon_irq_ciu0_en_mirror);
381*4882a593Smuzhiyun __clear_bit(cd->bit, pen);
382*4882a593Smuzhiyun /*
383*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
384*4882a593Smuzhiyun * enabling the irq.
385*4882a593Smuzhiyun */
386*4882a593Smuzhiyun wmb();
387*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2), *pen);
388*4882a593Smuzhiyun } else {
389*4882a593Smuzhiyun pen = this_cpu_ptr(&octeon_irq_ciu1_en_mirror);
390*4882a593Smuzhiyun __clear_bit(cd->bit, pen);
391*4882a593Smuzhiyun /*
392*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
393*4882a593Smuzhiyun * enabling the irq.
394*4882a593Smuzhiyun */
395*4882a593Smuzhiyun wmb();
396*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num() * 2 + 1), *pen);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun raw_spin_unlock_irqrestore(lock, flags);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
octeon_irq_ciu_disable_all(struct irq_data * data)401*4882a593Smuzhiyun static void octeon_irq_ciu_disable_all(struct irq_data *data)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun unsigned long flags;
404*4882a593Smuzhiyun unsigned long *pen;
405*4882a593Smuzhiyun int cpu;
406*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
407*4882a593Smuzhiyun raw_spinlock_t *lock;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun for_each_online_cpu(cpu) {
412*4882a593Smuzhiyun int coreid = octeon_coreid_for_cpu(cpu);
413*4882a593Smuzhiyun lock = &per_cpu(octeon_irq_ciu_spinlock, cpu);
414*4882a593Smuzhiyun if (cd->line == 0)
415*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu0_en_mirror, cpu);
416*4882a593Smuzhiyun else
417*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu1_en_mirror, cpu);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun raw_spin_lock_irqsave(lock, flags);
420*4882a593Smuzhiyun __clear_bit(cd->bit, pen);
421*4882a593Smuzhiyun /*
422*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
423*4882a593Smuzhiyun * enabling the irq.
424*4882a593Smuzhiyun */
425*4882a593Smuzhiyun wmb();
426*4882a593Smuzhiyun if (cd->line == 0)
427*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), *pen);
428*4882a593Smuzhiyun else
429*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), *pen);
430*4882a593Smuzhiyun raw_spin_unlock_irqrestore(lock, flags);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
octeon_irq_ciu_enable_all(struct irq_data * data)434*4882a593Smuzhiyun static void octeon_irq_ciu_enable_all(struct irq_data *data)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun unsigned long flags;
437*4882a593Smuzhiyun unsigned long *pen;
438*4882a593Smuzhiyun int cpu;
439*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
440*4882a593Smuzhiyun raw_spinlock_t *lock;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun for_each_online_cpu(cpu) {
445*4882a593Smuzhiyun int coreid = octeon_coreid_for_cpu(cpu);
446*4882a593Smuzhiyun lock = &per_cpu(octeon_irq_ciu_spinlock, cpu);
447*4882a593Smuzhiyun if (cd->line == 0)
448*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu0_en_mirror, cpu);
449*4882a593Smuzhiyun else
450*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu1_en_mirror, cpu);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun raw_spin_lock_irqsave(lock, flags);
453*4882a593Smuzhiyun __set_bit(cd->bit, pen);
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
456*4882a593Smuzhiyun * enabling the irq.
457*4882a593Smuzhiyun */
458*4882a593Smuzhiyun wmb();
459*4882a593Smuzhiyun if (cd->line == 0)
460*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), *pen);
461*4882a593Smuzhiyun else
462*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), *pen);
463*4882a593Smuzhiyun raw_spin_unlock_irqrestore(lock, flags);
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /*
468*4882a593Smuzhiyun * Enable the irq on the next core in the affinity set for chips that
469*4882a593Smuzhiyun * have the EN*_W1{S,C} registers.
470*4882a593Smuzhiyun */
octeon_irq_ciu_enable_v2(struct irq_data * data)471*4882a593Smuzhiyun static void octeon_irq_ciu_enable_v2(struct irq_data *data)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun u64 mask;
474*4882a593Smuzhiyun int cpu = next_cpu_for_irq(data);
475*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
478*4882a593Smuzhiyun mask = 1ull << (cd->bit);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /*
481*4882a593Smuzhiyun * Called under the desc lock, so these should never get out
482*4882a593Smuzhiyun * of sync.
483*4882a593Smuzhiyun */
484*4882a593Smuzhiyun if (cd->line == 0) {
485*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2;
486*4882a593Smuzhiyun set_bit(cd->bit, &per_cpu(octeon_irq_ciu0_en_mirror, cpu));
487*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
488*4882a593Smuzhiyun } else {
489*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2 + 1;
490*4882a593Smuzhiyun set_bit(cd->bit, &per_cpu(octeon_irq_ciu1_en_mirror, cpu));
491*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun /*
496*4882a593Smuzhiyun * Enable the irq in the sum2 registers.
497*4882a593Smuzhiyun */
octeon_irq_ciu_enable_sum2(struct irq_data * data)498*4882a593Smuzhiyun static void octeon_irq_ciu_enable_sum2(struct irq_data *data)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun u64 mask;
501*4882a593Smuzhiyun int cpu = next_cpu_for_irq(data);
502*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu);
503*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
506*4882a593Smuzhiyun mask = 1ull << (cd->bit);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_EN2_PPX_IP4_W1S(index), mask);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun /*
512*4882a593Smuzhiyun * Disable the irq in the sum2 registers.
513*4882a593Smuzhiyun */
octeon_irq_ciu_disable_local_sum2(struct irq_data * data)514*4882a593Smuzhiyun static void octeon_irq_ciu_disable_local_sum2(struct irq_data *data)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun u64 mask;
517*4882a593Smuzhiyun int cpu = next_cpu_for_irq(data);
518*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu);
519*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
522*4882a593Smuzhiyun mask = 1ull << (cd->bit);
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_EN2_PPX_IP4_W1C(index), mask);
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun
octeon_irq_ciu_ack_sum2(struct irq_data * data)527*4882a593Smuzhiyun static void octeon_irq_ciu_ack_sum2(struct irq_data *data)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun u64 mask;
530*4882a593Smuzhiyun int cpu = next_cpu_for_irq(data);
531*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu);
532*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
535*4882a593Smuzhiyun mask = 1ull << (cd->bit);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_SUM2_PPX_IP4(index), mask);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
octeon_irq_ciu_disable_all_sum2(struct irq_data * data)540*4882a593Smuzhiyun static void octeon_irq_ciu_disable_all_sum2(struct irq_data *data)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun int cpu;
543*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
544*4882a593Smuzhiyun u64 mask;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
547*4882a593Smuzhiyun mask = 1ull << (cd->bit);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun for_each_online_cpu(cpu) {
550*4882a593Smuzhiyun int coreid = octeon_coreid_for_cpu(cpu);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_EN2_PPX_IP4_W1C(coreid), mask);
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /*
557*4882a593Smuzhiyun * Enable the irq on the current CPU for chips that
558*4882a593Smuzhiyun * have the EN*_W1{S,C} registers.
559*4882a593Smuzhiyun */
octeon_irq_ciu_enable_local_v2(struct irq_data * data)560*4882a593Smuzhiyun static void octeon_irq_ciu_enable_local_v2(struct irq_data *data)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun u64 mask;
563*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
566*4882a593Smuzhiyun mask = 1ull << (cd->bit);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (cd->line == 0) {
569*4882a593Smuzhiyun int index = cvmx_get_core_num() * 2;
570*4882a593Smuzhiyun set_bit(cd->bit, this_cpu_ptr(&octeon_irq_ciu0_en_mirror));
571*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
572*4882a593Smuzhiyun } else {
573*4882a593Smuzhiyun int index = cvmx_get_core_num() * 2 + 1;
574*4882a593Smuzhiyun set_bit(cd->bit, this_cpu_ptr(&octeon_irq_ciu1_en_mirror));
575*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
octeon_irq_ciu_disable_local_v2(struct irq_data * data)579*4882a593Smuzhiyun static void octeon_irq_ciu_disable_local_v2(struct irq_data *data)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun u64 mask;
582*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
585*4882a593Smuzhiyun mask = 1ull << (cd->bit);
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun if (cd->line == 0) {
588*4882a593Smuzhiyun int index = cvmx_get_core_num() * 2;
589*4882a593Smuzhiyun clear_bit(cd->bit, this_cpu_ptr(&octeon_irq_ciu0_en_mirror));
590*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
591*4882a593Smuzhiyun } else {
592*4882a593Smuzhiyun int index = cvmx_get_core_num() * 2 + 1;
593*4882a593Smuzhiyun clear_bit(cd->bit, this_cpu_ptr(&octeon_irq_ciu1_en_mirror));
594*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun /*
599*4882a593Smuzhiyun * Write to the W1C bit in CVMX_CIU_INTX_SUM0 to clear the irq.
600*4882a593Smuzhiyun */
octeon_irq_ciu_ack(struct irq_data * data)601*4882a593Smuzhiyun static void octeon_irq_ciu_ack(struct irq_data *data)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun u64 mask;
604*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
607*4882a593Smuzhiyun mask = 1ull << (cd->bit);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun if (cd->line == 0) {
610*4882a593Smuzhiyun int index = cvmx_get_core_num() * 2;
611*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_SUM0(index), mask);
612*4882a593Smuzhiyun } else {
613*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INT_SUM1, mask);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
619*4882a593Smuzhiyun * registers.
620*4882a593Smuzhiyun */
octeon_irq_ciu_disable_all_v2(struct irq_data * data)621*4882a593Smuzhiyun static void octeon_irq_ciu_disable_all_v2(struct irq_data *data)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun int cpu;
624*4882a593Smuzhiyun u64 mask;
625*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
628*4882a593Smuzhiyun mask = 1ull << (cd->bit);
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun if (cd->line == 0) {
631*4882a593Smuzhiyun for_each_online_cpu(cpu) {
632*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2;
633*4882a593Smuzhiyun clear_bit(cd->bit,
634*4882a593Smuzhiyun &per_cpu(octeon_irq_ciu0_en_mirror, cpu));
635*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun } else {
638*4882a593Smuzhiyun for_each_online_cpu(cpu) {
639*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2 + 1;
640*4882a593Smuzhiyun clear_bit(cd->bit,
641*4882a593Smuzhiyun &per_cpu(octeon_irq_ciu1_en_mirror, cpu));
642*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun /*
648*4882a593Smuzhiyun * Enable the irq on the all cores for chips that have the EN*_W1{S,C}
649*4882a593Smuzhiyun * registers.
650*4882a593Smuzhiyun */
octeon_irq_ciu_enable_all_v2(struct irq_data * data)651*4882a593Smuzhiyun static void octeon_irq_ciu_enable_all_v2(struct irq_data *data)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun int cpu;
654*4882a593Smuzhiyun u64 mask;
655*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
658*4882a593Smuzhiyun mask = 1ull << (cd->bit);
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun if (cd->line == 0) {
661*4882a593Smuzhiyun for_each_online_cpu(cpu) {
662*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2;
663*4882a593Smuzhiyun set_bit(cd->bit,
664*4882a593Smuzhiyun &per_cpu(octeon_irq_ciu0_en_mirror, cpu));
665*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun } else {
668*4882a593Smuzhiyun for_each_online_cpu(cpu) {
669*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2 + 1;
670*4882a593Smuzhiyun set_bit(cd->bit,
671*4882a593Smuzhiyun &per_cpu(octeon_irq_ciu1_en_mirror, cpu));
672*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
octeon_irq_ciu_set_type(struct irq_data * data,unsigned int t)677*4882a593Smuzhiyun static int octeon_irq_ciu_set_type(struct irq_data *data, unsigned int t)
678*4882a593Smuzhiyun {
679*4882a593Smuzhiyun irqd_set_trigger_type(data, t);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun if (t & IRQ_TYPE_EDGE_BOTH)
682*4882a593Smuzhiyun irq_set_handler_locked(data, handle_edge_irq);
683*4882a593Smuzhiyun else
684*4882a593Smuzhiyun irq_set_handler_locked(data, handle_level_irq);
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun return IRQ_SET_MASK_OK;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun
octeon_irq_gpio_setup(struct irq_data * data)689*4882a593Smuzhiyun static void octeon_irq_gpio_setup(struct irq_data *data)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun union cvmx_gpio_bit_cfgx cfg;
692*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
693*4882a593Smuzhiyun u32 t = irqd_get_trigger_type(data);
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun cfg.u64 = 0;
698*4882a593Smuzhiyun cfg.s.int_en = 1;
699*4882a593Smuzhiyun cfg.s.int_type = (t & IRQ_TYPE_EDGE_BOTH) != 0;
700*4882a593Smuzhiyun cfg.s.rx_xor = (t & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) != 0;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun /* 140 nS glitch filter*/
703*4882a593Smuzhiyun cfg.s.fil_cnt = 7;
704*4882a593Smuzhiyun cfg.s.fil_sel = 3;
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd->gpio_line), cfg.u64);
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
octeon_irq_ciu_enable_gpio_v2(struct irq_data * data)709*4882a593Smuzhiyun static void octeon_irq_ciu_enable_gpio_v2(struct irq_data *data)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun octeon_irq_gpio_setup(data);
712*4882a593Smuzhiyun octeon_irq_ciu_enable_v2(data);
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
octeon_irq_ciu_enable_gpio(struct irq_data * data)715*4882a593Smuzhiyun static void octeon_irq_ciu_enable_gpio(struct irq_data *data)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun octeon_irq_gpio_setup(data);
718*4882a593Smuzhiyun octeon_irq_ciu_enable(data);
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
octeon_irq_ciu_gpio_set_type(struct irq_data * data,unsigned int t)721*4882a593Smuzhiyun static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun irqd_set_trigger_type(data, t);
724*4882a593Smuzhiyun octeon_irq_gpio_setup(data);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun if (t & IRQ_TYPE_EDGE_BOTH)
727*4882a593Smuzhiyun irq_set_handler_locked(data, handle_edge_irq);
728*4882a593Smuzhiyun else
729*4882a593Smuzhiyun irq_set_handler_locked(data, handle_level_irq);
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun return IRQ_SET_MASK_OK;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun
octeon_irq_ciu_disable_gpio_v2(struct irq_data * data)734*4882a593Smuzhiyun static void octeon_irq_ciu_disable_gpio_v2(struct irq_data *data)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
739*4882a593Smuzhiyun cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd->gpio_line), 0);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun octeon_irq_ciu_disable_all_v2(data);
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
octeon_irq_ciu_disable_gpio(struct irq_data * data)744*4882a593Smuzhiyun static void octeon_irq_ciu_disable_gpio(struct irq_data *data)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
749*4882a593Smuzhiyun cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd->gpio_line), 0);
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun octeon_irq_ciu_disable_all(data);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
octeon_irq_ciu_gpio_ack(struct irq_data * data)754*4882a593Smuzhiyun static void octeon_irq_ciu_gpio_ack(struct irq_data *data)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
757*4882a593Smuzhiyun u64 mask;
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
760*4882a593Smuzhiyun mask = 1ull << (cd->gpio_line);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun cvmx_write_csr(CVMX_GPIO_INT_CLR, mask);
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun #ifdef CONFIG_SMP
766*4882a593Smuzhiyun
octeon_irq_cpu_offline_ciu(struct irq_data * data)767*4882a593Smuzhiyun static void octeon_irq_cpu_offline_ciu(struct irq_data *data)
768*4882a593Smuzhiyun {
769*4882a593Smuzhiyun int cpu = smp_processor_id();
770*4882a593Smuzhiyun cpumask_t new_affinity;
771*4882a593Smuzhiyun struct cpumask *mask = irq_data_get_affinity_mask(data);
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun if (!cpumask_test_cpu(cpu, mask))
774*4882a593Smuzhiyun return;
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun if (cpumask_weight(mask) > 1) {
777*4882a593Smuzhiyun /*
778*4882a593Smuzhiyun * It has multi CPU affinity, just remove this CPU
779*4882a593Smuzhiyun * from the affinity set.
780*4882a593Smuzhiyun */
781*4882a593Smuzhiyun cpumask_copy(&new_affinity, mask);
782*4882a593Smuzhiyun cpumask_clear_cpu(cpu, &new_affinity);
783*4882a593Smuzhiyun } else {
784*4882a593Smuzhiyun /* Otherwise, put it on lowest numbered online CPU. */
785*4882a593Smuzhiyun cpumask_clear(&new_affinity);
786*4882a593Smuzhiyun cpumask_set_cpu(cpumask_first(cpu_online_mask), &new_affinity);
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun irq_set_affinity_locked(data, &new_affinity, false);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
octeon_irq_ciu_set_affinity(struct irq_data * data,const struct cpumask * dest,bool force)791*4882a593Smuzhiyun static int octeon_irq_ciu_set_affinity(struct irq_data *data,
792*4882a593Smuzhiyun const struct cpumask *dest, bool force)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun int cpu;
795*4882a593Smuzhiyun bool enable_one = !irqd_irq_disabled(data) && !irqd_irq_masked(data);
796*4882a593Smuzhiyun unsigned long flags;
797*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
798*4882a593Smuzhiyun unsigned long *pen;
799*4882a593Smuzhiyun raw_spinlock_t *lock;
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun /*
804*4882a593Smuzhiyun * For non-v2 CIU, we will allow only single CPU affinity.
805*4882a593Smuzhiyun * This removes the need to do locking in the .ack/.eoi
806*4882a593Smuzhiyun * functions.
807*4882a593Smuzhiyun */
808*4882a593Smuzhiyun if (cpumask_weight(dest) != 1)
809*4882a593Smuzhiyun return -EINVAL;
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun if (!enable_one)
812*4882a593Smuzhiyun return 0;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun for_each_online_cpu(cpu) {
816*4882a593Smuzhiyun int coreid = octeon_coreid_for_cpu(cpu);
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun lock = &per_cpu(octeon_irq_ciu_spinlock, cpu);
819*4882a593Smuzhiyun raw_spin_lock_irqsave(lock, flags);
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun if (cd->line == 0)
822*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu0_en_mirror, cpu);
823*4882a593Smuzhiyun else
824*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu1_en_mirror, cpu);
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun if (cpumask_test_cpu(cpu, dest) && enable_one) {
827*4882a593Smuzhiyun enable_one = false;
828*4882a593Smuzhiyun __set_bit(cd->bit, pen);
829*4882a593Smuzhiyun } else {
830*4882a593Smuzhiyun __clear_bit(cd->bit, pen);
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun /*
833*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before
834*4882a593Smuzhiyun * enabling the irq.
835*4882a593Smuzhiyun */
836*4882a593Smuzhiyun wmb();
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun if (cd->line == 0)
839*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), *pen);
840*4882a593Smuzhiyun else
841*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), *pen);
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun raw_spin_unlock_irqrestore(lock, flags);
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun return 0;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun /*
849*4882a593Smuzhiyun * Set affinity for the irq for chips that have the EN*_W1{S,C}
850*4882a593Smuzhiyun * registers.
851*4882a593Smuzhiyun */
octeon_irq_ciu_set_affinity_v2(struct irq_data * data,const struct cpumask * dest,bool force)852*4882a593Smuzhiyun static int octeon_irq_ciu_set_affinity_v2(struct irq_data *data,
853*4882a593Smuzhiyun const struct cpumask *dest,
854*4882a593Smuzhiyun bool force)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun int cpu;
857*4882a593Smuzhiyun bool enable_one = !irqd_irq_disabled(data) && !irqd_irq_masked(data);
858*4882a593Smuzhiyun u64 mask;
859*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun if (!enable_one)
862*4882a593Smuzhiyun return 0;
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
865*4882a593Smuzhiyun mask = 1ull << cd->bit;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun if (cd->line == 0) {
868*4882a593Smuzhiyun for_each_online_cpu(cpu) {
869*4882a593Smuzhiyun unsigned long *pen = &per_cpu(octeon_irq_ciu0_en_mirror, cpu);
870*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2;
871*4882a593Smuzhiyun if (cpumask_test_cpu(cpu, dest) && enable_one) {
872*4882a593Smuzhiyun enable_one = false;
873*4882a593Smuzhiyun set_bit(cd->bit, pen);
874*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
875*4882a593Smuzhiyun } else {
876*4882a593Smuzhiyun clear_bit(cd->bit, pen);
877*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun } else {
881*4882a593Smuzhiyun for_each_online_cpu(cpu) {
882*4882a593Smuzhiyun unsigned long *pen = &per_cpu(octeon_irq_ciu1_en_mirror, cpu);
883*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu) * 2 + 1;
884*4882a593Smuzhiyun if (cpumask_test_cpu(cpu, dest) && enable_one) {
885*4882a593Smuzhiyun enable_one = false;
886*4882a593Smuzhiyun set_bit(cd->bit, pen);
887*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
888*4882a593Smuzhiyun } else {
889*4882a593Smuzhiyun clear_bit(cd->bit, pen);
890*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun return 0;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun
octeon_irq_ciu_set_affinity_sum2(struct irq_data * data,const struct cpumask * dest,bool force)897*4882a593Smuzhiyun static int octeon_irq_ciu_set_affinity_sum2(struct irq_data *data,
898*4882a593Smuzhiyun const struct cpumask *dest,
899*4882a593Smuzhiyun bool force)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun int cpu;
902*4882a593Smuzhiyun bool enable_one = !irqd_irq_disabled(data) && !irqd_irq_masked(data);
903*4882a593Smuzhiyun u64 mask;
904*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun if (!enable_one)
907*4882a593Smuzhiyun return 0;
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
910*4882a593Smuzhiyun mask = 1ull << cd->bit;
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun for_each_online_cpu(cpu) {
913*4882a593Smuzhiyun int index = octeon_coreid_for_cpu(cpu);
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun if (cpumask_test_cpu(cpu, dest) && enable_one) {
916*4882a593Smuzhiyun enable_one = false;
917*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_EN2_PPX_IP4_W1S(index), mask);
918*4882a593Smuzhiyun } else {
919*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_EN2_PPX_IP4_W1C(index), mask);
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun return 0;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun #endif
925*4882a593Smuzhiyun
edge_startup(struct irq_data * data)926*4882a593Smuzhiyun static unsigned int edge_startup(struct irq_data *data)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun /* ack any pending edge-irq at startup, so there is
929*4882a593Smuzhiyun * an _edge_ to fire on when the event reappears.
930*4882a593Smuzhiyun */
931*4882a593Smuzhiyun data->chip->irq_ack(data);
932*4882a593Smuzhiyun data->chip->irq_enable(data);
933*4882a593Smuzhiyun return 0;
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun /*
937*4882a593Smuzhiyun * Newer octeon chips have support for lockless CIU operation.
938*4882a593Smuzhiyun */
939*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_v2 = {
940*4882a593Smuzhiyun .name = "CIU",
941*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_v2,
942*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all_v2,
943*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local_v2,
944*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable_v2,
945*4882a593Smuzhiyun #ifdef CONFIG_SMP
946*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
947*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
948*4882a593Smuzhiyun #endif
949*4882a593Smuzhiyun };
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_v2_edge = {
952*4882a593Smuzhiyun .name = "CIU",
953*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_v2,
954*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all_v2,
955*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_ack,
956*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local_v2,
957*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable_v2,
958*4882a593Smuzhiyun #ifdef CONFIG_SMP
959*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
960*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
961*4882a593Smuzhiyun #endif
962*4882a593Smuzhiyun };
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun /*
965*4882a593Smuzhiyun * Newer octeon chips have support for lockless CIU operation.
966*4882a593Smuzhiyun */
967*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_sum2 = {
968*4882a593Smuzhiyun .name = "CIU",
969*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_sum2,
970*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all_sum2,
971*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local_sum2,
972*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable_sum2,
973*4882a593Smuzhiyun #ifdef CONFIG_SMP
974*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity_sum2,
975*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
976*4882a593Smuzhiyun #endif
977*4882a593Smuzhiyun };
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_sum2_edge = {
980*4882a593Smuzhiyun .name = "CIU",
981*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_sum2,
982*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all_sum2,
983*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_ack_sum2,
984*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local_sum2,
985*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable_sum2,
986*4882a593Smuzhiyun #ifdef CONFIG_SMP
987*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity_sum2,
988*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
989*4882a593Smuzhiyun #endif
990*4882a593Smuzhiyun };
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu = {
993*4882a593Smuzhiyun .name = "CIU",
994*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable,
995*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all,
996*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local,
997*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable,
998*4882a593Smuzhiyun #ifdef CONFIG_SMP
999*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity,
1000*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
1001*4882a593Smuzhiyun #endif
1002*4882a593Smuzhiyun };
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_edge = {
1005*4882a593Smuzhiyun .name = "CIU",
1006*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable,
1007*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all,
1008*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_ack,
1009*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local,
1010*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable,
1011*4882a593Smuzhiyun #ifdef CONFIG_SMP
1012*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity,
1013*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
1014*4882a593Smuzhiyun #endif
1015*4882a593Smuzhiyun };
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun /* The mbox versions don't do any affinity or round-robin. */
1018*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_mbox_v2 = {
1019*4882a593Smuzhiyun .name = "CIU-M",
1020*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_all_v2,
1021*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all_v2,
1022*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_disable_local_v2,
1023*4882a593Smuzhiyun .irq_eoi = octeon_irq_ciu_enable_local_v2,
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun .irq_cpu_online = octeon_irq_ciu_enable_local_v2,
1026*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_ciu_disable_local_v2,
1027*4882a593Smuzhiyun .flags = IRQCHIP_ONOFFLINE_ENABLED,
1028*4882a593Smuzhiyun };
1029*4882a593Smuzhiyun
1030*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_mbox = {
1031*4882a593Smuzhiyun .name = "CIU-M",
1032*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_all,
1033*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all,
1034*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_disable_local,
1035*4882a593Smuzhiyun .irq_eoi = octeon_irq_ciu_enable_local,
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun .irq_cpu_online = octeon_irq_ciu_enable_local,
1038*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_ciu_disable_local,
1039*4882a593Smuzhiyun .flags = IRQCHIP_ONOFFLINE_ENABLED,
1040*4882a593Smuzhiyun };
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_gpio_v2 = {
1043*4882a593Smuzhiyun .name = "CIU-GPIO",
1044*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_gpio_v2,
1045*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_gpio_v2,
1046*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_gpio_ack,
1047*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local_v2,
1048*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable_v2,
1049*4882a593Smuzhiyun .irq_set_type = octeon_irq_ciu_gpio_set_type,
1050*4882a593Smuzhiyun #ifdef CONFIG_SMP
1051*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
1052*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
1053*4882a593Smuzhiyun #endif
1054*4882a593Smuzhiyun .flags = IRQCHIP_SET_TYPE_MASKED,
1055*4882a593Smuzhiyun };
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_gpio = {
1058*4882a593Smuzhiyun .name = "CIU-GPIO",
1059*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_enable_gpio,
1060*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_gpio,
1061*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local,
1062*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable,
1063*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_gpio_ack,
1064*4882a593Smuzhiyun .irq_set_type = octeon_irq_ciu_gpio_set_type,
1065*4882a593Smuzhiyun #ifdef CONFIG_SMP
1066*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu_set_affinity,
1067*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
1068*4882a593Smuzhiyun #endif
1069*4882a593Smuzhiyun .flags = IRQCHIP_SET_TYPE_MASKED,
1070*4882a593Smuzhiyun };
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun /*
1073*4882a593Smuzhiyun * Watchdog interrupts are special. They are associated with a single
1074*4882a593Smuzhiyun * core, so we hardwire the affinity to that core.
1075*4882a593Smuzhiyun */
octeon_irq_ciu_wd_enable(struct irq_data * data)1076*4882a593Smuzhiyun static void octeon_irq_ciu_wd_enable(struct irq_data *data)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun unsigned long flags;
1079*4882a593Smuzhiyun unsigned long *pen;
1080*4882a593Smuzhiyun int coreid = data->irq - OCTEON_IRQ_WDOG0; /* Bit 0-63 of EN1 */
1081*4882a593Smuzhiyun int cpu = octeon_cpu_for_coreid(coreid);
1082*4882a593Smuzhiyun raw_spinlock_t *lock = &per_cpu(octeon_irq_ciu_spinlock, cpu);
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun raw_spin_lock_irqsave(lock, flags);
1085*4882a593Smuzhiyun pen = &per_cpu(octeon_irq_ciu1_en_mirror, cpu);
1086*4882a593Smuzhiyun __set_bit(coreid, pen);
1087*4882a593Smuzhiyun /*
1088*4882a593Smuzhiyun * Must be visible to octeon_irq_ip{2,3}_ciu() before enabling
1089*4882a593Smuzhiyun * the irq.
1090*4882a593Smuzhiyun */
1091*4882a593Smuzhiyun wmb();
1092*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), *pen);
1093*4882a593Smuzhiyun raw_spin_unlock_irqrestore(lock, flags);
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun /*
1097*4882a593Smuzhiyun * Watchdog interrupts are special. They are associated with a single
1098*4882a593Smuzhiyun * core, so we hardwire the affinity to that core.
1099*4882a593Smuzhiyun */
octeon_irq_ciu1_wd_enable_v2(struct irq_data * data)1100*4882a593Smuzhiyun static void octeon_irq_ciu1_wd_enable_v2(struct irq_data *data)
1101*4882a593Smuzhiyun {
1102*4882a593Smuzhiyun int coreid = data->irq - OCTEON_IRQ_WDOG0;
1103*4882a593Smuzhiyun int cpu = octeon_cpu_for_coreid(coreid);
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun set_bit(coreid, &per_cpu(octeon_irq_ciu1_en_mirror, cpu));
1106*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(coreid * 2 + 1), 1ull << coreid);
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_wd_v2 = {
1111*4882a593Smuzhiyun .name = "CIU-W",
1112*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu1_wd_enable_v2,
1113*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all_v2,
1114*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local_v2,
1115*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable_local_v2,
1116*4882a593Smuzhiyun };
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu_wd = {
1119*4882a593Smuzhiyun .name = "CIU-W",
1120*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu_wd_enable,
1121*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu_disable_all,
1122*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu_disable_local,
1123*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu_enable_local,
1124*4882a593Smuzhiyun };
1125*4882a593Smuzhiyun
octeon_irq_ciu_is_edge(unsigned int line,unsigned int bit)1126*4882a593Smuzhiyun static bool octeon_irq_ciu_is_edge(unsigned int line, unsigned int bit)
1127*4882a593Smuzhiyun {
1128*4882a593Smuzhiyun bool edge = false;
1129*4882a593Smuzhiyun
1130*4882a593Smuzhiyun if (line == 0)
1131*4882a593Smuzhiyun switch (bit) {
1132*4882a593Smuzhiyun case 48 ... 49: /* GMX DRP */
1133*4882a593Smuzhiyun case 50: /* IPD_DRP */
1134*4882a593Smuzhiyun case 52 ... 55: /* Timers */
1135*4882a593Smuzhiyun case 58: /* MPI */
1136*4882a593Smuzhiyun edge = true;
1137*4882a593Smuzhiyun break;
1138*4882a593Smuzhiyun default:
1139*4882a593Smuzhiyun break;
1140*4882a593Smuzhiyun }
1141*4882a593Smuzhiyun else /* line == 1 */
1142*4882a593Smuzhiyun switch (bit) {
1143*4882a593Smuzhiyun case 47: /* PTP */
1144*4882a593Smuzhiyun edge = true;
1145*4882a593Smuzhiyun break;
1146*4882a593Smuzhiyun default:
1147*4882a593Smuzhiyun break;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun return edge;
1150*4882a593Smuzhiyun }
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun struct octeon_irq_gpio_domain_data {
1153*4882a593Smuzhiyun unsigned int base_hwirq;
1154*4882a593Smuzhiyun };
1155*4882a593Smuzhiyun
octeon_irq_gpio_xlat(struct irq_domain * d,struct device_node * node,const u32 * intspec,unsigned int intsize,unsigned long * out_hwirq,unsigned int * out_type)1156*4882a593Smuzhiyun static int octeon_irq_gpio_xlat(struct irq_domain *d,
1157*4882a593Smuzhiyun struct device_node *node,
1158*4882a593Smuzhiyun const u32 *intspec,
1159*4882a593Smuzhiyun unsigned int intsize,
1160*4882a593Smuzhiyun unsigned long *out_hwirq,
1161*4882a593Smuzhiyun unsigned int *out_type)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun unsigned int type;
1164*4882a593Smuzhiyun unsigned int pin;
1165*4882a593Smuzhiyun unsigned int trigger;
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun if (irq_domain_get_of_node(d) != node)
1168*4882a593Smuzhiyun return -EINVAL;
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun if (intsize < 2)
1171*4882a593Smuzhiyun return -EINVAL;
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun pin = intspec[0];
1174*4882a593Smuzhiyun if (pin >= 16)
1175*4882a593Smuzhiyun return -EINVAL;
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun trigger = intspec[1];
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun switch (trigger) {
1180*4882a593Smuzhiyun case 1:
1181*4882a593Smuzhiyun type = IRQ_TYPE_EDGE_RISING;
1182*4882a593Smuzhiyun break;
1183*4882a593Smuzhiyun case 2:
1184*4882a593Smuzhiyun type = IRQ_TYPE_EDGE_FALLING;
1185*4882a593Smuzhiyun break;
1186*4882a593Smuzhiyun case 4:
1187*4882a593Smuzhiyun type = IRQ_TYPE_LEVEL_HIGH;
1188*4882a593Smuzhiyun break;
1189*4882a593Smuzhiyun case 8:
1190*4882a593Smuzhiyun type = IRQ_TYPE_LEVEL_LOW;
1191*4882a593Smuzhiyun break;
1192*4882a593Smuzhiyun default:
1193*4882a593Smuzhiyun pr_err("Error: (%pOFn) Invalid irq trigger specification: %x\n",
1194*4882a593Smuzhiyun node,
1195*4882a593Smuzhiyun trigger);
1196*4882a593Smuzhiyun type = IRQ_TYPE_LEVEL_LOW;
1197*4882a593Smuzhiyun break;
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun *out_type = type;
1200*4882a593Smuzhiyun *out_hwirq = pin;
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun return 0;
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun
octeon_irq_ciu_xlat(struct irq_domain * d,struct device_node * node,const u32 * intspec,unsigned int intsize,unsigned long * out_hwirq,unsigned int * out_type)1205*4882a593Smuzhiyun static int octeon_irq_ciu_xlat(struct irq_domain *d,
1206*4882a593Smuzhiyun struct device_node *node,
1207*4882a593Smuzhiyun const u32 *intspec,
1208*4882a593Smuzhiyun unsigned int intsize,
1209*4882a593Smuzhiyun unsigned long *out_hwirq,
1210*4882a593Smuzhiyun unsigned int *out_type)
1211*4882a593Smuzhiyun {
1212*4882a593Smuzhiyun unsigned int ciu, bit;
1213*4882a593Smuzhiyun struct octeon_irq_ciu_domain_data *dd = d->host_data;
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun ciu = intspec[0];
1216*4882a593Smuzhiyun bit = intspec[1];
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun if (ciu >= dd->num_sum || bit > 63)
1219*4882a593Smuzhiyun return -EINVAL;
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun *out_hwirq = (ciu << 6) | bit;
1222*4882a593Smuzhiyun *out_type = 0;
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun return 0;
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun static struct irq_chip *octeon_irq_ciu_chip;
1228*4882a593Smuzhiyun static struct irq_chip *octeon_irq_ciu_chip_edge;
1229*4882a593Smuzhiyun static struct irq_chip *octeon_irq_gpio_chip;
1230*4882a593Smuzhiyun
octeon_irq_ciu_map(struct irq_domain * d,unsigned int virq,irq_hw_number_t hw)1231*4882a593Smuzhiyun static int octeon_irq_ciu_map(struct irq_domain *d,
1232*4882a593Smuzhiyun unsigned int virq, irq_hw_number_t hw)
1233*4882a593Smuzhiyun {
1234*4882a593Smuzhiyun int rv;
1235*4882a593Smuzhiyun unsigned int line = hw >> 6;
1236*4882a593Smuzhiyun unsigned int bit = hw & 63;
1237*4882a593Smuzhiyun struct octeon_irq_ciu_domain_data *dd = d->host_data;
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun if (line >= dd->num_sum || octeon_irq_ciu_to_irq[line][bit] != 0)
1240*4882a593Smuzhiyun return -EINVAL;
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun if (line == 2) {
1243*4882a593Smuzhiyun if (octeon_irq_ciu_is_edge(line, bit))
1244*4882a593Smuzhiyun rv = octeon_irq_set_ciu_mapping(virq, line, bit, 0,
1245*4882a593Smuzhiyun &octeon_irq_chip_ciu_sum2_edge,
1246*4882a593Smuzhiyun handle_edge_irq);
1247*4882a593Smuzhiyun else
1248*4882a593Smuzhiyun rv = octeon_irq_set_ciu_mapping(virq, line, bit, 0,
1249*4882a593Smuzhiyun &octeon_irq_chip_ciu_sum2,
1250*4882a593Smuzhiyun handle_level_irq);
1251*4882a593Smuzhiyun } else {
1252*4882a593Smuzhiyun if (octeon_irq_ciu_is_edge(line, bit))
1253*4882a593Smuzhiyun rv = octeon_irq_set_ciu_mapping(virq, line, bit, 0,
1254*4882a593Smuzhiyun octeon_irq_ciu_chip_edge,
1255*4882a593Smuzhiyun handle_edge_irq);
1256*4882a593Smuzhiyun else
1257*4882a593Smuzhiyun rv = octeon_irq_set_ciu_mapping(virq, line, bit, 0,
1258*4882a593Smuzhiyun octeon_irq_ciu_chip,
1259*4882a593Smuzhiyun handle_level_irq);
1260*4882a593Smuzhiyun }
1261*4882a593Smuzhiyun return rv;
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun
octeon_irq_gpio_map(struct irq_domain * d,unsigned int virq,irq_hw_number_t hw)1264*4882a593Smuzhiyun static int octeon_irq_gpio_map(struct irq_domain *d,
1265*4882a593Smuzhiyun unsigned int virq, irq_hw_number_t hw)
1266*4882a593Smuzhiyun {
1267*4882a593Smuzhiyun struct octeon_irq_gpio_domain_data *gpiod = d->host_data;
1268*4882a593Smuzhiyun unsigned int line, bit;
1269*4882a593Smuzhiyun int r;
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun line = (hw + gpiod->base_hwirq) >> 6;
1272*4882a593Smuzhiyun bit = (hw + gpiod->base_hwirq) & 63;
1273*4882a593Smuzhiyun if (line >= ARRAY_SIZE(octeon_irq_ciu_to_irq) ||
1274*4882a593Smuzhiyun octeon_irq_ciu_to_irq[line][bit] != 0)
1275*4882a593Smuzhiyun return -EINVAL;
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun /*
1278*4882a593Smuzhiyun * Default to handle_level_irq. If the DT contains a different
1279*4882a593Smuzhiyun * trigger type, it will call the irq_set_type callback and
1280*4882a593Smuzhiyun * the handler gets updated.
1281*4882a593Smuzhiyun */
1282*4882a593Smuzhiyun r = octeon_irq_set_ciu_mapping(virq, line, bit, hw,
1283*4882a593Smuzhiyun octeon_irq_gpio_chip, handle_level_irq);
1284*4882a593Smuzhiyun return r;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun static struct irq_domain_ops octeon_irq_domain_ciu_ops = {
1288*4882a593Smuzhiyun .map = octeon_irq_ciu_map,
1289*4882a593Smuzhiyun .unmap = octeon_irq_free_cd,
1290*4882a593Smuzhiyun .xlate = octeon_irq_ciu_xlat,
1291*4882a593Smuzhiyun };
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun static struct irq_domain_ops octeon_irq_domain_gpio_ops = {
1294*4882a593Smuzhiyun .map = octeon_irq_gpio_map,
1295*4882a593Smuzhiyun .unmap = octeon_irq_free_cd,
1296*4882a593Smuzhiyun .xlate = octeon_irq_gpio_xlat,
1297*4882a593Smuzhiyun };
1298*4882a593Smuzhiyun
octeon_irq_ip2_ciu(void)1299*4882a593Smuzhiyun static void octeon_irq_ip2_ciu(void)
1300*4882a593Smuzhiyun {
1301*4882a593Smuzhiyun const unsigned long core_id = cvmx_get_core_num();
1302*4882a593Smuzhiyun u64 ciu_sum = cvmx_read_csr(CVMX_CIU_INTX_SUM0(core_id * 2));
1303*4882a593Smuzhiyun
1304*4882a593Smuzhiyun ciu_sum &= __this_cpu_read(octeon_irq_ciu0_en_mirror);
1305*4882a593Smuzhiyun if (likely(ciu_sum)) {
1306*4882a593Smuzhiyun int bit = fls64(ciu_sum) - 1;
1307*4882a593Smuzhiyun int irq = octeon_irq_ciu_to_irq[0][bit];
1308*4882a593Smuzhiyun if (likely(irq))
1309*4882a593Smuzhiyun do_IRQ(irq);
1310*4882a593Smuzhiyun else
1311*4882a593Smuzhiyun spurious_interrupt();
1312*4882a593Smuzhiyun } else {
1313*4882a593Smuzhiyun spurious_interrupt();
1314*4882a593Smuzhiyun }
1315*4882a593Smuzhiyun }
1316*4882a593Smuzhiyun
octeon_irq_ip3_ciu(void)1317*4882a593Smuzhiyun static void octeon_irq_ip3_ciu(void)
1318*4882a593Smuzhiyun {
1319*4882a593Smuzhiyun u64 ciu_sum = cvmx_read_csr(CVMX_CIU_INT_SUM1);
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun ciu_sum &= __this_cpu_read(octeon_irq_ciu1_en_mirror);
1322*4882a593Smuzhiyun if (likely(ciu_sum)) {
1323*4882a593Smuzhiyun int bit = fls64(ciu_sum) - 1;
1324*4882a593Smuzhiyun int irq = octeon_irq_ciu_to_irq[1][bit];
1325*4882a593Smuzhiyun if (likely(irq))
1326*4882a593Smuzhiyun do_IRQ(irq);
1327*4882a593Smuzhiyun else
1328*4882a593Smuzhiyun spurious_interrupt();
1329*4882a593Smuzhiyun } else {
1330*4882a593Smuzhiyun spurious_interrupt();
1331*4882a593Smuzhiyun }
1332*4882a593Smuzhiyun }
1333*4882a593Smuzhiyun
octeon_irq_ip4_ciu(void)1334*4882a593Smuzhiyun static void octeon_irq_ip4_ciu(void)
1335*4882a593Smuzhiyun {
1336*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1337*4882a593Smuzhiyun u64 ciu_sum = cvmx_read_csr(CVMX_CIU_SUM2_PPX_IP4(coreid));
1338*4882a593Smuzhiyun u64 ciu_en = cvmx_read_csr(CVMX_CIU_EN2_PPX_IP4(coreid));
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun ciu_sum &= ciu_en;
1341*4882a593Smuzhiyun if (likely(ciu_sum)) {
1342*4882a593Smuzhiyun int bit = fls64(ciu_sum) - 1;
1343*4882a593Smuzhiyun int irq = octeon_irq_ciu_to_irq[2][bit];
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun if (likely(irq))
1346*4882a593Smuzhiyun do_IRQ(irq);
1347*4882a593Smuzhiyun else
1348*4882a593Smuzhiyun spurious_interrupt();
1349*4882a593Smuzhiyun } else {
1350*4882a593Smuzhiyun spurious_interrupt();
1351*4882a593Smuzhiyun }
1352*4882a593Smuzhiyun }
1353*4882a593Smuzhiyun
1354*4882a593Smuzhiyun static bool octeon_irq_use_ip4;
1355*4882a593Smuzhiyun
octeon_irq_local_enable_ip4(void * arg)1356*4882a593Smuzhiyun static void octeon_irq_local_enable_ip4(void *arg)
1357*4882a593Smuzhiyun {
1358*4882a593Smuzhiyun set_c0_status(STATUSF_IP4);
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun
octeon_irq_ip4_mask(void)1361*4882a593Smuzhiyun static void octeon_irq_ip4_mask(void)
1362*4882a593Smuzhiyun {
1363*4882a593Smuzhiyun clear_c0_status(STATUSF_IP4);
1364*4882a593Smuzhiyun spurious_interrupt();
1365*4882a593Smuzhiyun }
1366*4882a593Smuzhiyun
1367*4882a593Smuzhiyun static void (*octeon_irq_ip2)(void);
1368*4882a593Smuzhiyun static void (*octeon_irq_ip3)(void);
1369*4882a593Smuzhiyun static void (*octeon_irq_ip4)(void);
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun void (*octeon_irq_setup_secondary)(void);
1372*4882a593Smuzhiyun
octeon_irq_set_ip4_handler(octeon_irq_ip4_handler_t h)1373*4882a593Smuzhiyun void octeon_irq_set_ip4_handler(octeon_irq_ip4_handler_t h)
1374*4882a593Smuzhiyun {
1375*4882a593Smuzhiyun octeon_irq_ip4 = h;
1376*4882a593Smuzhiyun octeon_irq_use_ip4 = true;
1377*4882a593Smuzhiyun on_each_cpu(octeon_irq_local_enable_ip4, NULL, 1);
1378*4882a593Smuzhiyun }
1379*4882a593Smuzhiyun
octeon_irq_percpu_enable(void)1380*4882a593Smuzhiyun static void octeon_irq_percpu_enable(void)
1381*4882a593Smuzhiyun {
1382*4882a593Smuzhiyun irq_cpu_online();
1383*4882a593Smuzhiyun }
1384*4882a593Smuzhiyun
octeon_irq_init_ciu_percpu(void)1385*4882a593Smuzhiyun static void octeon_irq_init_ciu_percpu(void)
1386*4882a593Smuzhiyun {
1387*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun __this_cpu_write(octeon_irq_ciu0_en_mirror, 0);
1391*4882a593Smuzhiyun __this_cpu_write(octeon_irq_ciu1_en_mirror, 0);
1392*4882a593Smuzhiyun wmb();
1393*4882a593Smuzhiyun raw_spin_lock_init(this_cpu_ptr(&octeon_irq_ciu_spinlock));
1394*4882a593Smuzhiyun /*
1395*4882a593Smuzhiyun * Disable All CIU Interrupts. The ones we need will be
1396*4882a593Smuzhiyun * enabled later. Read the SUM register so we know the write
1397*4882a593Smuzhiyun * completed.
1398*4882a593Smuzhiyun */
1399*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2)), 0);
1400*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2 + 1)), 0);
1401*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2)), 0);
1402*4882a593Smuzhiyun cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2 + 1)), 0);
1403*4882a593Smuzhiyun cvmx_read_csr(CVMX_CIU_INTX_SUM0((coreid * 2)));
1404*4882a593Smuzhiyun }
1405*4882a593Smuzhiyun
octeon_irq_init_ciu2_percpu(void)1406*4882a593Smuzhiyun static void octeon_irq_init_ciu2_percpu(void)
1407*4882a593Smuzhiyun {
1408*4882a593Smuzhiyun u64 regx, ipx;
1409*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1410*4882a593Smuzhiyun u64 base = CVMX_CIU2_EN_PPX_IP2_WRKQ(coreid);
1411*4882a593Smuzhiyun
1412*4882a593Smuzhiyun /*
1413*4882a593Smuzhiyun * Disable All CIU2 Interrupts. The ones we need will be
1414*4882a593Smuzhiyun * enabled later. Read the SUM register so we know the write
1415*4882a593Smuzhiyun * completed.
1416*4882a593Smuzhiyun *
1417*4882a593Smuzhiyun * There are 9 registers and 3 IPX levels with strides 0x1000
1418*4882a593Smuzhiyun * and 0x200 respectivly. Use loops to clear them.
1419*4882a593Smuzhiyun */
1420*4882a593Smuzhiyun for (regx = 0; regx <= 0x8000; regx += 0x1000) {
1421*4882a593Smuzhiyun for (ipx = 0; ipx <= 0x400; ipx += 0x200)
1422*4882a593Smuzhiyun cvmx_write_csr(base + regx + ipx, 0);
1423*4882a593Smuzhiyun }
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(coreid));
1426*4882a593Smuzhiyun }
1427*4882a593Smuzhiyun
octeon_irq_setup_secondary_ciu(void)1428*4882a593Smuzhiyun static void octeon_irq_setup_secondary_ciu(void)
1429*4882a593Smuzhiyun {
1430*4882a593Smuzhiyun octeon_irq_init_ciu_percpu();
1431*4882a593Smuzhiyun octeon_irq_percpu_enable();
1432*4882a593Smuzhiyun
1433*4882a593Smuzhiyun /* Enable the CIU lines */
1434*4882a593Smuzhiyun set_c0_status(STATUSF_IP3 | STATUSF_IP2);
1435*4882a593Smuzhiyun if (octeon_irq_use_ip4)
1436*4882a593Smuzhiyun set_c0_status(STATUSF_IP4);
1437*4882a593Smuzhiyun else
1438*4882a593Smuzhiyun clear_c0_status(STATUSF_IP4);
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun
octeon_irq_setup_secondary_ciu2(void)1441*4882a593Smuzhiyun static void octeon_irq_setup_secondary_ciu2(void)
1442*4882a593Smuzhiyun {
1443*4882a593Smuzhiyun octeon_irq_init_ciu2_percpu();
1444*4882a593Smuzhiyun octeon_irq_percpu_enable();
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun /* Enable the CIU lines */
1447*4882a593Smuzhiyun set_c0_status(STATUSF_IP3 | STATUSF_IP2);
1448*4882a593Smuzhiyun if (octeon_irq_use_ip4)
1449*4882a593Smuzhiyun set_c0_status(STATUSF_IP4);
1450*4882a593Smuzhiyun else
1451*4882a593Smuzhiyun clear_c0_status(STATUSF_IP4);
1452*4882a593Smuzhiyun }
1453*4882a593Smuzhiyun
octeon_irq_init_ciu(struct device_node * ciu_node,struct device_node * parent)1454*4882a593Smuzhiyun static int __init octeon_irq_init_ciu(
1455*4882a593Smuzhiyun struct device_node *ciu_node, struct device_node *parent)
1456*4882a593Smuzhiyun {
1457*4882a593Smuzhiyun unsigned int i, r;
1458*4882a593Smuzhiyun struct irq_chip *chip;
1459*4882a593Smuzhiyun struct irq_chip *chip_edge;
1460*4882a593Smuzhiyun struct irq_chip *chip_mbox;
1461*4882a593Smuzhiyun struct irq_chip *chip_wd;
1462*4882a593Smuzhiyun struct irq_domain *ciu_domain = NULL;
1463*4882a593Smuzhiyun struct octeon_irq_ciu_domain_data *dd;
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun dd = kzalloc(sizeof(*dd), GFP_KERNEL);
1466*4882a593Smuzhiyun if (!dd)
1467*4882a593Smuzhiyun return -ENOMEM;
1468*4882a593Smuzhiyun
1469*4882a593Smuzhiyun octeon_irq_init_ciu_percpu();
1470*4882a593Smuzhiyun octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun octeon_irq_ip2 = octeon_irq_ip2_ciu;
1473*4882a593Smuzhiyun octeon_irq_ip3 = octeon_irq_ip3_ciu;
1474*4882a593Smuzhiyun if ((OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3())
1475*4882a593Smuzhiyun && !OCTEON_IS_MODEL(OCTEON_CN63XX)) {
1476*4882a593Smuzhiyun octeon_irq_ip4 = octeon_irq_ip4_ciu;
1477*4882a593Smuzhiyun dd->num_sum = 3;
1478*4882a593Smuzhiyun octeon_irq_use_ip4 = true;
1479*4882a593Smuzhiyun } else {
1480*4882a593Smuzhiyun octeon_irq_ip4 = octeon_irq_ip4_mask;
1481*4882a593Smuzhiyun dd->num_sum = 2;
1482*4882a593Smuzhiyun octeon_irq_use_ip4 = false;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun if (OCTEON_IS_MODEL(OCTEON_CN58XX_PASS2_X) ||
1485*4882a593Smuzhiyun OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) ||
1486*4882a593Smuzhiyun OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) ||
1487*4882a593Smuzhiyun OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3()) {
1488*4882a593Smuzhiyun chip = &octeon_irq_chip_ciu_v2;
1489*4882a593Smuzhiyun chip_edge = &octeon_irq_chip_ciu_v2_edge;
1490*4882a593Smuzhiyun chip_mbox = &octeon_irq_chip_ciu_mbox_v2;
1491*4882a593Smuzhiyun chip_wd = &octeon_irq_chip_ciu_wd_v2;
1492*4882a593Smuzhiyun octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio_v2;
1493*4882a593Smuzhiyun } else {
1494*4882a593Smuzhiyun chip = &octeon_irq_chip_ciu;
1495*4882a593Smuzhiyun chip_edge = &octeon_irq_chip_ciu_edge;
1496*4882a593Smuzhiyun chip_mbox = &octeon_irq_chip_ciu_mbox;
1497*4882a593Smuzhiyun chip_wd = &octeon_irq_chip_ciu_wd;
1498*4882a593Smuzhiyun octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio;
1499*4882a593Smuzhiyun }
1500*4882a593Smuzhiyun octeon_irq_ciu_chip = chip;
1501*4882a593Smuzhiyun octeon_irq_ciu_chip_edge = chip_edge;
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun /* Mips internal */
1504*4882a593Smuzhiyun octeon_irq_init_core();
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun ciu_domain = irq_domain_add_tree(
1507*4882a593Smuzhiyun ciu_node, &octeon_irq_domain_ciu_ops, dd);
1508*4882a593Smuzhiyun irq_set_default_host(ciu_domain);
1509*4882a593Smuzhiyun
1510*4882a593Smuzhiyun /* CIU_0 */
1511*4882a593Smuzhiyun for (i = 0; i < 16; i++) {
1512*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
1513*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_WORKQ0, 0, i + 0);
1514*4882a593Smuzhiyun if (r)
1515*4882a593Smuzhiyun goto err;
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun r = octeon_irq_set_ciu_mapping(
1519*4882a593Smuzhiyun OCTEON_IRQ_MBOX0, 0, 32, 0, chip_mbox, handle_percpu_irq);
1520*4882a593Smuzhiyun if (r)
1521*4882a593Smuzhiyun goto err;
1522*4882a593Smuzhiyun r = octeon_irq_set_ciu_mapping(
1523*4882a593Smuzhiyun OCTEON_IRQ_MBOX1, 0, 33, 0, chip_mbox, handle_percpu_irq);
1524*4882a593Smuzhiyun if (r)
1525*4882a593Smuzhiyun goto err;
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
1528*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
1529*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_PCI_INT0, 0, i + 36);
1530*4882a593Smuzhiyun if (r)
1531*4882a593Smuzhiyun goto err;
1532*4882a593Smuzhiyun }
1533*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
1534*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
1535*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 0, i + 40);
1536*4882a593Smuzhiyun if (r)
1537*4882a593Smuzhiyun goto err;
1538*4882a593Smuzhiyun }
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_TWSI, 0, 45);
1541*4882a593Smuzhiyun if (r)
1542*4882a593Smuzhiyun goto err;
1543*4882a593Smuzhiyun
1544*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46);
1545*4882a593Smuzhiyun if (r)
1546*4882a593Smuzhiyun goto err;
1547*4882a593Smuzhiyun
1548*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
1549*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
1550*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52);
1551*4882a593Smuzhiyun if (r)
1552*4882a593Smuzhiyun goto err;
1553*4882a593Smuzhiyun }
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_TWSI2, 0, 59);
1556*4882a593Smuzhiyun if (r)
1557*4882a593Smuzhiyun goto err;
1558*4882a593Smuzhiyun
1559*4882a593Smuzhiyun /* CIU_1 */
1560*4882a593Smuzhiyun for (i = 0; i < 16; i++) {
1561*4882a593Smuzhiyun r = octeon_irq_set_ciu_mapping(
1562*4882a593Smuzhiyun i + OCTEON_IRQ_WDOG0, 1, i + 0, 0, chip_wd,
1563*4882a593Smuzhiyun handle_level_irq);
1564*4882a593Smuzhiyun if (r)
1565*4882a593Smuzhiyun goto err;
1566*4882a593Smuzhiyun }
1567*4882a593Smuzhiyun
1568*4882a593Smuzhiyun /* Enable the CIU lines */
1569*4882a593Smuzhiyun set_c0_status(STATUSF_IP3 | STATUSF_IP2);
1570*4882a593Smuzhiyun if (octeon_irq_use_ip4)
1571*4882a593Smuzhiyun set_c0_status(STATUSF_IP4);
1572*4882a593Smuzhiyun else
1573*4882a593Smuzhiyun clear_c0_status(STATUSF_IP4);
1574*4882a593Smuzhiyun
1575*4882a593Smuzhiyun return 0;
1576*4882a593Smuzhiyun err:
1577*4882a593Smuzhiyun return r;
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun
octeon_irq_init_gpio(struct device_node * gpio_node,struct device_node * parent)1580*4882a593Smuzhiyun static int __init octeon_irq_init_gpio(
1581*4882a593Smuzhiyun struct device_node *gpio_node, struct device_node *parent)
1582*4882a593Smuzhiyun {
1583*4882a593Smuzhiyun struct octeon_irq_gpio_domain_data *gpiod;
1584*4882a593Smuzhiyun u32 interrupt_cells;
1585*4882a593Smuzhiyun unsigned int base_hwirq;
1586*4882a593Smuzhiyun int r;
1587*4882a593Smuzhiyun
1588*4882a593Smuzhiyun r = of_property_read_u32(parent, "#interrupt-cells", &interrupt_cells);
1589*4882a593Smuzhiyun if (r)
1590*4882a593Smuzhiyun return r;
1591*4882a593Smuzhiyun
1592*4882a593Smuzhiyun if (interrupt_cells == 1) {
1593*4882a593Smuzhiyun u32 v;
1594*4882a593Smuzhiyun
1595*4882a593Smuzhiyun r = of_property_read_u32_index(gpio_node, "interrupts", 0, &v);
1596*4882a593Smuzhiyun if (r) {
1597*4882a593Smuzhiyun pr_warn("No \"interrupts\" property.\n");
1598*4882a593Smuzhiyun return r;
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun base_hwirq = v;
1601*4882a593Smuzhiyun } else if (interrupt_cells == 2) {
1602*4882a593Smuzhiyun u32 v0, v1;
1603*4882a593Smuzhiyun
1604*4882a593Smuzhiyun r = of_property_read_u32_index(gpio_node, "interrupts", 0, &v0);
1605*4882a593Smuzhiyun if (r) {
1606*4882a593Smuzhiyun pr_warn("No \"interrupts\" property.\n");
1607*4882a593Smuzhiyun return r;
1608*4882a593Smuzhiyun }
1609*4882a593Smuzhiyun r = of_property_read_u32_index(gpio_node, "interrupts", 1, &v1);
1610*4882a593Smuzhiyun if (r) {
1611*4882a593Smuzhiyun pr_warn("No \"interrupts\" property.\n");
1612*4882a593Smuzhiyun return r;
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun base_hwirq = (v0 << 6) | v1;
1615*4882a593Smuzhiyun } else {
1616*4882a593Smuzhiyun pr_warn("Bad \"#interrupt-cells\" property: %u\n",
1617*4882a593Smuzhiyun interrupt_cells);
1618*4882a593Smuzhiyun return -EINVAL;
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun
1621*4882a593Smuzhiyun gpiod = kzalloc(sizeof(*gpiod), GFP_KERNEL);
1622*4882a593Smuzhiyun if (gpiod) {
1623*4882a593Smuzhiyun /* gpio domain host_data is the base hwirq number. */
1624*4882a593Smuzhiyun gpiod->base_hwirq = base_hwirq;
1625*4882a593Smuzhiyun irq_domain_add_linear(
1626*4882a593Smuzhiyun gpio_node, 16, &octeon_irq_domain_gpio_ops, gpiod);
1627*4882a593Smuzhiyun } else {
1628*4882a593Smuzhiyun pr_warn("Cannot allocate memory for GPIO irq_domain.\n");
1629*4882a593Smuzhiyun return -ENOMEM;
1630*4882a593Smuzhiyun }
1631*4882a593Smuzhiyun
1632*4882a593Smuzhiyun /*
1633*4882a593Smuzhiyun * Clear the OF_POPULATED flag that was set by of_irq_init()
1634*4882a593Smuzhiyun * so that all GPIO devices will be probed.
1635*4882a593Smuzhiyun */
1636*4882a593Smuzhiyun of_node_clear_flag(gpio_node, OF_POPULATED);
1637*4882a593Smuzhiyun
1638*4882a593Smuzhiyun return 0;
1639*4882a593Smuzhiyun }
1640*4882a593Smuzhiyun /*
1641*4882a593Smuzhiyun * Watchdog interrupts are special. They are associated with a single
1642*4882a593Smuzhiyun * core, so we hardwire the affinity to that core.
1643*4882a593Smuzhiyun */
octeon_irq_ciu2_wd_enable(struct irq_data * data)1644*4882a593Smuzhiyun static void octeon_irq_ciu2_wd_enable(struct irq_data *data)
1645*4882a593Smuzhiyun {
1646*4882a593Smuzhiyun u64 mask;
1647*4882a593Smuzhiyun u64 en_addr;
1648*4882a593Smuzhiyun int coreid = data->irq - OCTEON_IRQ_WDOG0;
1649*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1652*4882a593Smuzhiyun mask = 1ull << (cd->bit);
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(coreid) +
1655*4882a593Smuzhiyun (0x1000ull * cd->line);
1656*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun }
1659*4882a593Smuzhiyun
octeon_irq_ciu2_enable(struct irq_data * data)1660*4882a593Smuzhiyun static void octeon_irq_ciu2_enable(struct irq_data *data)
1661*4882a593Smuzhiyun {
1662*4882a593Smuzhiyun u64 mask;
1663*4882a593Smuzhiyun u64 en_addr;
1664*4882a593Smuzhiyun int cpu = next_cpu_for_irq(data);
1665*4882a593Smuzhiyun int coreid = octeon_coreid_for_cpu(cpu);
1666*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1669*4882a593Smuzhiyun mask = 1ull << (cd->bit);
1670*4882a593Smuzhiyun
1671*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(coreid) +
1672*4882a593Smuzhiyun (0x1000ull * cd->line);
1673*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1674*4882a593Smuzhiyun }
1675*4882a593Smuzhiyun
octeon_irq_ciu2_enable_local(struct irq_data * data)1676*4882a593Smuzhiyun static void octeon_irq_ciu2_enable_local(struct irq_data *data)
1677*4882a593Smuzhiyun {
1678*4882a593Smuzhiyun u64 mask;
1679*4882a593Smuzhiyun u64 en_addr;
1680*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1681*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1684*4882a593Smuzhiyun mask = 1ull << (cd->bit);
1685*4882a593Smuzhiyun
1686*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(coreid) +
1687*4882a593Smuzhiyun (0x1000ull * cd->line);
1688*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1689*4882a593Smuzhiyun
1690*4882a593Smuzhiyun }
1691*4882a593Smuzhiyun
octeon_irq_ciu2_disable_local(struct irq_data * data)1692*4882a593Smuzhiyun static void octeon_irq_ciu2_disable_local(struct irq_data *data)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun u64 mask;
1695*4882a593Smuzhiyun u64 en_addr;
1696*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1697*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1698*4882a593Smuzhiyun
1699*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1700*4882a593Smuzhiyun mask = 1ull << (cd->bit);
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(coreid) +
1703*4882a593Smuzhiyun (0x1000ull * cd->line);
1704*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1705*4882a593Smuzhiyun
1706*4882a593Smuzhiyun }
1707*4882a593Smuzhiyun
octeon_irq_ciu2_ack(struct irq_data * data)1708*4882a593Smuzhiyun static void octeon_irq_ciu2_ack(struct irq_data *data)
1709*4882a593Smuzhiyun {
1710*4882a593Smuzhiyun u64 mask;
1711*4882a593Smuzhiyun u64 en_addr;
1712*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1713*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1714*4882a593Smuzhiyun
1715*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1716*4882a593Smuzhiyun mask = 1ull << (cd->bit);
1717*4882a593Smuzhiyun
1718*4882a593Smuzhiyun en_addr = CVMX_CIU2_RAW_PPX_IP2_WRKQ(coreid) + (0x1000ull * cd->line);
1719*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun }
1722*4882a593Smuzhiyun
octeon_irq_ciu2_disable_all(struct irq_data * data)1723*4882a593Smuzhiyun static void octeon_irq_ciu2_disable_all(struct irq_data *data)
1724*4882a593Smuzhiyun {
1725*4882a593Smuzhiyun int cpu;
1726*4882a593Smuzhiyun u64 mask;
1727*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1728*4882a593Smuzhiyun
1729*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1730*4882a593Smuzhiyun mask = 1ull << (cd->bit);
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun for_each_online_cpu(cpu) {
1733*4882a593Smuzhiyun u64 en_addr = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(
1734*4882a593Smuzhiyun octeon_coreid_for_cpu(cpu)) + (0x1000ull * cd->line);
1735*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1736*4882a593Smuzhiyun }
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun
octeon_irq_ciu2_mbox_enable_all(struct irq_data * data)1739*4882a593Smuzhiyun static void octeon_irq_ciu2_mbox_enable_all(struct irq_data *data)
1740*4882a593Smuzhiyun {
1741*4882a593Smuzhiyun int cpu;
1742*4882a593Smuzhiyun u64 mask;
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun mask = 1ull << (data->irq - OCTEON_IRQ_MBOX0);
1745*4882a593Smuzhiyun
1746*4882a593Smuzhiyun for_each_online_cpu(cpu) {
1747*4882a593Smuzhiyun u64 en_addr = CVMX_CIU2_EN_PPX_IP3_MBOX_W1S(
1748*4882a593Smuzhiyun octeon_coreid_for_cpu(cpu));
1749*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1750*4882a593Smuzhiyun }
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun
octeon_irq_ciu2_mbox_disable_all(struct irq_data * data)1753*4882a593Smuzhiyun static void octeon_irq_ciu2_mbox_disable_all(struct irq_data *data)
1754*4882a593Smuzhiyun {
1755*4882a593Smuzhiyun int cpu;
1756*4882a593Smuzhiyun u64 mask;
1757*4882a593Smuzhiyun
1758*4882a593Smuzhiyun mask = 1ull << (data->irq - OCTEON_IRQ_MBOX0);
1759*4882a593Smuzhiyun
1760*4882a593Smuzhiyun for_each_online_cpu(cpu) {
1761*4882a593Smuzhiyun u64 en_addr = CVMX_CIU2_EN_PPX_IP3_MBOX_W1C(
1762*4882a593Smuzhiyun octeon_coreid_for_cpu(cpu));
1763*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1764*4882a593Smuzhiyun }
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun
octeon_irq_ciu2_mbox_enable_local(struct irq_data * data)1767*4882a593Smuzhiyun static void octeon_irq_ciu2_mbox_enable_local(struct irq_data *data)
1768*4882a593Smuzhiyun {
1769*4882a593Smuzhiyun u64 mask;
1770*4882a593Smuzhiyun u64 en_addr;
1771*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun mask = 1ull << (data->irq - OCTEON_IRQ_MBOX0);
1774*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP3_MBOX_W1S(coreid);
1775*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1776*4882a593Smuzhiyun }
1777*4882a593Smuzhiyun
octeon_irq_ciu2_mbox_disable_local(struct irq_data * data)1778*4882a593Smuzhiyun static void octeon_irq_ciu2_mbox_disable_local(struct irq_data *data)
1779*4882a593Smuzhiyun {
1780*4882a593Smuzhiyun u64 mask;
1781*4882a593Smuzhiyun u64 en_addr;
1782*4882a593Smuzhiyun int coreid = cvmx_get_core_num();
1783*4882a593Smuzhiyun
1784*4882a593Smuzhiyun mask = 1ull << (data->irq - OCTEON_IRQ_MBOX0);
1785*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP3_MBOX_W1C(coreid);
1786*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1787*4882a593Smuzhiyun }
1788*4882a593Smuzhiyun
1789*4882a593Smuzhiyun #ifdef CONFIG_SMP
octeon_irq_ciu2_set_affinity(struct irq_data * data,const struct cpumask * dest,bool force)1790*4882a593Smuzhiyun static int octeon_irq_ciu2_set_affinity(struct irq_data *data,
1791*4882a593Smuzhiyun const struct cpumask *dest, bool force)
1792*4882a593Smuzhiyun {
1793*4882a593Smuzhiyun int cpu;
1794*4882a593Smuzhiyun bool enable_one = !irqd_irq_disabled(data) && !irqd_irq_masked(data);
1795*4882a593Smuzhiyun u64 mask;
1796*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1797*4882a593Smuzhiyun
1798*4882a593Smuzhiyun if (!enable_one)
1799*4882a593Smuzhiyun return 0;
1800*4882a593Smuzhiyun
1801*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1802*4882a593Smuzhiyun mask = 1ull << cd->bit;
1803*4882a593Smuzhiyun
1804*4882a593Smuzhiyun for_each_online_cpu(cpu) {
1805*4882a593Smuzhiyun u64 en_addr;
1806*4882a593Smuzhiyun if (cpumask_test_cpu(cpu, dest) && enable_one) {
1807*4882a593Smuzhiyun enable_one = false;
1808*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1S(
1809*4882a593Smuzhiyun octeon_coreid_for_cpu(cpu)) +
1810*4882a593Smuzhiyun (0x1000ull * cd->line);
1811*4882a593Smuzhiyun } else {
1812*4882a593Smuzhiyun en_addr = CVMX_CIU2_EN_PPX_IP2_WRKQ_W1C(
1813*4882a593Smuzhiyun octeon_coreid_for_cpu(cpu)) +
1814*4882a593Smuzhiyun (0x1000ull * cd->line);
1815*4882a593Smuzhiyun }
1816*4882a593Smuzhiyun cvmx_write_csr(en_addr, mask);
1817*4882a593Smuzhiyun }
1818*4882a593Smuzhiyun
1819*4882a593Smuzhiyun return 0;
1820*4882a593Smuzhiyun }
1821*4882a593Smuzhiyun #endif
1822*4882a593Smuzhiyun
octeon_irq_ciu2_enable_gpio(struct irq_data * data)1823*4882a593Smuzhiyun static void octeon_irq_ciu2_enable_gpio(struct irq_data *data)
1824*4882a593Smuzhiyun {
1825*4882a593Smuzhiyun octeon_irq_gpio_setup(data);
1826*4882a593Smuzhiyun octeon_irq_ciu2_enable(data);
1827*4882a593Smuzhiyun }
1828*4882a593Smuzhiyun
octeon_irq_ciu2_disable_gpio(struct irq_data * data)1829*4882a593Smuzhiyun static void octeon_irq_ciu2_disable_gpio(struct irq_data *data)
1830*4882a593Smuzhiyun {
1831*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
1832*4882a593Smuzhiyun
1833*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
1834*4882a593Smuzhiyun
1835*4882a593Smuzhiyun cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd->gpio_line), 0);
1836*4882a593Smuzhiyun
1837*4882a593Smuzhiyun octeon_irq_ciu2_disable_all(data);
1838*4882a593Smuzhiyun }
1839*4882a593Smuzhiyun
1840*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu2 = {
1841*4882a593Smuzhiyun .name = "CIU2-E",
1842*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu2_enable,
1843*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu2_disable_all,
1844*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu2_disable_local,
1845*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu2_enable,
1846*4882a593Smuzhiyun #ifdef CONFIG_SMP
1847*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu2_set_affinity,
1848*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
1849*4882a593Smuzhiyun #endif
1850*4882a593Smuzhiyun };
1851*4882a593Smuzhiyun
1852*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu2_edge = {
1853*4882a593Smuzhiyun .name = "CIU2-E",
1854*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu2_enable,
1855*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu2_disable_all,
1856*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu2_ack,
1857*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu2_disable_local,
1858*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu2_enable,
1859*4882a593Smuzhiyun #ifdef CONFIG_SMP
1860*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu2_set_affinity,
1861*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
1862*4882a593Smuzhiyun #endif
1863*4882a593Smuzhiyun };
1864*4882a593Smuzhiyun
1865*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu2_mbox = {
1866*4882a593Smuzhiyun .name = "CIU2-M",
1867*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu2_mbox_enable_all,
1868*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu2_mbox_disable_all,
1869*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu2_mbox_disable_local,
1870*4882a593Smuzhiyun .irq_eoi = octeon_irq_ciu2_mbox_enable_local,
1871*4882a593Smuzhiyun
1872*4882a593Smuzhiyun .irq_cpu_online = octeon_irq_ciu2_mbox_enable_local,
1873*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_ciu2_mbox_disable_local,
1874*4882a593Smuzhiyun .flags = IRQCHIP_ONOFFLINE_ENABLED,
1875*4882a593Smuzhiyun };
1876*4882a593Smuzhiyun
1877*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu2_wd = {
1878*4882a593Smuzhiyun .name = "CIU2-W",
1879*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu2_wd_enable,
1880*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu2_disable_all,
1881*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu2_disable_local,
1882*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu2_enable_local,
1883*4882a593Smuzhiyun };
1884*4882a593Smuzhiyun
1885*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu2_gpio = {
1886*4882a593Smuzhiyun .name = "CIU-GPIO",
1887*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu2_enable_gpio,
1888*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu2_disable_gpio,
1889*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu_gpio_ack,
1890*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu2_disable_local,
1891*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu2_enable,
1892*4882a593Smuzhiyun .irq_set_type = octeon_irq_ciu_gpio_set_type,
1893*4882a593Smuzhiyun #ifdef CONFIG_SMP
1894*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu2_set_affinity,
1895*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
1896*4882a593Smuzhiyun #endif
1897*4882a593Smuzhiyun .flags = IRQCHIP_SET_TYPE_MASKED,
1898*4882a593Smuzhiyun };
1899*4882a593Smuzhiyun
octeon_irq_ciu2_xlat(struct irq_domain * d,struct device_node * node,const u32 * intspec,unsigned int intsize,unsigned long * out_hwirq,unsigned int * out_type)1900*4882a593Smuzhiyun static int octeon_irq_ciu2_xlat(struct irq_domain *d,
1901*4882a593Smuzhiyun struct device_node *node,
1902*4882a593Smuzhiyun const u32 *intspec,
1903*4882a593Smuzhiyun unsigned int intsize,
1904*4882a593Smuzhiyun unsigned long *out_hwirq,
1905*4882a593Smuzhiyun unsigned int *out_type)
1906*4882a593Smuzhiyun {
1907*4882a593Smuzhiyun unsigned int ciu, bit;
1908*4882a593Smuzhiyun
1909*4882a593Smuzhiyun ciu = intspec[0];
1910*4882a593Smuzhiyun bit = intspec[1];
1911*4882a593Smuzhiyun
1912*4882a593Smuzhiyun *out_hwirq = (ciu << 6) | bit;
1913*4882a593Smuzhiyun *out_type = 0;
1914*4882a593Smuzhiyun
1915*4882a593Smuzhiyun return 0;
1916*4882a593Smuzhiyun }
1917*4882a593Smuzhiyun
octeon_irq_ciu2_is_edge(unsigned int line,unsigned int bit)1918*4882a593Smuzhiyun static bool octeon_irq_ciu2_is_edge(unsigned int line, unsigned int bit)
1919*4882a593Smuzhiyun {
1920*4882a593Smuzhiyun bool edge = false;
1921*4882a593Smuzhiyun
1922*4882a593Smuzhiyun if (line == 3) /* MIO */
1923*4882a593Smuzhiyun switch (bit) {
1924*4882a593Smuzhiyun case 2: /* IPD_DRP */
1925*4882a593Smuzhiyun case 8 ... 11: /* Timers */
1926*4882a593Smuzhiyun case 48: /* PTP */
1927*4882a593Smuzhiyun edge = true;
1928*4882a593Smuzhiyun break;
1929*4882a593Smuzhiyun default:
1930*4882a593Smuzhiyun break;
1931*4882a593Smuzhiyun }
1932*4882a593Smuzhiyun else if (line == 6) /* PKT */
1933*4882a593Smuzhiyun switch (bit) {
1934*4882a593Smuzhiyun case 52 ... 53: /* ILK_DRP */
1935*4882a593Smuzhiyun case 8 ... 12: /* GMX_DRP */
1936*4882a593Smuzhiyun edge = true;
1937*4882a593Smuzhiyun break;
1938*4882a593Smuzhiyun default:
1939*4882a593Smuzhiyun break;
1940*4882a593Smuzhiyun }
1941*4882a593Smuzhiyun return edge;
1942*4882a593Smuzhiyun }
1943*4882a593Smuzhiyun
octeon_irq_ciu2_map(struct irq_domain * d,unsigned int virq,irq_hw_number_t hw)1944*4882a593Smuzhiyun static int octeon_irq_ciu2_map(struct irq_domain *d,
1945*4882a593Smuzhiyun unsigned int virq, irq_hw_number_t hw)
1946*4882a593Smuzhiyun {
1947*4882a593Smuzhiyun unsigned int line = hw >> 6;
1948*4882a593Smuzhiyun unsigned int bit = hw & 63;
1949*4882a593Smuzhiyun
1950*4882a593Smuzhiyun /*
1951*4882a593Smuzhiyun * Don't map irq if it is reserved for GPIO.
1952*4882a593Smuzhiyun * (Line 7 are the GPIO lines.)
1953*4882a593Smuzhiyun */
1954*4882a593Smuzhiyun if (line == 7)
1955*4882a593Smuzhiyun return 0;
1956*4882a593Smuzhiyun
1957*4882a593Smuzhiyun if (line > 7 || octeon_irq_ciu_to_irq[line][bit] != 0)
1958*4882a593Smuzhiyun return -EINVAL;
1959*4882a593Smuzhiyun
1960*4882a593Smuzhiyun if (octeon_irq_ciu2_is_edge(line, bit))
1961*4882a593Smuzhiyun octeon_irq_set_ciu_mapping(virq, line, bit, 0,
1962*4882a593Smuzhiyun &octeon_irq_chip_ciu2_edge,
1963*4882a593Smuzhiyun handle_edge_irq);
1964*4882a593Smuzhiyun else
1965*4882a593Smuzhiyun octeon_irq_set_ciu_mapping(virq, line, bit, 0,
1966*4882a593Smuzhiyun &octeon_irq_chip_ciu2,
1967*4882a593Smuzhiyun handle_level_irq);
1968*4882a593Smuzhiyun
1969*4882a593Smuzhiyun return 0;
1970*4882a593Smuzhiyun }
1971*4882a593Smuzhiyun
1972*4882a593Smuzhiyun static struct irq_domain_ops octeon_irq_domain_ciu2_ops = {
1973*4882a593Smuzhiyun .map = octeon_irq_ciu2_map,
1974*4882a593Smuzhiyun .unmap = octeon_irq_free_cd,
1975*4882a593Smuzhiyun .xlate = octeon_irq_ciu2_xlat,
1976*4882a593Smuzhiyun };
1977*4882a593Smuzhiyun
octeon_irq_ciu2(void)1978*4882a593Smuzhiyun static void octeon_irq_ciu2(void)
1979*4882a593Smuzhiyun {
1980*4882a593Smuzhiyun int line;
1981*4882a593Smuzhiyun int bit;
1982*4882a593Smuzhiyun int irq;
1983*4882a593Smuzhiyun u64 src_reg, src, sum;
1984*4882a593Smuzhiyun const unsigned long core_id = cvmx_get_core_num();
1985*4882a593Smuzhiyun
1986*4882a593Smuzhiyun sum = cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(core_id)) & 0xfful;
1987*4882a593Smuzhiyun
1988*4882a593Smuzhiyun if (unlikely(!sum))
1989*4882a593Smuzhiyun goto spurious;
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun line = fls64(sum) - 1;
1992*4882a593Smuzhiyun src_reg = CVMX_CIU2_SRC_PPX_IP2_WRKQ(core_id) + (0x1000 * line);
1993*4882a593Smuzhiyun src = cvmx_read_csr(src_reg);
1994*4882a593Smuzhiyun
1995*4882a593Smuzhiyun if (unlikely(!src))
1996*4882a593Smuzhiyun goto spurious;
1997*4882a593Smuzhiyun
1998*4882a593Smuzhiyun bit = fls64(src) - 1;
1999*4882a593Smuzhiyun irq = octeon_irq_ciu_to_irq[line][bit];
2000*4882a593Smuzhiyun if (unlikely(!irq))
2001*4882a593Smuzhiyun goto spurious;
2002*4882a593Smuzhiyun
2003*4882a593Smuzhiyun do_IRQ(irq);
2004*4882a593Smuzhiyun goto out;
2005*4882a593Smuzhiyun
2006*4882a593Smuzhiyun spurious:
2007*4882a593Smuzhiyun spurious_interrupt();
2008*4882a593Smuzhiyun out:
2009*4882a593Smuzhiyun /* CN68XX pass 1.x has an errata that accessing the ACK registers
2010*4882a593Smuzhiyun can stop interrupts from propagating */
2011*4882a593Smuzhiyun if (OCTEON_IS_MODEL(OCTEON_CN68XX))
2012*4882a593Smuzhiyun cvmx_read_csr(CVMX_CIU2_INTR_CIU_READY);
2013*4882a593Smuzhiyun else
2014*4882a593Smuzhiyun cvmx_read_csr(CVMX_CIU2_ACK_PPX_IP2(core_id));
2015*4882a593Smuzhiyun return;
2016*4882a593Smuzhiyun }
2017*4882a593Smuzhiyun
octeon_irq_ciu2_mbox(void)2018*4882a593Smuzhiyun static void octeon_irq_ciu2_mbox(void)
2019*4882a593Smuzhiyun {
2020*4882a593Smuzhiyun int line;
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun const unsigned long core_id = cvmx_get_core_num();
2023*4882a593Smuzhiyun u64 sum = cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP3(core_id)) >> 60;
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun if (unlikely(!sum))
2026*4882a593Smuzhiyun goto spurious;
2027*4882a593Smuzhiyun
2028*4882a593Smuzhiyun line = fls64(sum) - 1;
2029*4882a593Smuzhiyun
2030*4882a593Smuzhiyun do_IRQ(OCTEON_IRQ_MBOX0 + line);
2031*4882a593Smuzhiyun goto out;
2032*4882a593Smuzhiyun
2033*4882a593Smuzhiyun spurious:
2034*4882a593Smuzhiyun spurious_interrupt();
2035*4882a593Smuzhiyun out:
2036*4882a593Smuzhiyun /* CN68XX pass 1.x has an errata that accessing the ACK registers
2037*4882a593Smuzhiyun can stop interrupts from propagating */
2038*4882a593Smuzhiyun if (OCTEON_IS_MODEL(OCTEON_CN68XX))
2039*4882a593Smuzhiyun cvmx_read_csr(CVMX_CIU2_INTR_CIU_READY);
2040*4882a593Smuzhiyun else
2041*4882a593Smuzhiyun cvmx_read_csr(CVMX_CIU2_ACK_PPX_IP3(core_id));
2042*4882a593Smuzhiyun return;
2043*4882a593Smuzhiyun }
2044*4882a593Smuzhiyun
octeon_irq_init_ciu2(struct device_node * ciu_node,struct device_node * parent)2045*4882a593Smuzhiyun static int __init octeon_irq_init_ciu2(
2046*4882a593Smuzhiyun struct device_node *ciu_node, struct device_node *parent)
2047*4882a593Smuzhiyun {
2048*4882a593Smuzhiyun unsigned int i, r;
2049*4882a593Smuzhiyun struct irq_domain *ciu_domain = NULL;
2050*4882a593Smuzhiyun
2051*4882a593Smuzhiyun octeon_irq_init_ciu2_percpu();
2052*4882a593Smuzhiyun octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu2;
2053*4882a593Smuzhiyun
2054*4882a593Smuzhiyun octeon_irq_gpio_chip = &octeon_irq_chip_ciu2_gpio;
2055*4882a593Smuzhiyun octeon_irq_ip2 = octeon_irq_ciu2;
2056*4882a593Smuzhiyun octeon_irq_ip3 = octeon_irq_ciu2_mbox;
2057*4882a593Smuzhiyun octeon_irq_ip4 = octeon_irq_ip4_mask;
2058*4882a593Smuzhiyun
2059*4882a593Smuzhiyun /* Mips internal */
2060*4882a593Smuzhiyun octeon_irq_init_core();
2061*4882a593Smuzhiyun
2062*4882a593Smuzhiyun ciu_domain = irq_domain_add_tree(
2063*4882a593Smuzhiyun ciu_node, &octeon_irq_domain_ciu2_ops, NULL);
2064*4882a593Smuzhiyun irq_set_default_host(ciu_domain);
2065*4882a593Smuzhiyun
2066*4882a593Smuzhiyun /* CUI2 */
2067*4882a593Smuzhiyun for (i = 0; i < 64; i++) {
2068*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
2069*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_WORKQ0, 0, i);
2070*4882a593Smuzhiyun if (r)
2071*4882a593Smuzhiyun goto err;
2072*4882a593Smuzhiyun }
2073*4882a593Smuzhiyun
2074*4882a593Smuzhiyun for (i = 0; i < 32; i++) {
2075*4882a593Smuzhiyun r = octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i, 0,
2076*4882a593Smuzhiyun &octeon_irq_chip_ciu2_wd, handle_level_irq);
2077*4882a593Smuzhiyun if (r)
2078*4882a593Smuzhiyun goto err;
2079*4882a593Smuzhiyun }
2080*4882a593Smuzhiyun
2081*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
2082*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
2083*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_TIMER0, 3, i + 8);
2084*4882a593Smuzhiyun if (r)
2085*4882a593Smuzhiyun goto err;
2086*4882a593Smuzhiyun }
2087*4882a593Smuzhiyun
2088*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
2089*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
2090*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_PCI_INT0, 4, i);
2091*4882a593Smuzhiyun if (r)
2092*4882a593Smuzhiyun goto err;
2093*4882a593Smuzhiyun }
2094*4882a593Smuzhiyun
2095*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
2096*4882a593Smuzhiyun r = octeon_irq_force_ciu_mapping(
2097*4882a593Smuzhiyun ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 4, i + 8);
2098*4882a593Smuzhiyun if (r)
2099*4882a593Smuzhiyun goto err;
2100*4882a593Smuzhiyun }
2101*4882a593Smuzhiyun
2102*4882a593Smuzhiyun irq_set_chip_and_handler(OCTEON_IRQ_MBOX0, &octeon_irq_chip_ciu2_mbox, handle_percpu_irq);
2103*4882a593Smuzhiyun irq_set_chip_and_handler(OCTEON_IRQ_MBOX1, &octeon_irq_chip_ciu2_mbox, handle_percpu_irq);
2104*4882a593Smuzhiyun irq_set_chip_and_handler(OCTEON_IRQ_MBOX2, &octeon_irq_chip_ciu2_mbox, handle_percpu_irq);
2105*4882a593Smuzhiyun irq_set_chip_and_handler(OCTEON_IRQ_MBOX3, &octeon_irq_chip_ciu2_mbox, handle_percpu_irq);
2106*4882a593Smuzhiyun
2107*4882a593Smuzhiyun /* Enable the CIU lines */
2108*4882a593Smuzhiyun set_c0_status(STATUSF_IP3 | STATUSF_IP2);
2109*4882a593Smuzhiyun clear_c0_status(STATUSF_IP4);
2110*4882a593Smuzhiyun return 0;
2111*4882a593Smuzhiyun err:
2112*4882a593Smuzhiyun return r;
2113*4882a593Smuzhiyun }
2114*4882a593Smuzhiyun
2115*4882a593Smuzhiyun struct octeon_irq_cib_host_data {
2116*4882a593Smuzhiyun raw_spinlock_t lock;
2117*4882a593Smuzhiyun u64 raw_reg;
2118*4882a593Smuzhiyun u64 en_reg;
2119*4882a593Smuzhiyun int max_bits;
2120*4882a593Smuzhiyun };
2121*4882a593Smuzhiyun
2122*4882a593Smuzhiyun struct octeon_irq_cib_chip_data {
2123*4882a593Smuzhiyun struct octeon_irq_cib_host_data *host_data;
2124*4882a593Smuzhiyun int bit;
2125*4882a593Smuzhiyun };
2126*4882a593Smuzhiyun
octeon_irq_cib_enable(struct irq_data * data)2127*4882a593Smuzhiyun static void octeon_irq_cib_enable(struct irq_data *data)
2128*4882a593Smuzhiyun {
2129*4882a593Smuzhiyun unsigned long flags;
2130*4882a593Smuzhiyun u64 en;
2131*4882a593Smuzhiyun struct octeon_irq_cib_chip_data *cd = irq_data_get_irq_chip_data(data);
2132*4882a593Smuzhiyun struct octeon_irq_cib_host_data *host_data = cd->host_data;
2133*4882a593Smuzhiyun
2134*4882a593Smuzhiyun raw_spin_lock_irqsave(&host_data->lock, flags);
2135*4882a593Smuzhiyun en = cvmx_read_csr(host_data->en_reg);
2136*4882a593Smuzhiyun en |= 1ull << cd->bit;
2137*4882a593Smuzhiyun cvmx_write_csr(host_data->en_reg, en);
2138*4882a593Smuzhiyun raw_spin_unlock_irqrestore(&host_data->lock, flags);
2139*4882a593Smuzhiyun }
2140*4882a593Smuzhiyun
octeon_irq_cib_disable(struct irq_data * data)2141*4882a593Smuzhiyun static void octeon_irq_cib_disable(struct irq_data *data)
2142*4882a593Smuzhiyun {
2143*4882a593Smuzhiyun unsigned long flags;
2144*4882a593Smuzhiyun u64 en;
2145*4882a593Smuzhiyun struct octeon_irq_cib_chip_data *cd = irq_data_get_irq_chip_data(data);
2146*4882a593Smuzhiyun struct octeon_irq_cib_host_data *host_data = cd->host_data;
2147*4882a593Smuzhiyun
2148*4882a593Smuzhiyun raw_spin_lock_irqsave(&host_data->lock, flags);
2149*4882a593Smuzhiyun en = cvmx_read_csr(host_data->en_reg);
2150*4882a593Smuzhiyun en &= ~(1ull << cd->bit);
2151*4882a593Smuzhiyun cvmx_write_csr(host_data->en_reg, en);
2152*4882a593Smuzhiyun raw_spin_unlock_irqrestore(&host_data->lock, flags);
2153*4882a593Smuzhiyun }
2154*4882a593Smuzhiyun
octeon_irq_cib_set_type(struct irq_data * data,unsigned int t)2155*4882a593Smuzhiyun static int octeon_irq_cib_set_type(struct irq_data *data, unsigned int t)
2156*4882a593Smuzhiyun {
2157*4882a593Smuzhiyun irqd_set_trigger_type(data, t);
2158*4882a593Smuzhiyun return IRQ_SET_MASK_OK;
2159*4882a593Smuzhiyun }
2160*4882a593Smuzhiyun
2161*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_cib = {
2162*4882a593Smuzhiyun .name = "CIB",
2163*4882a593Smuzhiyun .irq_enable = octeon_irq_cib_enable,
2164*4882a593Smuzhiyun .irq_disable = octeon_irq_cib_disable,
2165*4882a593Smuzhiyun .irq_mask = octeon_irq_cib_disable,
2166*4882a593Smuzhiyun .irq_unmask = octeon_irq_cib_enable,
2167*4882a593Smuzhiyun .irq_set_type = octeon_irq_cib_set_type,
2168*4882a593Smuzhiyun };
2169*4882a593Smuzhiyun
octeon_irq_cib_xlat(struct irq_domain * d,struct device_node * node,const u32 * intspec,unsigned int intsize,unsigned long * out_hwirq,unsigned int * out_type)2170*4882a593Smuzhiyun static int octeon_irq_cib_xlat(struct irq_domain *d,
2171*4882a593Smuzhiyun struct device_node *node,
2172*4882a593Smuzhiyun const u32 *intspec,
2173*4882a593Smuzhiyun unsigned int intsize,
2174*4882a593Smuzhiyun unsigned long *out_hwirq,
2175*4882a593Smuzhiyun unsigned int *out_type)
2176*4882a593Smuzhiyun {
2177*4882a593Smuzhiyun unsigned int type = 0;
2178*4882a593Smuzhiyun
2179*4882a593Smuzhiyun if (intsize == 2)
2180*4882a593Smuzhiyun type = intspec[1];
2181*4882a593Smuzhiyun
2182*4882a593Smuzhiyun switch (type) {
2183*4882a593Smuzhiyun case 0: /* unofficial value, but we might as well let it work. */
2184*4882a593Smuzhiyun case 4: /* official value for level triggering. */
2185*4882a593Smuzhiyun *out_type = IRQ_TYPE_LEVEL_HIGH;
2186*4882a593Smuzhiyun break;
2187*4882a593Smuzhiyun case 1: /* official value for edge triggering. */
2188*4882a593Smuzhiyun *out_type = IRQ_TYPE_EDGE_RISING;
2189*4882a593Smuzhiyun break;
2190*4882a593Smuzhiyun default: /* Nothing else is acceptable. */
2191*4882a593Smuzhiyun return -EINVAL;
2192*4882a593Smuzhiyun }
2193*4882a593Smuzhiyun
2194*4882a593Smuzhiyun *out_hwirq = intspec[0];
2195*4882a593Smuzhiyun
2196*4882a593Smuzhiyun return 0;
2197*4882a593Smuzhiyun }
2198*4882a593Smuzhiyun
octeon_irq_cib_map(struct irq_domain * d,unsigned int virq,irq_hw_number_t hw)2199*4882a593Smuzhiyun static int octeon_irq_cib_map(struct irq_domain *d,
2200*4882a593Smuzhiyun unsigned int virq, irq_hw_number_t hw)
2201*4882a593Smuzhiyun {
2202*4882a593Smuzhiyun struct octeon_irq_cib_host_data *host_data = d->host_data;
2203*4882a593Smuzhiyun struct octeon_irq_cib_chip_data *cd;
2204*4882a593Smuzhiyun
2205*4882a593Smuzhiyun if (hw >= host_data->max_bits) {
2206*4882a593Smuzhiyun pr_err("ERROR: %s mapping %u is too big!\n",
2207*4882a593Smuzhiyun irq_domain_get_of_node(d)->name, (unsigned)hw);
2208*4882a593Smuzhiyun return -EINVAL;
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun cd = kzalloc(sizeof(*cd), GFP_KERNEL);
2212*4882a593Smuzhiyun if (!cd)
2213*4882a593Smuzhiyun return -ENOMEM;
2214*4882a593Smuzhiyun
2215*4882a593Smuzhiyun cd->host_data = host_data;
2216*4882a593Smuzhiyun cd->bit = hw;
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &octeon_irq_chip_cib,
2219*4882a593Smuzhiyun handle_simple_irq);
2220*4882a593Smuzhiyun irq_set_chip_data(virq, cd);
2221*4882a593Smuzhiyun return 0;
2222*4882a593Smuzhiyun }
2223*4882a593Smuzhiyun
2224*4882a593Smuzhiyun static struct irq_domain_ops octeon_irq_domain_cib_ops = {
2225*4882a593Smuzhiyun .map = octeon_irq_cib_map,
2226*4882a593Smuzhiyun .unmap = octeon_irq_free_cd,
2227*4882a593Smuzhiyun .xlate = octeon_irq_cib_xlat,
2228*4882a593Smuzhiyun };
2229*4882a593Smuzhiyun
2230*4882a593Smuzhiyun /* Chain to real handler. */
octeon_irq_cib_handler(int my_irq,void * data)2231*4882a593Smuzhiyun static irqreturn_t octeon_irq_cib_handler(int my_irq, void *data)
2232*4882a593Smuzhiyun {
2233*4882a593Smuzhiyun u64 en;
2234*4882a593Smuzhiyun u64 raw;
2235*4882a593Smuzhiyun u64 bits;
2236*4882a593Smuzhiyun int i;
2237*4882a593Smuzhiyun int irq;
2238*4882a593Smuzhiyun struct irq_domain *cib_domain = data;
2239*4882a593Smuzhiyun struct octeon_irq_cib_host_data *host_data = cib_domain->host_data;
2240*4882a593Smuzhiyun
2241*4882a593Smuzhiyun en = cvmx_read_csr(host_data->en_reg);
2242*4882a593Smuzhiyun raw = cvmx_read_csr(host_data->raw_reg);
2243*4882a593Smuzhiyun
2244*4882a593Smuzhiyun bits = en & raw;
2245*4882a593Smuzhiyun
2246*4882a593Smuzhiyun for (i = 0; i < host_data->max_bits; i++) {
2247*4882a593Smuzhiyun if ((bits & 1ull << i) == 0)
2248*4882a593Smuzhiyun continue;
2249*4882a593Smuzhiyun irq = irq_find_mapping(cib_domain, i);
2250*4882a593Smuzhiyun if (!irq) {
2251*4882a593Smuzhiyun unsigned long flags;
2252*4882a593Smuzhiyun
2253*4882a593Smuzhiyun pr_err("ERROR: CIB bit %d@%llx IRQ unhandled, disabling\n",
2254*4882a593Smuzhiyun i, host_data->raw_reg);
2255*4882a593Smuzhiyun raw_spin_lock_irqsave(&host_data->lock, flags);
2256*4882a593Smuzhiyun en = cvmx_read_csr(host_data->en_reg);
2257*4882a593Smuzhiyun en &= ~(1ull << i);
2258*4882a593Smuzhiyun cvmx_write_csr(host_data->en_reg, en);
2259*4882a593Smuzhiyun cvmx_write_csr(host_data->raw_reg, 1ull << i);
2260*4882a593Smuzhiyun raw_spin_unlock_irqrestore(&host_data->lock, flags);
2261*4882a593Smuzhiyun } else {
2262*4882a593Smuzhiyun struct irq_desc *desc = irq_to_desc(irq);
2263*4882a593Smuzhiyun struct irq_data *irq_data = irq_desc_get_irq_data(desc);
2264*4882a593Smuzhiyun /* If edge, acknowledge the bit we will be sending. */
2265*4882a593Smuzhiyun if (irqd_get_trigger_type(irq_data) &
2266*4882a593Smuzhiyun IRQ_TYPE_EDGE_BOTH)
2267*4882a593Smuzhiyun cvmx_write_csr(host_data->raw_reg, 1ull << i);
2268*4882a593Smuzhiyun generic_handle_irq_desc(desc);
2269*4882a593Smuzhiyun }
2270*4882a593Smuzhiyun }
2271*4882a593Smuzhiyun
2272*4882a593Smuzhiyun return IRQ_HANDLED;
2273*4882a593Smuzhiyun }
2274*4882a593Smuzhiyun
octeon_irq_init_cib(struct device_node * ciu_node,struct device_node * parent)2275*4882a593Smuzhiyun static int __init octeon_irq_init_cib(struct device_node *ciu_node,
2276*4882a593Smuzhiyun struct device_node *parent)
2277*4882a593Smuzhiyun {
2278*4882a593Smuzhiyun const __be32 *addr;
2279*4882a593Smuzhiyun u32 val;
2280*4882a593Smuzhiyun struct octeon_irq_cib_host_data *host_data;
2281*4882a593Smuzhiyun int parent_irq;
2282*4882a593Smuzhiyun int r;
2283*4882a593Smuzhiyun struct irq_domain *cib_domain;
2284*4882a593Smuzhiyun
2285*4882a593Smuzhiyun parent_irq = irq_of_parse_and_map(ciu_node, 0);
2286*4882a593Smuzhiyun if (!parent_irq) {
2287*4882a593Smuzhiyun pr_err("ERROR: Couldn't acquire parent_irq for %pOFn\n",
2288*4882a593Smuzhiyun ciu_node);
2289*4882a593Smuzhiyun return -EINVAL;
2290*4882a593Smuzhiyun }
2291*4882a593Smuzhiyun
2292*4882a593Smuzhiyun host_data = kzalloc(sizeof(*host_data), GFP_KERNEL);
2293*4882a593Smuzhiyun if (!host_data)
2294*4882a593Smuzhiyun return -ENOMEM;
2295*4882a593Smuzhiyun raw_spin_lock_init(&host_data->lock);
2296*4882a593Smuzhiyun
2297*4882a593Smuzhiyun addr = of_get_address(ciu_node, 0, NULL, NULL);
2298*4882a593Smuzhiyun if (!addr) {
2299*4882a593Smuzhiyun pr_err("ERROR: Couldn't acquire reg(0) %pOFn\n", ciu_node);
2300*4882a593Smuzhiyun return -EINVAL;
2301*4882a593Smuzhiyun }
2302*4882a593Smuzhiyun host_data->raw_reg = (u64)phys_to_virt(
2303*4882a593Smuzhiyun of_translate_address(ciu_node, addr));
2304*4882a593Smuzhiyun
2305*4882a593Smuzhiyun addr = of_get_address(ciu_node, 1, NULL, NULL);
2306*4882a593Smuzhiyun if (!addr) {
2307*4882a593Smuzhiyun pr_err("ERROR: Couldn't acquire reg(1) %pOFn\n", ciu_node);
2308*4882a593Smuzhiyun return -EINVAL;
2309*4882a593Smuzhiyun }
2310*4882a593Smuzhiyun host_data->en_reg = (u64)phys_to_virt(
2311*4882a593Smuzhiyun of_translate_address(ciu_node, addr));
2312*4882a593Smuzhiyun
2313*4882a593Smuzhiyun r = of_property_read_u32(ciu_node, "cavium,max-bits", &val);
2314*4882a593Smuzhiyun if (r) {
2315*4882a593Smuzhiyun pr_err("ERROR: Couldn't read cavium,max-bits from %pOFn\n",
2316*4882a593Smuzhiyun ciu_node);
2317*4882a593Smuzhiyun return r;
2318*4882a593Smuzhiyun }
2319*4882a593Smuzhiyun host_data->max_bits = val;
2320*4882a593Smuzhiyun
2321*4882a593Smuzhiyun cib_domain = irq_domain_add_linear(ciu_node, host_data->max_bits,
2322*4882a593Smuzhiyun &octeon_irq_domain_cib_ops,
2323*4882a593Smuzhiyun host_data);
2324*4882a593Smuzhiyun if (!cib_domain) {
2325*4882a593Smuzhiyun pr_err("ERROR: Couldn't irq_domain_add_linear()\n");
2326*4882a593Smuzhiyun return -ENOMEM;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun
2329*4882a593Smuzhiyun cvmx_write_csr(host_data->en_reg, 0); /* disable all IRQs */
2330*4882a593Smuzhiyun cvmx_write_csr(host_data->raw_reg, ~0); /* ack any outstanding */
2331*4882a593Smuzhiyun
2332*4882a593Smuzhiyun r = request_irq(parent_irq, octeon_irq_cib_handler,
2333*4882a593Smuzhiyun IRQF_NO_THREAD, "cib", cib_domain);
2334*4882a593Smuzhiyun if (r) {
2335*4882a593Smuzhiyun pr_err("request_irq cib failed %d\n", r);
2336*4882a593Smuzhiyun return r;
2337*4882a593Smuzhiyun }
2338*4882a593Smuzhiyun pr_info("CIB interrupt controller probed: %llx %d\n",
2339*4882a593Smuzhiyun host_data->raw_reg, host_data->max_bits);
2340*4882a593Smuzhiyun return 0;
2341*4882a593Smuzhiyun }
2342*4882a593Smuzhiyun
octeon_irq_ciu3_xlat(struct irq_domain * d,struct device_node * node,const u32 * intspec,unsigned int intsize,unsigned long * out_hwirq,unsigned int * out_type)2343*4882a593Smuzhiyun int octeon_irq_ciu3_xlat(struct irq_domain *d,
2344*4882a593Smuzhiyun struct device_node *node,
2345*4882a593Smuzhiyun const u32 *intspec,
2346*4882a593Smuzhiyun unsigned int intsize,
2347*4882a593Smuzhiyun unsigned long *out_hwirq,
2348*4882a593Smuzhiyun unsigned int *out_type)
2349*4882a593Smuzhiyun {
2350*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info = d->host_data;
2351*4882a593Smuzhiyun unsigned int hwirq, type, intsn_major;
2352*4882a593Smuzhiyun union cvmx_ciu3_iscx_ctl isc;
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun if (intsize < 2)
2355*4882a593Smuzhiyun return -EINVAL;
2356*4882a593Smuzhiyun hwirq = intspec[0];
2357*4882a593Smuzhiyun type = intspec[1];
2358*4882a593Smuzhiyun
2359*4882a593Smuzhiyun if (hwirq >= (1 << 20))
2360*4882a593Smuzhiyun return -EINVAL;
2361*4882a593Smuzhiyun
2362*4882a593Smuzhiyun intsn_major = hwirq >> 12;
2363*4882a593Smuzhiyun switch (intsn_major) {
2364*4882a593Smuzhiyun case 0x04: /* Software handled separately. */
2365*4882a593Smuzhiyun return -EINVAL;
2366*4882a593Smuzhiyun default:
2367*4882a593Smuzhiyun break;
2368*4882a593Smuzhiyun }
2369*4882a593Smuzhiyun
2370*4882a593Smuzhiyun isc.u64 = cvmx_read_csr(ciu3_info->ciu3_addr + CIU3_ISC_CTL(hwirq));
2371*4882a593Smuzhiyun if (!isc.s.imp)
2372*4882a593Smuzhiyun return -EINVAL;
2373*4882a593Smuzhiyun
2374*4882a593Smuzhiyun switch (type) {
2375*4882a593Smuzhiyun case 4: /* official value for level triggering. */
2376*4882a593Smuzhiyun *out_type = IRQ_TYPE_LEVEL_HIGH;
2377*4882a593Smuzhiyun break;
2378*4882a593Smuzhiyun case 0: /* unofficial value, but we might as well let it work. */
2379*4882a593Smuzhiyun case 1: /* official value for edge triggering. */
2380*4882a593Smuzhiyun *out_type = IRQ_TYPE_EDGE_RISING;
2381*4882a593Smuzhiyun break;
2382*4882a593Smuzhiyun default: /* Nothing else is acceptable. */
2383*4882a593Smuzhiyun return -EINVAL;
2384*4882a593Smuzhiyun }
2385*4882a593Smuzhiyun
2386*4882a593Smuzhiyun *out_hwirq = hwirq;
2387*4882a593Smuzhiyun
2388*4882a593Smuzhiyun return 0;
2389*4882a593Smuzhiyun }
2390*4882a593Smuzhiyun
octeon_irq_ciu3_enable(struct irq_data * data)2391*4882a593Smuzhiyun void octeon_irq_ciu3_enable(struct irq_data *data)
2392*4882a593Smuzhiyun {
2393*4882a593Smuzhiyun int cpu;
2394*4882a593Smuzhiyun union cvmx_ciu3_iscx_ctl isc_ctl;
2395*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2396*4882a593Smuzhiyun u64 isc_ctl_addr;
2397*4882a593Smuzhiyun
2398*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
2399*4882a593Smuzhiyun
2400*4882a593Smuzhiyun cpu = next_cpu_for_irq(data);
2401*4882a593Smuzhiyun
2402*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
2403*4882a593Smuzhiyun
2404*4882a593Smuzhiyun isc_w1c.u64 = 0;
2405*4882a593Smuzhiyun isc_w1c.s.en = 1;
2406*4882a593Smuzhiyun cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64);
2407*4882a593Smuzhiyun
2408*4882a593Smuzhiyun isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn);
2409*4882a593Smuzhiyun isc_ctl.u64 = 0;
2410*4882a593Smuzhiyun isc_ctl.s.en = 1;
2411*4882a593Smuzhiyun isc_ctl.s.idt = per_cpu(octeon_irq_ciu3_idt_ip2, cpu);
2412*4882a593Smuzhiyun cvmx_write_csr(isc_ctl_addr, isc_ctl.u64);
2413*4882a593Smuzhiyun cvmx_read_csr(isc_ctl_addr);
2414*4882a593Smuzhiyun }
2415*4882a593Smuzhiyun
octeon_irq_ciu3_disable(struct irq_data * data)2416*4882a593Smuzhiyun void octeon_irq_ciu3_disable(struct irq_data *data)
2417*4882a593Smuzhiyun {
2418*4882a593Smuzhiyun u64 isc_ctl_addr;
2419*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2420*4882a593Smuzhiyun
2421*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
2422*4882a593Smuzhiyun
2423*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
2424*4882a593Smuzhiyun
2425*4882a593Smuzhiyun isc_w1c.u64 = 0;
2426*4882a593Smuzhiyun isc_w1c.s.en = 1;
2427*4882a593Smuzhiyun
2428*4882a593Smuzhiyun isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn);
2429*4882a593Smuzhiyun cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64);
2430*4882a593Smuzhiyun cvmx_write_csr(isc_ctl_addr, 0);
2431*4882a593Smuzhiyun cvmx_read_csr(isc_ctl_addr);
2432*4882a593Smuzhiyun }
2433*4882a593Smuzhiyun
octeon_irq_ciu3_ack(struct irq_data * data)2434*4882a593Smuzhiyun void octeon_irq_ciu3_ack(struct irq_data *data)
2435*4882a593Smuzhiyun {
2436*4882a593Smuzhiyun u64 isc_w1c_addr;
2437*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2438*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
2439*4882a593Smuzhiyun u32 trigger_type = irqd_get_trigger_type(data);
2440*4882a593Smuzhiyun
2441*4882a593Smuzhiyun /*
2442*4882a593Smuzhiyun * We use a single irq_chip, so we have to do nothing to ack a
2443*4882a593Smuzhiyun * level interrupt.
2444*4882a593Smuzhiyun */
2445*4882a593Smuzhiyun if (!(trigger_type & IRQ_TYPE_EDGE_BOTH))
2446*4882a593Smuzhiyun return;
2447*4882a593Smuzhiyun
2448*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
2449*4882a593Smuzhiyun
2450*4882a593Smuzhiyun isc_w1c.u64 = 0;
2451*4882a593Smuzhiyun isc_w1c.s.raw = 1;
2452*4882a593Smuzhiyun
2453*4882a593Smuzhiyun isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn);
2454*4882a593Smuzhiyun cvmx_write_csr(isc_w1c_addr, isc_w1c.u64);
2455*4882a593Smuzhiyun cvmx_read_csr(isc_w1c_addr);
2456*4882a593Smuzhiyun }
2457*4882a593Smuzhiyun
octeon_irq_ciu3_mask(struct irq_data * data)2458*4882a593Smuzhiyun void octeon_irq_ciu3_mask(struct irq_data *data)
2459*4882a593Smuzhiyun {
2460*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2461*4882a593Smuzhiyun u64 isc_w1c_addr;
2462*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
2463*4882a593Smuzhiyun
2464*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
2465*4882a593Smuzhiyun
2466*4882a593Smuzhiyun isc_w1c.u64 = 0;
2467*4882a593Smuzhiyun isc_w1c.s.en = 1;
2468*4882a593Smuzhiyun
2469*4882a593Smuzhiyun isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn);
2470*4882a593Smuzhiyun cvmx_write_csr(isc_w1c_addr, isc_w1c.u64);
2471*4882a593Smuzhiyun cvmx_read_csr(isc_w1c_addr);
2472*4882a593Smuzhiyun }
2473*4882a593Smuzhiyun
octeon_irq_ciu3_mask_ack(struct irq_data * data)2474*4882a593Smuzhiyun void octeon_irq_ciu3_mask_ack(struct irq_data *data)
2475*4882a593Smuzhiyun {
2476*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2477*4882a593Smuzhiyun u64 isc_w1c_addr;
2478*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd;
2479*4882a593Smuzhiyun u32 trigger_type = irqd_get_trigger_type(data);
2480*4882a593Smuzhiyun
2481*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
2482*4882a593Smuzhiyun
2483*4882a593Smuzhiyun isc_w1c.u64 = 0;
2484*4882a593Smuzhiyun isc_w1c.s.en = 1;
2485*4882a593Smuzhiyun
2486*4882a593Smuzhiyun /*
2487*4882a593Smuzhiyun * We use a single irq_chip, so only ack an edge (!level)
2488*4882a593Smuzhiyun * interrupt.
2489*4882a593Smuzhiyun */
2490*4882a593Smuzhiyun if (trigger_type & IRQ_TYPE_EDGE_BOTH)
2491*4882a593Smuzhiyun isc_w1c.s.raw = 1;
2492*4882a593Smuzhiyun
2493*4882a593Smuzhiyun isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn);
2494*4882a593Smuzhiyun cvmx_write_csr(isc_w1c_addr, isc_w1c.u64);
2495*4882a593Smuzhiyun cvmx_read_csr(isc_w1c_addr);
2496*4882a593Smuzhiyun }
2497*4882a593Smuzhiyun
2498*4882a593Smuzhiyun #ifdef CONFIG_SMP
octeon_irq_ciu3_set_affinity(struct irq_data * data,const struct cpumask * dest,bool force)2499*4882a593Smuzhiyun static int octeon_irq_ciu3_set_affinity(struct irq_data *data,
2500*4882a593Smuzhiyun const struct cpumask *dest, bool force)
2501*4882a593Smuzhiyun {
2502*4882a593Smuzhiyun union cvmx_ciu3_iscx_ctl isc_ctl;
2503*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2504*4882a593Smuzhiyun u64 isc_ctl_addr;
2505*4882a593Smuzhiyun int cpu;
2506*4882a593Smuzhiyun bool enable_one = !irqd_irq_disabled(data) && !irqd_irq_masked(data);
2507*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data);
2508*4882a593Smuzhiyun
2509*4882a593Smuzhiyun if (!cpumask_subset(dest, cpumask_of_node(cd->ciu_node)))
2510*4882a593Smuzhiyun return -EINVAL;
2511*4882a593Smuzhiyun
2512*4882a593Smuzhiyun if (!enable_one)
2513*4882a593Smuzhiyun return IRQ_SET_MASK_OK;
2514*4882a593Smuzhiyun
2515*4882a593Smuzhiyun cd = irq_data_get_irq_chip_data(data);
2516*4882a593Smuzhiyun cpu = cpumask_first(dest);
2517*4882a593Smuzhiyun if (cpu >= nr_cpu_ids)
2518*4882a593Smuzhiyun cpu = smp_processor_id();
2519*4882a593Smuzhiyun cd->current_cpu = cpu;
2520*4882a593Smuzhiyun
2521*4882a593Smuzhiyun isc_w1c.u64 = 0;
2522*4882a593Smuzhiyun isc_w1c.s.en = 1;
2523*4882a593Smuzhiyun cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64);
2524*4882a593Smuzhiyun
2525*4882a593Smuzhiyun isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn);
2526*4882a593Smuzhiyun isc_ctl.u64 = 0;
2527*4882a593Smuzhiyun isc_ctl.s.en = 1;
2528*4882a593Smuzhiyun isc_ctl.s.idt = per_cpu(octeon_irq_ciu3_idt_ip2, cpu);
2529*4882a593Smuzhiyun cvmx_write_csr(isc_ctl_addr, isc_ctl.u64);
2530*4882a593Smuzhiyun cvmx_read_csr(isc_ctl_addr);
2531*4882a593Smuzhiyun
2532*4882a593Smuzhiyun return IRQ_SET_MASK_OK;
2533*4882a593Smuzhiyun }
2534*4882a593Smuzhiyun #endif
2535*4882a593Smuzhiyun
2536*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu3 = {
2537*4882a593Smuzhiyun .name = "CIU3",
2538*4882a593Smuzhiyun .irq_startup = edge_startup,
2539*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu3_enable,
2540*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu3_disable,
2541*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu3_ack,
2542*4882a593Smuzhiyun .irq_mask = octeon_irq_ciu3_mask,
2543*4882a593Smuzhiyun .irq_mask_ack = octeon_irq_ciu3_mask_ack,
2544*4882a593Smuzhiyun .irq_unmask = octeon_irq_ciu3_enable,
2545*4882a593Smuzhiyun .irq_set_type = octeon_irq_ciu_set_type,
2546*4882a593Smuzhiyun #ifdef CONFIG_SMP
2547*4882a593Smuzhiyun .irq_set_affinity = octeon_irq_ciu3_set_affinity,
2548*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
2549*4882a593Smuzhiyun #endif
2550*4882a593Smuzhiyun };
2551*4882a593Smuzhiyun
octeon_irq_ciu3_mapx(struct irq_domain * d,unsigned int virq,irq_hw_number_t hw,struct irq_chip * chip)2552*4882a593Smuzhiyun int octeon_irq_ciu3_mapx(struct irq_domain *d, unsigned int virq,
2553*4882a593Smuzhiyun irq_hw_number_t hw, struct irq_chip *chip)
2554*4882a593Smuzhiyun {
2555*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info = d->host_data;
2556*4882a593Smuzhiyun struct octeon_ciu_chip_data *cd = kzalloc_node(sizeof(*cd), GFP_KERNEL,
2557*4882a593Smuzhiyun ciu3_info->node);
2558*4882a593Smuzhiyun if (!cd)
2559*4882a593Smuzhiyun return -ENOMEM;
2560*4882a593Smuzhiyun cd->intsn = hw;
2561*4882a593Smuzhiyun cd->current_cpu = -1;
2562*4882a593Smuzhiyun cd->ciu3_addr = ciu3_info->ciu3_addr;
2563*4882a593Smuzhiyun cd->ciu_node = ciu3_info->node;
2564*4882a593Smuzhiyun irq_set_chip_and_handler(virq, chip, handle_edge_irq);
2565*4882a593Smuzhiyun irq_set_chip_data(virq, cd);
2566*4882a593Smuzhiyun
2567*4882a593Smuzhiyun return 0;
2568*4882a593Smuzhiyun }
2569*4882a593Smuzhiyun
octeon_irq_ciu3_map(struct irq_domain * d,unsigned int virq,irq_hw_number_t hw)2570*4882a593Smuzhiyun static int octeon_irq_ciu3_map(struct irq_domain *d,
2571*4882a593Smuzhiyun unsigned int virq, irq_hw_number_t hw)
2572*4882a593Smuzhiyun {
2573*4882a593Smuzhiyun return octeon_irq_ciu3_mapx(d, virq, hw, &octeon_irq_chip_ciu3);
2574*4882a593Smuzhiyun }
2575*4882a593Smuzhiyun
2576*4882a593Smuzhiyun static struct irq_domain_ops octeon_dflt_domain_ciu3_ops = {
2577*4882a593Smuzhiyun .map = octeon_irq_ciu3_map,
2578*4882a593Smuzhiyun .unmap = octeon_irq_free_cd,
2579*4882a593Smuzhiyun .xlate = octeon_irq_ciu3_xlat,
2580*4882a593Smuzhiyun };
2581*4882a593Smuzhiyun
octeon_irq_ciu3_ip2(void)2582*4882a593Smuzhiyun static void octeon_irq_ciu3_ip2(void)
2583*4882a593Smuzhiyun {
2584*4882a593Smuzhiyun union cvmx_ciu3_destx_pp_int dest_pp_int;
2585*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2586*4882a593Smuzhiyun u64 ciu3_addr;
2587*4882a593Smuzhiyun
2588*4882a593Smuzhiyun ciu3_info = __this_cpu_read(octeon_ciu3_info);
2589*4882a593Smuzhiyun ciu3_addr = ciu3_info->ciu3_addr;
2590*4882a593Smuzhiyun
2591*4882a593Smuzhiyun dest_pp_int.u64 = cvmx_read_csr(ciu3_addr + CIU3_DEST_PP_INT(3 * cvmx_get_local_core_num()));
2592*4882a593Smuzhiyun
2593*4882a593Smuzhiyun if (likely(dest_pp_int.s.intr)) {
2594*4882a593Smuzhiyun irq_hw_number_t intsn = dest_pp_int.s.intsn;
2595*4882a593Smuzhiyun irq_hw_number_t hw;
2596*4882a593Smuzhiyun struct irq_domain *domain;
2597*4882a593Smuzhiyun /* Get the domain to use from the major block */
2598*4882a593Smuzhiyun int block = intsn >> 12;
2599*4882a593Smuzhiyun int ret;
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun domain = ciu3_info->domain[block];
2602*4882a593Smuzhiyun if (ciu3_info->intsn2hw[block])
2603*4882a593Smuzhiyun hw = ciu3_info->intsn2hw[block](domain, intsn);
2604*4882a593Smuzhiyun else
2605*4882a593Smuzhiyun hw = intsn;
2606*4882a593Smuzhiyun
2607*4882a593Smuzhiyun ret = handle_domain_irq(domain, hw, NULL);
2608*4882a593Smuzhiyun if (ret < 0) {
2609*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2610*4882a593Smuzhiyun u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn);
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun isc_w1c.u64 = 0;
2613*4882a593Smuzhiyun isc_w1c.s.en = 1;
2614*4882a593Smuzhiyun cvmx_write_csr(isc_w1c_addr, isc_w1c.u64);
2615*4882a593Smuzhiyun cvmx_read_csr(isc_w1c_addr);
2616*4882a593Smuzhiyun spurious_interrupt();
2617*4882a593Smuzhiyun }
2618*4882a593Smuzhiyun } else {
2619*4882a593Smuzhiyun spurious_interrupt();
2620*4882a593Smuzhiyun }
2621*4882a593Smuzhiyun }
2622*4882a593Smuzhiyun
2623*4882a593Smuzhiyun /*
2624*4882a593Smuzhiyun * 10 mbox per core starting from zero.
2625*4882a593Smuzhiyun * Base mbox is core * 10
2626*4882a593Smuzhiyun */
octeon_irq_ciu3_base_mbox_intsn(int core)2627*4882a593Smuzhiyun static unsigned int octeon_irq_ciu3_base_mbox_intsn(int core)
2628*4882a593Smuzhiyun {
2629*4882a593Smuzhiyun /* SW (mbox) are 0x04 in bits 12..19 */
2630*4882a593Smuzhiyun return 0x04000 + CIU3_MBOX_PER_CORE * core;
2631*4882a593Smuzhiyun }
2632*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_intsn_for_core(int core,unsigned int mbox)2633*4882a593Smuzhiyun static unsigned int octeon_irq_ciu3_mbox_intsn_for_core(int core, unsigned int mbox)
2634*4882a593Smuzhiyun {
2635*4882a593Smuzhiyun return octeon_irq_ciu3_base_mbox_intsn(core) + mbox;
2636*4882a593Smuzhiyun }
2637*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_intsn_for_cpu(int cpu,unsigned int mbox)2638*4882a593Smuzhiyun static unsigned int octeon_irq_ciu3_mbox_intsn_for_cpu(int cpu, unsigned int mbox)
2639*4882a593Smuzhiyun {
2640*4882a593Smuzhiyun int local_core = octeon_coreid_for_cpu(cpu) & 0x3f;
2641*4882a593Smuzhiyun
2642*4882a593Smuzhiyun return octeon_irq_ciu3_mbox_intsn_for_core(local_core, mbox);
2643*4882a593Smuzhiyun }
2644*4882a593Smuzhiyun
octeon_irq_ciu3_mbox(void)2645*4882a593Smuzhiyun static void octeon_irq_ciu3_mbox(void)
2646*4882a593Smuzhiyun {
2647*4882a593Smuzhiyun union cvmx_ciu3_destx_pp_int dest_pp_int;
2648*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2649*4882a593Smuzhiyun u64 ciu3_addr;
2650*4882a593Smuzhiyun int core = cvmx_get_local_core_num();
2651*4882a593Smuzhiyun
2652*4882a593Smuzhiyun ciu3_info = __this_cpu_read(octeon_ciu3_info);
2653*4882a593Smuzhiyun ciu3_addr = ciu3_info->ciu3_addr;
2654*4882a593Smuzhiyun
2655*4882a593Smuzhiyun dest_pp_int.u64 = cvmx_read_csr(ciu3_addr + CIU3_DEST_PP_INT(1 + 3 * core));
2656*4882a593Smuzhiyun
2657*4882a593Smuzhiyun if (likely(dest_pp_int.s.intr)) {
2658*4882a593Smuzhiyun irq_hw_number_t intsn = dest_pp_int.s.intsn;
2659*4882a593Smuzhiyun int mbox = intsn - octeon_irq_ciu3_base_mbox_intsn(core);
2660*4882a593Smuzhiyun
2661*4882a593Smuzhiyun if (likely(mbox >= 0 && mbox < CIU3_MBOX_PER_CORE)) {
2662*4882a593Smuzhiyun do_IRQ(mbox + OCTEON_IRQ_MBOX0);
2663*4882a593Smuzhiyun } else {
2664*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2665*4882a593Smuzhiyun u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn);
2666*4882a593Smuzhiyun
2667*4882a593Smuzhiyun isc_w1c.u64 = 0;
2668*4882a593Smuzhiyun isc_w1c.s.en = 1;
2669*4882a593Smuzhiyun cvmx_write_csr(isc_w1c_addr, isc_w1c.u64);
2670*4882a593Smuzhiyun cvmx_read_csr(isc_w1c_addr);
2671*4882a593Smuzhiyun spurious_interrupt();
2672*4882a593Smuzhiyun }
2673*4882a593Smuzhiyun } else {
2674*4882a593Smuzhiyun spurious_interrupt();
2675*4882a593Smuzhiyun }
2676*4882a593Smuzhiyun }
2677*4882a593Smuzhiyun
octeon_ciu3_mbox_send(int cpu,unsigned int mbox)2678*4882a593Smuzhiyun void octeon_ciu3_mbox_send(int cpu, unsigned int mbox)
2679*4882a593Smuzhiyun {
2680*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2681*4882a593Smuzhiyun unsigned int intsn;
2682*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1s isc_w1s;
2683*4882a593Smuzhiyun u64 isc_w1s_addr;
2684*4882a593Smuzhiyun
2685*4882a593Smuzhiyun if (WARN_ON_ONCE(mbox >= CIU3_MBOX_PER_CORE))
2686*4882a593Smuzhiyun return;
2687*4882a593Smuzhiyun
2688*4882a593Smuzhiyun intsn = octeon_irq_ciu3_mbox_intsn_for_cpu(cpu, mbox);
2689*4882a593Smuzhiyun ciu3_info = per_cpu(octeon_ciu3_info, cpu);
2690*4882a593Smuzhiyun isc_w1s_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1S(intsn);
2691*4882a593Smuzhiyun
2692*4882a593Smuzhiyun isc_w1s.u64 = 0;
2693*4882a593Smuzhiyun isc_w1s.s.raw = 1;
2694*4882a593Smuzhiyun
2695*4882a593Smuzhiyun cvmx_write_csr(isc_w1s_addr, isc_w1s.u64);
2696*4882a593Smuzhiyun cvmx_read_csr(isc_w1s_addr);
2697*4882a593Smuzhiyun }
2698*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_set_enable(struct irq_data * data,int cpu,bool en)2699*4882a593Smuzhiyun static void octeon_irq_ciu3_mbox_set_enable(struct irq_data *data, int cpu, bool en)
2700*4882a593Smuzhiyun {
2701*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2702*4882a593Smuzhiyun unsigned int intsn;
2703*4882a593Smuzhiyun u64 isc_ctl_addr, isc_w1c_addr;
2704*4882a593Smuzhiyun union cvmx_ciu3_iscx_ctl isc_ctl;
2705*4882a593Smuzhiyun unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0;
2706*4882a593Smuzhiyun
2707*4882a593Smuzhiyun intsn = octeon_irq_ciu3_mbox_intsn_for_cpu(cpu, mbox);
2708*4882a593Smuzhiyun ciu3_info = per_cpu(octeon_ciu3_info, cpu);
2709*4882a593Smuzhiyun isc_w1c_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1C(intsn);
2710*4882a593Smuzhiyun isc_ctl_addr = ciu3_info->ciu3_addr + CIU3_ISC_CTL(intsn);
2711*4882a593Smuzhiyun
2712*4882a593Smuzhiyun isc_ctl.u64 = 0;
2713*4882a593Smuzhiyun isc_ctl.s.en = 1;
2714*4882a593Smuzhiyun
2715*4882a593Smuzhiyun cvmx_write_csr(isc_w1c_addr, isc_ctl.u64);
2716*4882a593Smuzhiyun cvmx_write_csr(isc_ctl_addr, 0);
2717*4882a593Smuzhiyun if (en) {
2718*4882a593Smuzhiyun unsigned int idt = per_cpu(octeon_irq_ciu3_idt_ip3, cpu);
2719*4882a593Smuzhiyun
2720*4882a593Smuzhiyun isc_ctl.u64 = 0;
2721*4882a593Smuzhiyun isc_ctl.s.en = 1;
2722*4882a593Smuzhiyun isc_ctl.s.idt = idt;
2723*4882a593Smuzhiyun cvmx_write_csr(isc_ctl_addr, isc_ctl.u64);
2724*4882a593Smuzhiyun }
2725*4882a593Smuzhiyun cvmx_read_csr(isc_ctl_addr);
2726*4882a593Smuzhiyun }
2727*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_enable(struct irq_data * data)2728*4882a593Smuzhiyun static void octeon_irq_ciu3_mbox_enable(struct irq_data *data)
2729*4882a593Smuzhiyun {
2730*4882a593Smuzhiyun int cpu;
2731*4882a593Smuzhiyun unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0;
2732*4882a593Smuzhiyun
2733*4882a593Smuzhiyun WARN_ON(mbox >= CIU3_MBOX_PER_CORE);
2734*4882a593Smuzhiyun
2735*4882a593Smuzhiyun for_each_online_cpu(cpu)
2736*4882a593Smuzhiyun octeon_irq_ciu3_mbox_set_enable(data, cpu, true);
2737*4882a593Smuzhiyun }
2738*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_disable(struct irq_data * data)2739*4882a593Smuzhiyun static void octeon_irq_ciu3_mbox_disable(struct irq_data *data)
2740*4882a593Smuzhiyun {
2741*4882a593Smuzhiyun int cpu;
2742*4882a593Smuzhiyun unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0;
2743*4882a593Smuzhiyun
2744*4882a593Smuzhiyun WARN_ON(mbox >= CIU3_MBOX_PER_CORE);
2745*4882a593Smuzhiyun
2746*4882a593Smuzhiyun for_each_online_cpu(cpu)
2747*4882a593Smuzhiyun octeon_irq_ciu3_mbox_set_enable(data, cpu, false);
2748*4882a593Smuzhiyun }
2749*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_ack(struct irq_data * data)2750*4882a593Smuzhiyun static void octeon_irq_ciu3_mbox_ack(struct irq_data *data)
2751*4882a593Smuzhiyun {
2752*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2753*4882a593Smuzhiyun unsigned int intsn;
2754*4882a593Smuzhiyun u64 isc_w1c_addr;
2755*4882a593Smuzhiyun union cvmx_ciu3_iscx_w1c isc_w1c;
2756*4882a593Smuzhiyun unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0;
2757*4882a593Smuzhiyun
2758*4882a593Smuzhiyun intsn = octeon_irq_ciu3_mbox_intsn_for_core(cvmx_get_local_core_num(), mbox);
2759*4882a593Smuzhiyun
2760*4882a593Smuzhiyun isc_w1c.u64 = 0;
2761*4882a593Smuzhiyun isc_w1c.s.raw = 1;
2762*4882a593Smuzhiyun
2763*4882a593Smuzhiyun ciu3_info = __this_cpu_read(octeon_ciu3_info);
2764*4882a593Smuzhiyun isc_w1c_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1C(intsn);
2765*4882a593Smuzhiyun cvmx_write_csr(isc_w1c_addr, isc_w1c.u64);
2766*4882a593Smuzhiyun cvmx_read_csr(isc_w1c_addr);
2767*4882a593Smuzhiyun }
2768*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_cpu_online(struct irq_data * data)2769*4882a593Smuzhiyun static void octeon_irq_ciu3_mbox_cpu_online(struct irq_data *data)
2770*4882a593Smuzhiyun {
2771*4882a593Smuzhiyun octeon_irq_ciu3_mbox_set_enable(data, smp_processor_id(), true);
2772*4882a593Smuzhiyun }
2773*4882a593Smuzhiyun
octeon_irq_ciu3_mbox_cpu_offline(struct irq_data * data)2774*4882a593Smuzhiyun static void octeon_irq_ciu3_mbox_cpu_offline(struct irq_data *data)
2775*4882a593Smuzhiyun {
2776*4882a593Smuzhiyun octeon_irq_ciu3_mbox_set_enable(data, smp_processor_id(), false);
2777*4882a593Smuzhiyun }
2778*4882a593Smuzhiyun
octeon_irq_ciu3_alloc_resources(struct octeon_ciu3_info * ciu3_info)2779*4882a593Smuzhiyun static int octeon_irq_ciu3_alloc_resources(struct octeon_ciu3_info *ciu3_info)
2780*4882a593Smuzhiyun {
2781*4882a593Smuzhiyun u64 b = ciu3_info->ciu3_addr;
2782*4882a593Smuzhiyun int idt_ip2, idt_ip3, idt_ip4;
2783*4882a593Smuzhiyun int unused_idt2;
2784*4882a593Smuzhiyun int core = cvmx_get_local_core_num();
2785*4882a593Smuzhiyun int i;
2786*4882a593Smuzhiyun
2787*4882a593Smuzhiyun __this_cpu_write(octeon_ciu3_info, ciu3_info);
2788*4882a593Smuzhiyun
2789*4882a593Smuzhiyun /*
2790*4882a593Smuzhiyun * 4 idt per core starting from 1 because zero is reserved.
2791*4882a593Smuzhiyun * Base idt per core is 4 * core + 1
2792*4882a593Smuzhiyun */
2793*4882a593Smuzhiyun idt_ip2 = core * 4 + 1;
2794*4882a593Smuzhiyun idt_ip3 = core * 4 + 2;
2795*4882a593Smuzhiyun idt_ip4 = core * 4 + 3;
2796*4882a593Smuzhiyun unused_idt2 = core * 4 + 4;
2797*4882a593Smuzhiyun __this_cpu_write(octeon_irq_ciu3_idt_ip2, idt_ip2);
2798*4882a593Smuzhiyun __this_cpu_write(octeon_irq_ciu3_idt_ip3, idt_ip3);
2799*4882a593Smuzhiyun
2800*4882a593Smuzhiyun /* ip2 interrupts for this CPU */
2801*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip2), 0);
2802*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_PP(idt_ip2, 0), 1ull << core);
2803*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_IO(idt_ip2), 0);
2804*4882a593Smuzhiyun
2805*4882a593Smuzhiyun /* ip3 interrupts for this CPU */
2806*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip3), 1);
2807*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_PP(idt_ip3, 0), 1ull << core);
2808*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_IO(idt_ip3), 0);
2809*4882a593Smuzhiyun
2810*4882a593Smuzhiyun /* ip4 interrupts for this CPU */
2811*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip4), 2);
2812*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_PP(idt_ip4, 0), 0);
2813*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_IO(idt_ip4), 0);
2814*4882a593Smuzhiyun
2815*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_CTL(unused_idt2), 0);
2816*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_PP(unused_idt2, 0), 0);
2817*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_IDT_IO(unused_idt2), 0);
2818*4882a593Smuzhiyun
2819*4882a593Smuzhiyun for (i = 0; i < CIU3_MBOX_PER_CORE; i++) {
2820*4882a593Smuzhiyun unsigned int intsn = octeon_irq_ciu3_mbox_intsn_for_core(core, i);
2821*4882a593Smuzhiyun
2822*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_ISC_W1C(intsn), 2);
2823*4882a593Smuzhiyun cvmx_write_csr(b + CIU3_ISC_CTL(intsn), 0);
2824*4882a593Smuzhiyun }
2825*4882a593Smuzhiyun
2826*4882a593Smuzhiyun return 0;
2827*4882a593Smuzhiyun }
2828*4882a593Smuzhiyun
octeon_irq_setup_secondary_ciu3(void)2829*4882a593Smuzhiyun static void octeon_irq_setup_secondary_ciu3(void)
2830*4882a593Smuzhiyun {
2831*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2832*4882a593Smuzhiyun
2833*4882a593Smuzhiyun ciu3_info = octeon_ciu3_info_per_node[cvmx_get_node_num()];
2834*4882a593Smuzhiyun octeon_irq_ciu3_alloc_resources(ciu3_info);
2835*4882a593Smuzhiyun irq_cpu_online();
2836*4882a593Smuzhiyun
2837*4882a593Smuzhiyun /* Enable the CIU lines */
2838*4882a593Smuzhiyun set_c0_status(STATUSF_IP3 | STATUSF_IP2);
2839*4882a593Smuzhiyun if (octeon_irq_use_ip4)
2840*4882a593Smuzhiyun set_c0_status(STATUSF_IP4);
2841*4882a593Smuzhiyun else
2842*4882a593Smuzhiyun clear_c0_status(STATUSF_IP4);
2843*4882a593Smuzhiyun }
2844*4882a593Smuzhiyun
2845*4882a593Smuzhiyun static struct irq_chip octeon_irq_chip_ciu3_mbox = {
2846*4882a593Smuzhiyun .name = "CIU3-M",
2847*4882a593Smuzhiyun .irq_enable = octeon_irq_ciu3_mbox_enable,
2848*4882a593Smuzhiyun .irq_disable = octeon_irq_ciu3_mbox_disable,
2849*4882a593Smuzhiyun .irq_ack = octeon_irq_ciu3_mbox_ack,
2850*4882a593Smuzhiyun
2851*4882a593Smuzhiyun .irq_cpu_online = octeon_irq_ciu3_mbox_cpu_online,
2852*4882a593Smuzhiyun .irq_cpu_offline = octeon_irq_ciu3_mbox_cpu_offline,
2853*4882a593Smuzhiyun .flags = IRQCHIP_ONOFFLINE_ENABLED,
2854*4882a593Smuzhiyun };
2855*4882a593Smuzhiyun
octeon_irq_init_ciu3(struct device_node * ciu_node,struct device_node * parent)2856*4882a593Smuzhiyun static int __init octeon_irq_init_ciu3(struct device_node *ciu_node,
2857*4882a593Smuzhiyun struct device_node *parent)
2858*4882a593Smuzhiyun {
2859*4882a593Smuzhiyun int i;
2860*4882a593Smuzhiyun int node;
2861*4882a593Smuzhiyun struct irq_domain *domain;
2862*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2863*4882a593Smuzhiyun const __be32 *zero_addr;
2864*4882a593Smuzhiyun u64 base_addr;
2865*4882a593Smuzhiyun union cvmx_ciu3_const consts;
2866*4882a593Smuzhiyun
2867*4882a593Smuzhiyun node = 0; /* of_node_to_nid(ciu_node); */
2868*4882a593Smuzhiyun ciu3_info = kzalloc_node(sizeof(*ciu3_info), GFP_KERNEL, node);
2869*4882a593Smuzhiyun
2870*4882a593Smuzhiyun if (!ciu3_info)
2871*4882a593Smuzhiyun return -ENOMEM;
2872*4882a593Smuzhiyun
2873*4882a593Smuzhiyun zero_addr = of_get_address(ciu_node, 0, NULL, NULL);
2874*4882a593Smuzhiyun if (WARN_ON(!zero_addr))
2875*4882a593Smuzhiyun return -EINVAL;
2876*4882a593Smuzhiyun
2877*4882a593Smuzhiyun base_addr = of_translate_address(ciu_node, zero_addr);
2878*4882a593Smuzhiyun base_addr = (u64)phys_to_virt(base_addr);
2879*4882a593Smuzhiyun
2880*4882a593Smuzhiyun ciu3_info->ciu3_addr = base_addr;
2881*4882a593Smuzhiyun ciu3_info->node = node;
2882*4882a593Smuzhiyun
2883*4882a593Smuzhiyun consts.u64 = cvmx_read_csr(base_addr + CIU3_CONST);
2884*4882a593Smuzhiyun
2885*4882a593Smuzhiyun octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu3;
2886*4882a593Smuzhiyun
2887*4882a593Smuzhiyun octeon_irq_ip2 = octeon_irq_ciu3_ip2;
2888*4882a593Smuzhiyun octeon_irq_ip3 = octeon_irq_ciu3_mbox;
2889*4882a593Smuzhiyun octeon_irq_ip4 = octeon_irq_ip4_mask;
2890*4882a593Smuzhiyun
2891*4882a593Smuzhiyun if (node == cvmx_get_node_num()) {
2892*4882a593Smuzhiyun /* Mips internal */
2893*4882a593Smuzhiyun octeon_irq_init_core();
2894*4882a593Smuzhiyun
2895*4882a593Smuzhiyun /* Only do per CPU things if it is the CIU of the boot node. */
2896*4882a593Smuzhiyun i = irq_alloc_descs_from(OCTEON_IRQ_MBOX0, 8, node);
2897*4882a593Smuzhiyun WARN_ON(i < 0);
2898*4882a593Smuzhiyun
2899*4882a593Smuzhiyun for (i = 0; i < 8; i++)
2900*4882a593Smuzhiyun irq_set_chip_and_handler(i + OCTEON_IRQ_MBOX0,
2901*4882a593Smuzhiyun &octeon_irq_chip_ciu3_mbox, handle_percpu_irq);
2902*4882a593Smuzhiyun }
2903*4882a593Smuzhiyun
2904*4882a593Smuzhiyun /*
2905*4882a593Smuzhiyun * Initialize all domains to use the default domain. Specific major
2906*4882a593Smuzhiyun * blocks will overwrite the default domain as needed.
2907*4882a593Smuzhiyun */
2908*4882a593Smuzhiyun domain = irq_domain_add_tree(ciu_node, &octeon_dflt_domain_ciu3_ops,
2909*4882a593Smuzhiyun ciu3_info);
2910*4882a593Smuzhiyun for (i = 0; i < MAX_CIU3_DOMAINS; i++)
2911*4882a593Smuzhiyun ciu3_info->domain[i] = domain;
2912*4882a593Smuzhiyun
2913*4882a593Smuzhiyun octeon_ciu3_info_per_node[node] = ciu3_info;
2914*4882a593Smuzhiyun
2915*4882a593Smuzhiyun if (node == cvmx_get_node_num()) {
2916*4882a593Smuzhiyun /* Only do per CPU things if it is the CIU of the boot node. */
2917*4882a593Smuzhiyun octeon_irq_ciu3_alloc_resources(ciu3_info);
2918*4882a593Smuzhiyun if (node == 0)
2919*4882a593Smuzhiyun irq_set_default_host(domain);
2920*4882a593Smuzhiyun
2921*4882a593Smuzhiyun octeon_irq_use_ip4 = false;
2922*4882a593Smuzhiyun /* Enable the CIU lines */
2923*4882a593Smuzhiyun set_c0_status(STATUSF_IP2 | STATUSF_IP3);
2924*4882a593Smuzhiyun clear_c0_status(STATUSF_IP4);
2925*4882a593Smuzhiyun }
2926*4882a593Smuzhiyun
2927*4882a593Smuzhiyun return 0;
2928*4882a593Smuzhiyun }
2929*4882a593Smuzhiyun
2930*4882a593Smuzhiyun static struct of_device_id ciu_types[] __initdata = {
2931*4882a593Smuzhiyun {.compatible = "cavium,octeon-3860-ciu", .data = octeon_irq_init_ciu},
2932*4882a593Smuzhiyun {.compatible = "cavium,octeon-3860-gpio", .data = octeon_irq_init_gpio},
2933*4882a593Smuzhiyun {.compatible = "cavium,octeon-6880-ciu2", .data = octeon_irq_init_ciu2},
2934*4882a593Smuzhiyun {.compatible = "cavium,octeon-7890-ciu3", .data = octeon_irq_init_ciu3},
2935*4882a593Smuzhiyun {.compatible = "cavium,octeon-7130-cib", .data = octeon_irq_init_cib},
2936*4882a593Smuzhiyun {}
2937*4882a593Smuzhiyun };
2938*4882a593Smuzhiyun
arch_init_irq(void)2939*4882a593Smuzhiyun void __init arch_init_irq(void)
2940*4882a593Smuzhiyun {
2941*4882a593Smuzhiyun #ifdef CONFIG_SMP
2942*4882a593Smuzhiyun /* Set the default affinity to the boot cpu. */
2943*4882a593Smuzhiyun cpumask_clear(irq_default_affinity);
2944*4882a593Smuzhiyun cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
2945*4882a593Smuzhiyun #endif
2946*4882a593Smuzhiyun of_irq_init(ciu_types);
2947*4882a593Smuzhiyun }
2948*4882a593Smuzhiyun
plat_irq_dispatch(void)2949*4882a593Smuzhiyun asmlinkage void plat_irq_dispatch(void)
2950*4882a593Smuzhiyun {
2951*4882a593Smuzhiyun unsigned long cop0_cause;
2952*4882a593Smuzhiyun unsigned long cop0_status;
2953*4882a593Smuzhiyun
2954*4882a593Smuzhiyun while (1) {
2955*4882a593Smuzhiyun cop0_cause = read_c0_cause();
2956*4882a593Smuzhiyun cop0_status = read_c0_status();
2957*4882a593Smuzhiyun cop0_cause &= cop0_status;
2958*4882a593Smuzhiyun cop0_cause &= ST0_IM;
2959*4882a593Smuzhiyun
2960*4882a593Smuzhiyun if (cop0_cause & STATUSF_IP2)
2961*4882a593Smuzhiyun octeon_irq_ip2();
2962*4882a593Smuzhiyun else if (cop0_cause & STATUSF_IP3)
2963*4882a593Smuzhiyun octeon_irq_ip3();
2964*4882a593Smuzhiyun else if (cop0_cause & STATUSF_IP4)
2965*4882a593Smuzhiyun octeon_irq_ip4();
2966*4882a593Smuzhiyun else if (cop0_cause)
2967*4882a593Smuzhiyun do_IRQ(fls(cop0_cause) - 9 + MIPS_CPU_IRQ_BASE);
2968*4882a593Smuzhiyun else
2969*4882a593Smuzhiyun break;
2970*4882a593Smuzhiyun }
2971*4882a593Smuzhiyun }
2972*4882a593Smuzhiyun
2973*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
2974*4882a593Smuzhiyun
octeon_fixup_irqs(void)2975*4882a593Smuzhiyun void octeon_fixup_irqs(void)
2976*4882a593Smuzhiyun {
2977*4882a593Smuzhiyun irq_cpu_offline();
2978*4882a593Smuzhiyun }
2979*4882a593Smuzhiyun
2980*4882a593Smuzhiyun #endif /* CONFIG_HOTPLUG_CPU */
2981*4882a593Smuzhiyun
octeon_irq_get_block_domain(int node,uint8_t block)2982*4882a593Smuzhiyun struct irq_domain *octeon_irq_get_block_domain(int node, uint8_t block)
2983*4882a593Smuzhiyun {
2984*4882a593Smuzhiyun struct octeon_ciu3_info *ciu3_info;
2985*4882a593Smuzhiyun
2986*4882a593Smuzhiyun ciu3_info = octeon_ciu3_info_per_node[node & CVMX_NODE_MASK];
2987*4882a593Smuzhiyun return ciu3_info->domain[block];
2988*4882a593Smuzhiyun }
2989*4882a593Smuzhiyun EXPORT_SYMBOL(octeon_irq_get_block_domain);
2990