1
0
Files
kernel-49/arch/mips/tc3262/irq.c
2021-03-11 18:33:13 +03:00

307 lines
7.1 KiB
C

/*
* Interrupt service routines for Trendchip board
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/tc3162/tc3162.h>
#include "irq.h"
extern void vsmp_int_init(void);
extern int plat_set_irq_affinity(struct irq_data *d,
const struct cpumask *affinity, bool force);
__IMEM
static inline bool mips_mt_cpu_is_irq0(const struct irq_data *d)
{
return d->irq == SI_SWINT_INT0 || d->irq == SI_SWINT1_INT0;
}
__IMEM
static inline unsigned long mips_mt_cpu_irq_mask(const struct irq_data *d)
{
if (mips_mt_cpu_is_irq0(d))
return CAUSEF_IP0;
return CAUSEF_IP1;
}
__IMEM
static inline void unmask_mips_mt_irq(struct irq_data *d)
{
const unsigned int vpflags = dvpe();
set_c0_status(mips_mt_cpu_irq_mask(d));
irq_enable_hazard();
evpe(vpflags);
}
__IMEM
static inline void mask_mips_mt_irq(struct irq_data *d)
{
const unsigned int vpflags = dvpe();
clear_c0_status(mips_mt_cpu_irq_mask(d));
irq_disable_hazard();
evpe(vpflags);
}
__IMEM
static unsigned int mips_mt_cpu_irq_startup(struct irq_data *d)
{
const unsigned int vpflags = dvpe();
const unsigned int mask = mips_mt_cpu_irq_mask(d);
unsigned int reg_imr = VPint(CR_INTC_IMR);
if (mips_mt_cpu_is_irq0(d))
reg_imr |= (1u << (SI_SWINT_INT0 - 1)) |
(1u << (SI_SWINT1_INT0 - 1));
else
reg_imr |= (1u << (SI_SWINT_INT1 - 1)) |
(1u << (SI_SWINT1_INT1 - 1));
VPint(CR_INTC_IMR) = reg_imr;
clear_c0_cause(mask);
set_c0_status(mask);
irq_enable_hazard();
evpe(vpflags);
return 0;
}
/*
* While we ack the interrupt interrupts are disabled and thus we don't need
* to deal with concurrency issues. Same for mips_cpu_irq_end.
*/
__IMEM
static void mips_mt_cpu_irq_ack(struct irq_data *d)
{
const unsigned int vpflags = dvpe();
const unsigned int mask = mips_mt_cpu_irq_mask(d);
clear_c0_cause(mask);
clear_c0_status(mask);
irq_disable_hazard();
evpe(vpflags);
}
static struct irq_chip mips_mt_cpu_irq_controller = {
.name = "MIPS",
.irq_startup = mips_mt_cpu_irq_startup,
.irq_ack = mips_mt_cpu_irq_ack,
.irq_mask = mask_mips_mt_irq,
.irq_mask_ack = mips_mt_cpu_irq_ack,
.irq_unmask = unmask_mips_mt_irq,
.irq_eoi = unmask_mips_mt_irq,
.irq_disable = mask_mips_mt_irq,
.irq_enable = unmask_mips_mt_irq,
};
static DEFINE_SPINLOCK(tc3262_irq_lock);
__IMEM
static inline void unmask_mips_irq(struct irq_data *d)
{
unsigned long flags;
unsigned int irq = d->irq;
spin_lock_irqsave(&tc3262_irq_lock, flags);
if (smp_processor_id() != 0 && irq == SI_TIMER_INT)
irq = SI_TIMER1_INT;
if (irq <= 32)
VPint(CR_INTC_IMR) |= (1u << (irq - 1));
else
VPint(CR_INTC_IMR_1) |= (1u << (irq - 33));
spin_unlock_irqrestore(&tc3262_irq_lock, flags);
}
__IMEM
static inline void mask_mips_irq(struct irq_data *d)
{
unsigned long flags;
unsigned int irq = d->irq;
spin_lock_irqsave(&tc3262_irq_lock, flags);
if (smp_processor_id() != 0 && irq == SI_TIMER_INT)
irq = SI_TIMER1_INT;
if (irq <= 32)
VPint(CR_INTC_IMR) &= ~(1u << (irq - 1));
else
VPint(CR_INTC_IMR_1) &= ~(1u << (irq - 33));
spin_unlock_irqrestore(&tc3262_irq_lock, flags);
}
static struct irq_chip tc3262_irq_chip = {
.name = "INTC",
.irq_ack = mask_mips_irq,
.irq_mask = mask_mips_irq,
.irq_mask_ack = mask_mips_irq,
.irq_unmask = unmask_mips_irq,
.irq_eoi = unmask_mips_irq,
.irq_disable = mask_mips_irq,
.irq_enable = unmask_mips_irq,
#ifdef CONFIG_MIPS_MT_SMP
.irq_set_affinity = plat_set_irq_affinity,
#endif
};
#define __BUILD_IRQ_DISPATCH(irq_n) \
__IMEM \
static void __tc3262_irq_dispatch##irq_n(void) \
{ \
do_IRQ(irq_n); \
}
#define __BUILD_IRQ_DISPATCH_FUNC(irq_n) __tc3262_irq_dispatch##irq_n
/* pre-built 41 irq dispatch function */
__BUILD_IRQ_DISPATCH(0)
__BUILD_IRQ_DISPATCH(1)
__BUILD_IRQ_DISPATCH(2)
__BUILD_IRQ_DISPATCH(3)
__BUILD_IRQ_DISPATCH(4)
__BUILD_IRQ_DISPATCH(5)
__BUILD_IRQ_DISPATCH(6)
__BUILD_IRQ_DISPATCH(7)
__BUILD_IRQ_DISPATCH(8)
__BUILD_IRQ_DISPATCH(9)
__BUILD_IRQ_DISPATCH(10)
__BUILD_IRQ_DISPATCH(11)
__BUILD_IRQ_DISPATCH(12)
__BUILD_IRQ_DISPATCH(13)
__BUILD_IRQ_DISPATCH(14)
__BUILD_IRQ_DISPATCH(15)
__BUILD_IRQ_DISPATCH(16)
__BUILD_IRQ_DISPATCH(17)
__BUILD_IRQ_DISPATCH(18)
__BUILD_IRQ_DISPATCH(19)
__BUILD_IRQ_DISPATCH(20)
__BUILD_IRQ_DISPATCH(21)
__BUILD_IRQ_DISPATCH(22)
__BUILD_IRQ_DISPATCH(23)
__BUILD_IRQ_DISPATCH(24)
__BUILD_IRQ_DISPATCH(25)
__BUILD_IRQ_DISPATCH(26)
__BUILD_IRQ_DISPATCH(27)
__BUILD_IRQ_DISPATCH(28)
__BUILD_IRQ_DISPATCH(29)
__BUILD_IRQ_DISPATCH(30)
__BUILD_IRQ_DISPATCH(31)
__BUILD_IRQ_DISPATCH(32)
__BUILD_IRQ_DISPATCH(33)
__BUILD_IRQ_DISPATCH(34)
__BUILD_IRQ_DISPATCH(35)
__BUILD_IRQ_DISPATCH(36)
__BUILD_IRQ_DISPATCH(37)
__BUILD_IRQ_DISPATCH(38)
__BUILD_IRQ_DISPATCH(39)
__BUILD_IRQ_DISPATCH(40)
/* register pre-built 41 irq dispatch function */
static void (*irq_dispatch_tab[])(void) =
{
__BUILD_IRQ_DISPATCH_FUNC(0),
__BUILD_IRQ_DISPATCH_FUNC(1),
__BUILD_IRQ_DISPATCH_FUNC(2),
__BUILD_IRQ_DISPATCH_FUNC(3),
__BUILD_IRQ_DISPATCH_FUNC(4),
__BUILD_IRQ_DISPATCH_FUNC(5),
__BUILD_IRQ_DISPATCH_FUNC(6),
__BUILD_IRQ_DISPATCH_FUNC(7),
__BUILD_IRQ_DISPATCH_FUNC(8),
__BUILD_IRQ_DISPATCH_FUNC(9),
__BUILD_IRQ_DISPATCH_FUNC(10),
__BUILD_IRQ_DISPATCH_FUNC(11),
__BUILD_IRQ_DISPATCH_FUNC(12),
__BUILD_IRQ_DISPATCH_FUNC(13),
__BUILD_IRQ_DISPATCH_FUNC(14),
__BUILD_IRQ_DISPATCH_FUNC(15),
__BUILD_IRQ_DISPATCH_FUNC(16),
__BUILD_IRQ_DISPATCH_FUNC(17),
__BUILD_IRQ_DISPATCH_FUNC(18),
__BUILD_IRQ_DISPATCH_FUNC(19),
__BUILD_IRQ_DISPATCH_FUNC(20),
__BUILD_IRQ_DISPATCH_FUNC(21),
__BUILD_IRQ_DISPATCH_FUNC(22),
__BUILD_IRQ_DISPATCH_FUNC(23),
__BUILD_IRQ_DISPATCH_FUNC(24),
__BUILD_IRQ_DISPATCH_FUNC(25),
__BUILD_IRQ_DISPATCH_FUNC(26),
__BUILD_IRQ_DISPATCH_FUNC(27),
__BUILD_IRQ_DISPATCH_FUNC(28),
__BUILD_IRQ_DISPATCH_FUNC(29),
__BUILD_IRQ_DISPATCH_FUNC(30),
__BUILD_IRQ_DISPATCH_FUNC(31),
__BUILD_IRQ_DISPATCH_FUNC(32),
__BUILD_IRQ_DISPATCH_FUNC(33),
__BUILD_IRQ_DISPATCH_FUNC(34),
__BUILD_IRQ_DISPATCH_FUNC(35),
__BUILD_IRQ_DISPATCH_FUNC(36),
__BUILD_IRQ_DISPATCH_FUNC(37),
__BUILD_IRQ_DISPATCH_FUNC(38),
__BUILD_IRQ_DISPATCH_FUNC(39),
__BUILD_IRQ_DISPATCH_FUNC(40)
};
void tc_disable_irq_all(void)
{
unsigned long flags;
spin_lock_irqsave(&tc3262_irq_lock, flags);
VPint(CR_INTC_IMR) = 0x0;
VPint(CR_INTC_IMR_1) = 0x0;
spin_unlock_irqrestore(&tc3262_irq_lock, flags);
}
void __init arch_init_irq(void)
{
unsigned int i;
/* disable all hardware interrupts */
clear_c0_status(ST0_IM);
clear_c0_cause(CAUSEF_IP);
for (i = 0; i < NR_IRQS; i++) {
if (i == SI_SWINT_INT0 || i == SI_SWINT1_INT0 ||
i == SI_SWINT_INT1 || i == SI_SWINT1_INT1) {
irq_set_chip(i, &mips_mt_cpu_irq_controller);
} else if (i == SI_TIMER_INT || i == SI_TIMER1_INT)
irq_set_chip_and_handler(i, &tc3262_irq_chip,
handle_percpu_devid_irq);
else
irq_set_chip_and_handler(i, &tc3262_irq_chip,
handle_level_irq);
set_vi_handler(i, irq_dispatch_tab[i]);
}
#ifdef CONFIG_MIPS_MT_SMP
vsmp_int_init();
#endif
/* enable MIPS IRQ0 and IRQ1 */
write_c0_status((read_c0_status() & ~ST0_IM) |
(STATUSF_IP0 | STATUSF_IP1));
}
__IMEM
asmlinkage void plat_irq_dispatch(void)
{
unsigned int irq = (read_c0_cause() & ST0_IM) >> 10;
do_IRQ(irq);
}