2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
8 #include <linux/init.h>
13 #include <asm/irq_cpu.h>
14 #include <asm/setup.h>
16 #include <asm/mips-boards/sead3int.h>
18 #define SEAD_CONFIG_GIC_PRESENT_SHF 1
19 #define SEAD_CONFIG_GIC_PRESENT_MSK (1 << SEAD_CONFIG_GIC_PRESENT_SHF)
20 #define SEAD_CONFIG_BASE 0x1b100110
21 #define SEAD_CONFIG_SIZE 4
24 static unsigned long sead3_config_reg
;
27 * This table defines the setup for each external GIC interrupt. It is
28 * indexed by interrupt number.
30 #define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
31 static struct gic_intr_map gic_intr_map
[GIC_NUM_INTRS
] = {
32 { 0, GIC_CPU_INT4
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
33 { 0, GIC_CPU_INT3
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
34 { 0, GIC_CPU_INT2
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
35 { 0, GIC_CPU_INT2
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
36 { 0, GIC_CPU_INT1
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
37 { 0, GIC_CPU_INT0
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
38 { 0, GIC_CPU_INT0
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
39 { 0, GIC_CPU_INT0
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
40 { 0, GIC_CPU_INT0
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
41 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
42 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
43 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
44 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
45 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
46 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
47 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
50 asmlinkage
void plat_irq_dispatch(void)
52 unsigned int pending
= read_c0_cause() & read_c0_status() & ST0_IM
;
55 irq
= (fls(pending
) - CAUSEB_IP
- 1);
57 do_IRQ(MIPS_CPU_IRQ_BASE
+ irq
);
62 void __init
arch_init_irq(void)
70 /* install generic handler */
71 for (i
= 0; i
< 8; i
++)
72 set_vi_handler(i
, plat_irq_dispatch
);
76 sead3_config_reg
= (unsigned long)ioremap_nocache(SEAD_CONFIG_BASE
,
78 gic_present
= (REG32(sead3_config_reg
) & SEAD_CONFIG_GIC_PRESENT_MSK
) >>
79 SEAD_CONFIG_GIC_PRESENT_SHF
;
80 pr_info("GIC: %spresent\n", (gic_present
) ? "" : "not ");
82 (current_cpu_data
.options
& MIPS_CPU_VEIC
) ? "on" : "off");
85 gic_init(GIC_BASE_ADDR
, GIC_ADDRSPACE_SZ
, gic_intr_map
,
86 ARRAY_SIZE(gic_intr_map
), MIPS_GIC_IRQ_BASE
);
89 void gic_enable_interrupt(int irq_vec
)
91 unsigned int i
, irq_source
;
93 /* enable all the interrupts associated with this vector */
94 for (i
= 0; i
< gic_shared_intr_map
[irq_vec
].num_shared_intr
; i
++) {
95 irq_source
= gic_shared_intr_map
[irq_vec
].intr_list
[i
];
96 GIC_SET_INTR_MASK(irq_source
);
98 /* enable all local interrupts associated with this vector */
99 if (gic_shared_intr_map
[irq_vec
].local_intr_mask
) {
100 GICWRITE(GIC_REG(VPE_LOCAL
, GIC_VPE_OTHER_ADDR
), 0);
101 GICWRITE(GIC_REG(VPE_OTHER
, GIC_VPE_SMASK
),
102 gic_shared_intr_map
[irq_vec
].local_intr_mask
);
106 void gic_disable_interrupt(int irq_vec
)
108 unsigned int i
, irq_source
;
110 /* disable all the interrupts associated with this vector */
111 for (i
= 0; i
< gic_shared_intr_map
[irq_vec
].num_shared_intr
; i
++) {
112 irq_source
= gic_shared_intr_map
[irq_vec
].intr_list
[i
];
113 GIC_CLR_INTR_MASK(irq_source
);
115 /* disable all local interrupts associated with this vector */
116 if (gic_shared_intr_map
[irq_vec
].local_intr_mask
) {
117 GICWRITE(GIC_REG(VPE_LOCAL
, GIC_VPE_OTHER_ADDR
), 0);
118 GICWRITE(GIC_REG(VPE_OTHER
, GIC_VPE_RMASK
),
119 gic_shared_intr_map
[irq_vec
].local_intr_mask
);
123 void gic_irq_ack(struct irq_data
*d
)
125 GIC_CLR_INTR_MASK(d
->irq
- gic_irq_base
);
128 void gic_finish_irq(struct irq_data
*d
)
130 unsigned int irq
= (d
->irq
- gic_irq_base
);
131 unsigned int i
, irq_source
;
133 /* Clear edge detectors. */
134 for (i
= 0; i
< gic_shared_intr_map
[irq
].num_shared_intr
; i
++) {
135 irq_source
= gic_shared_intr_map
[irq
].intr_list
[i
];
136 if (gic_irq_flags
[irq_source
] & GIC_TRIG_EDGE
)
137 GICWRITE(GIC_REG(SHARED
, GIC_SH_WEDGE
), irq_source
);
140 /* Enable interrupts. */
141 GIC_SET_INTR_MASK(irq
);
144 void __init
gic_platform_init(int irqs
, struct irq_chip
*irq_controller
)
149 * For non-EIC mode, we want to setup the GIC in pass-through
150 * mode, as if the GIC didn't exist. Do not map any interrupts
151 * for an external interrupt controller.
156 for (i
= gic_irq_base
; i
< (gic_irq_base
+ irqs
); i
++)
157 irq_set_chip_and_handler(i
, irq_controller
, handle_percpu_irq
);