2009-08-31 08:15:11 +08:00
|
|
|
/*
|
|
|
|
* Portions copyright (C) 2005-2009 Scientific Atlanta
|
|
|
|
* Portions copyright (C) 2009 Cisco Systems, Inc.
|
|
|
|
*
|
|
|
|
* Modified from arch/mips/kernel/irq-rm7000.c:
|
|
|
|
* Copyright (C) 2003 Ralf Baechle
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
* option) any later version.
|
|
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/kernel.h>
|
2010-10-07 21:08:54 +08:00
|
|
|
#include <linux/irq.h>
|
2009-08-31 08:15:11 +08:00
|
|
|
|
|
|
|
#include <asm/irq_cpu.h>
|
|
|
|
#include <asm/mipsregs.h>
|
|
|
|
#include <asm/system.h>
|
|
|
|
|
|
|
|
#include <asm/mach-powertv/asic_regs.h>
|
|
|
|
|
2011-03-24 05:09:09 +08:00
|
|
|
static inline void unmask_asic_irq(struct irq_data *d)
|
2009-08-31 08:15:11 +08:00
|
|
|
{
|
|
|
|
unsigned long enable_bit;
|
2011-03-24 05:09:09 +08:00
|
|
|
unsigned int irq = d->irq;
|
2009-08-31 08:15:11 +08:00
|
|
|
|
|
|
|
enable_bit = (1 << (irq & 0x1f));
|
|
|
|
|
|
|
|
switch (irq >> 5) {
|
|
|
|
case 0:
|
|
|
|
asic_write(asic_read(ien_int_0) | enable_bit, ien_int_0);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
asic_write(asic_read(ien_int_1) | enable_bit, ien_int_1);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
asic_write(asic_read(ien_int_2) | enable_bit, ien_int_2);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
asic_write(asic_read(ien_int_3) | enable_bit, ien_int_3);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-24 05:09:09 +08:00
|
|
|
static inline void mask_asic_irq(struct irq_data *d)
|
2009-08-31 08:15:11 +08:00
|
|
|
{
|
|
|
|
unsigned long disable_mask;
|
2011-03-24 05:09:09 +08:00
|
|
|
unsigned int irq = d->irq;
|
2009-08-31 08:15:11 +08:00
|
|
|
|
|
|
|
disable_mask = ~(1 << (irq & 0x1f));
|
|
|
|
|
|
|
|
switch (irq >> 5) {
|
|
|
|
case 0:
|
|
|
|
asic_write(asic_read(ien_int_0) & disable_mask, ien_int_0);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
asic_write(asic_read(ien_int_1) & disable_mask, ien_int_1);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
asic_write(asic_read(ien_int_2) & disable_mask, ien_int_2);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
asic_write(asic_read(ien_int_3) & disable_mask, ien_int_3);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct irq_chip asic_irq_chip = {
|
|
|
|
.name = "ASIC Level",
|
2011-03-24 05:09:09 +08:00
|
|
|
.irq_mask = mask_asic_irq,
|
|
|
|
.irq_unmask = unmask_asic_irq,
|
2009-08-31 08:15:11 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void __init asic_irq_init(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* set priority to 0 */
|
|
|
|
write_c0_status(read_c0_status() & ~(0x0000fc00));
|
|
|
|
|
|
|
|
asic_write(0, ien_int_0);
|
|
|
|
asic_write(0, ien_int_1);
|
|
|
|
asic_write(0, ien_int_2);
|
|
|
|
asic_write(0, ien_int_3);
|
|
|
|
|
|
|
|
asic_write(0x0fffffff, int_level_3_3);
|
|
|
|
asic_write(0xffffffff, int_level_3_2);
|
|
|
|
asic_write(0xffffffff, int_level_3_1);
|
|
|
|
asic_write(0xffffffff, int_level_3_0);
|
|
|
|
asic_write(0xffffffff, int_level_2_3);
|
|
|
|
asic_write(0xffffffff, int_level_2_2);
|
|
|
|
asic_write(0xffffffff, int_level_2_1);
|
|
|
|
asic_write(0xffffffff, int_level_2_0);
|
|
|
|
asic_write(0xffffffff, int_level_1_3);
|
|
|
|
asic_write(0xffffffff, int_level_1_2);
|
|
|
|
asic_write(0xffffffff, int_level_1_1);
|
|
|
|
asic_write(0xffffffff, int_level_1_0);
|
|
|
|
asic_write(0xffffffff, int_level_0_3);
|
|
|
|
asic_write(0xffffffff, int_level_0_2);
|
|
|
|
asic_write(0xffffffff, int_level_0_1);
|
|
|
|
asic_write(0xffffffff, int_level_0_0);
|
|
|
|
|
|
|
|
asic_write(0xf, int_int_scan);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize interrupt handlers.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < NR_IRQS; i++)
|
|
|
|
set_irq_chip_and_handler(i, &asic_irq_chip, handle_level_irq);
|
|
|
|
}
|