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
23 static unsigned long sead3_config_reg
;
26 * This table defines the setup for each external GIC interrupt. It is
27 * indexed by interrupt number.
29 #define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
30 static struct gic_intr_map gic_intr_map
[GIC_NUM_INTRS
] = {
31 { 0, GIC_CPU_INT4
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
32 { 0, GIC_CPU_INT3
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
33 { 0, GIC_CPU_INT2
, 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_INT1
, GIC_POL_POS
, GIC_TRIG_LEVEL
, GIC_FLAG_TRANSPARENT
},
36 { 0, GIC_CPU_INT0
, 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 { GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
, GIC_UNUSED
},
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
},
49 asmlinkage
void plat_irq_dispatch(void)
51 unsigned int pending
= read_c0_cause() & read_c0_status() & ST0_IM
;
54 irq
= (fls(pending
) - CAUSEB_IP
- 1);
56 do_IRQ(MIPS_CPU_IRQ_BASE
+ irq
);
61 void __init
arch_init_irq(void)
69 /* install generic handler */
70 for (i
= 0; i
< 8; i
++)
71 set_vi_handler(i
, plat_irq_dispatch
);
75 sead3_config_reg
= (unsigned long)ioremap_nocache(SEAD_CONFIG_BASE
,
77 gic_present
= (REG32(sead3_config_reg
) & SEAD_CONFIG_GIC_PRESENT_MSK
) >>
78 SEAD_CONFIG_GIC_PRESENT_SHF
;
79 pr_info("GIC: %spresent\n", (gic_present
) ? "" : "not ");
81 (current_cpu_data
.options
& MIPS_CPU_VEIC
) ? "on" : "off");
84 gic_init(GIC_BASE_ADDR
, GIC_ADDRSPACE_SZ
, gic_intr_map
,
85 ARRAY_SIZE(gic_intr_map
), MIPS_GIC_IRQ_BASE
);
88 void gic_enable_interrupt(int irq_vec
)
90 unsigned int i
, irq_source
;
92 /* enable all the interrupts associated with this vector */
93 for (i
= 0; i
< gic_shared_intr_map
[irq_vec
].num_shared_intr
; i
++) {
94 irq_source
= gic_shared_intr_map
[irq_vec
].intr_list
[i
];
95 GIC_SET_INTR_MASK(irq_source
);
97 /* enable all local interrupts associated with this vector */
98 if (gic_shared_intr_map
[irq_vec
].local_intr_mask
) {
99 GICWRITE(GIC_REG(VPE_LOCAL
, GIC_VPE_OTHER_ADDR
), 0);
100 GICWRITE(GIC_REG(VPE_OTHER
, GIC_VPE_SMASK
),
101 gic_shared_intr_map
[irq_vec
].local_intr_mask
);
105 void gic_disable_interrupt(int irq_vec
)
107 unsigned int i
, irq_source
;
109 /* disable all the interrupts associated with this vector */
110 for (i
= 0; i
< gic_shared_intr_map
[irq_vec
].num_shared_intr
; i
++) {
111 irq_source
= gic_shared_intr_map
[irq_vec
].intr_list
[i
];
112 GIC_CLR_INTR_MASK(irq_source
);
114 /* disable all local interrupts associated with this vector */
115 if (gic_shared_intr_map
[irq_vec
].local_intr_mask
) {
116 GICWRITE(GIC_REG(VPE_LOCAL
, GIC_VPE_OTHER_ADDR
), 0);
117 GICWRITE(GIC_REG(VPE_OTHER
, GIC_VPE_RMASK
),
118 gic_shared_intr_map
[irq_vec
].local_intr_mask
);
122 void gic_irq_ack(struct irq_data
*d
)
124 GIC_CLR_INTR_MASK(d
->irq
- gic_irq_base
);
127 void gic_finish_irq(struct irq_data
*d
)
129 unsigned int irq
= (d
->irq
- gic_irq_base
);
130 unsigned int i
, irq_source
;
132 /* Clear edge detectors. */
133 for (i
= 0; i
< gic_shared_intr_map
[irq
].num_shared_intr
; i
++) {
134 irq_source
= gic_shared_intr_map
[irq
].intr_list
[i
];
135 if (gic_irq_flags
[irq_source
] & GIC_TRIG_EDGE
)
136 GICWRITE(GIC_REG(SHARED
, GIC_SH_WEDGE
), irq_source
);
139 /* Enable interrupts. */
140 GIC_SET_INTR_MASK(irq
);
143 void __init
gic_platform_init(int irqs
, struct irq_chip
*irq_controller
)
148 * For non-EIC mode, we want to setup the GIC in pass-through
149 * mode, as if the GIC didn't exist. Do not map any interrupts
150 * for an external interrupt controller.
155 for (i
= gic_irq_base
; i
< (gic_irq_base
+ irqs
); i
++)
156 irq_set_chip_and_handler(i
, irq_controller
, handle_percpu_irq
);