Skip to content

Commit

Permalink
MIPS: BCM63XX: Prepare irq code to handle different external irq hard…
Browse files Browse the repository at this point in the history
…ware implementation.

External irq only works for 6348, change code to prepare support of
other CPUs.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2895/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
Maxime Bizon authored and Ralf Baechle committed Dec 7, 2011
1 parent f61cced commit 37c42a7
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 44 deletions.
104 changes: 67 additions & 37 deletions arch/mips/bcm63xx/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,32 @@ static void __dispatch_internal(void) __maybe_unused;
#ifdef CONFIG_BCM63XX_CPU_6338
#define irq_stat_reg PERF_IRQSTAT_6338_REG
#define irq_mask_reg PERF_IRQMASK_6338_REG
#define is_ext_irq_cascaded 0
#define ext_irq_start 0
#define ext_irq_end 0
#endif
#ifdef CONFIG_BCM63XX_CPU_6345
#define irq_stat_reg PERF_IRQSTAT_6345_REG
#define irq_mask_reg PERF_IRQMASK_6345_REG
#define is_ext_irq_cascaded 0
#define ext_irq_start 0
#define ext_irq_end 0
#endif
#ifdef CONFIG_BCM63XX_CPU_6348
#define irq_stat_reg PERF_IRQSTAT_6348_REG
#define irq_mask_reg PERF_IRQMASK_6348_REG
#define dispatch_internal __dispatch_internal
#define is_ext_irq_cascaded 0
#define ext_irq_start 0
#define ext_irq_end 0
#endif
#ifdef CONFIG_BCM63XX_CPU_6358
#define irq_stat_reg PERF_IRQSTAT_6358_REG
#define irq_mask_reg PERF_IRQMASK_6358_REG
#define dispatch_internal __dispatch_internal
#define is_ext_irq_cascaded 1
#define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE)
#define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE)
#endif

#define dispatch_internal __dispatch_internal
Expand All @@ -51,6 +65,8 @@ static inline void bcm63xx_init_irq(void)

static u32 irq_stat_addr, irq_mask_addr;
static void (*dispatch_internal)(void);
static int is_ext_irq_cascaded;
static unsigned int ext_irq_start, ext_irq_end;

static void bcm63xx_init_irq(void)
{
Expand All @@ -73,6 +89,9 @@ static void bcm63xx_init_irq(void)
case BCM6358_CPU_ID:
irq_stat_addr += PERF_IRQSTAT_6358_REG;
irq_mask_addr += PERF_IRQMASK_6358_REG;
is_ext_irq_cascaded = 1;
ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
break;
default:
BUG();
Expand All @@ -84,7 +103,11 @@ static void bcm63xx_init_irq(void)

static inline void handle_internal(int intbit)
{
do_IRQ(intbit + IRQ_INTERNAL_BASE);
if (is_ext_irq_cascaded &&
intbit >= ext_irq_start && intbit <= ext_irq_end)
do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
else
do_IRQ(intbit + IRQ_INTERNAL_BASE);
}

/*
Expand Down Expand Up @@ -128,94 +151,93 @@ asmlinkage void plat_irq_dispatch(void)
do_IRQ(7);
if (cause & CAUSEF_IP2)
dispatch_internal();
if (cause & CAUSEF_IP3)
do_IRQ(IRQ_EXT_0);
if (cause & CAUSEF_IP4)
do_IRQ(IRQ_EXT_1);
if (cause & CAUSEF_IP5)
do_IRQ(IRQ_EXT_2);
if (cause & CAUSEF_IP6)
do_IRQ(IRQ_EXT_3);
if (!is_ext_irq_cascaded) {
if (cause & CAUSEF_IP3)
do_IRQ(IRQ_EXT_0);
if (cause & CAUSEF_IP4)
do_IRQ(IRQ_EXT_1);
if (cause & CAUSEF_IP5)
do_IRQ(IRQ_EXT_2);
if (cause & CAUSEF_IP6)
do_IRQ(IRQ_EXT_3);
}
} while (1);
}

/*
* internal IRQs operations: only mask/unmask on PERF irq mask
* register.
*/
static inline void bcm63xx_internal_irq_mask(struct irq_data *d)
static void internal_irq_mask(unsigned int irq)
{
unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
u32 mask;

mask = bcm_readl(irq_mask_addr);
mask &= ~(1 << irq);
bcm_writel(mask, irq_mask_addr);
}

static void bcm63xx_internal_irq_unmask(struct irq_data *d)
static void internal_irq_unmask(unsigned int irq)
{
unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
u32 mask;

mask = bcm_readl(irq_mask_addr);
mask |= (1 << irq);
bcm_writel(mask, irq_mask_addr);
}

static void bcm63xx_internal_irq_mask(struct irq_data *d)
{
internal_irq_mask(d->irq - IRQ_INTERNAL_BASE);
}

static void bcm63xx_internal_irq_unmask(struct irq_data *d)
{
internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE);
}

/*
* external IRQs operations: mask/unmask and clear on PERF external
* irq control register.
*/
static void bcm63xx_external_irq_mask(struct irq_data *d)
{
unsigned int irq = d->irq - IRQ_EXT_BASE;
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;

reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
reg &= ~EXTIRQ_CFG_MASK(irq);
bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
if (is_ext_irq_cascaded)
internal_irq_mask(irq + ext_irq_start);
}

static void bcm63xx_external_irq_unmask(struct irq_data *d)
{
unsigned int irq = d->irq - IRQ_EXT_BASE;
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;

reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
reg |= EXTIRQ_CFG_MASK(irq);
bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
if (is_ext_irq_cascaded)
internal_irq_unmask(irq + ext_irq_start);
}

static void bcm63xx_external_irq_clear(struct irq_data *d)
{
unsigned int irq = d->irq - IRQ_EXT_BASE;
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;

reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
reg |= EXTIRQ_CFG_CLEAR(irq);
bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
}

static unsigned int bcm63xx_external_irq_startup(struct irq_data *d)
{
set_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
irq_enable_hazard();
bcm63xx_external_irq_unmask(d);
return 0;
}

static void bcm63xx_external_irq_shutdown(struct irq_data *d)
{
bcm63xx_external_irq_mask(d);
clear_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
irq_disable_hazard();
}

static int bcm63xx_external_irq_set_type(struct irq_data *d,
unsigned int flow_type)
{
unsigned int irq = d->irq - IRQ_EXT_BASE;
unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;

flow_type &= IRQ_TYPE_SENSE_MASK;
Expand Down Expand Up @@ -275,9 +297,6 @@ static struct irq_chip bcm63xx_internal_irq_chip = {

static struct irq_chip bcm63xx_external_irq_chip = {
.name = "bcm63xx_epic",
.irq_startup = bcm63xx_external_irq_startup,
.irq_shutdown = bcm63xx_external_irq_shutdown,

.irq_ack = bcm63xx_external_irq_clear,

.irq_mask = bcm63xx_external_irq_mask,
Expand All @@ -292,6 +311,12 @@ static struct irqaction cpu_ip2_cascade_action = {
.flags = IRQF_NO_THREAD,
};

static struct irqaction cpu_ext_cascade_action = {
.handler = no_action,
.name = "cascade_extirq",
.flags = IRQF_NO_THREAD,
};

void __init arch_init_irq(void)
{
int i;
Expand All @@ -302,9 +327,14 @@ void __init arch_init_irq(void)
irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
handle_level_irq);

for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i)
for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + 4; ++i)
irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
handle_edge_irq);

setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action);
if (!is_ext_irq_cascaded) {
for (i = 3; i < 7; ++i)
setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action);
}

setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);
}
12 changes: 5 additions & 7 deletions arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@

#include <bcm63xx_cpu.h>

#define IRQ_MIPS_BASE 0
#define IRQ_INTERNAL_BASE 8

#define IRQ_EXT_BASE (IRQ_MIPS_BASE + 3)
#define IRQ_EXT_0 (IRQ_EXT_BASE + 0)
#define IRQ_EXT_1 (IRQ_EXT_BASE + 1)
#define IRQ_EXT_2 (IRQ_EXT_BASE + 2)
#define IRQ_EXT_3 (IRQ_EXT_BASE + 3)
#define IRQ_EXTERNAL_BASE 100
#define IRQ_EXT_0 (IRQ_EXTERNAL_BASE + 0)
#define IRQ_EXT_1 (IRQ_EXTERNAL_BASE + 1)
#define IRQ_EXT_2 (IRQ_EXTERNAL_BASE + 2)
#define IRQ_EXT_3 (IRQ_EXTERNAL_BASE + 3)

#endif /* ! BCM63XX_IRQ_H_ */
7 changes: 7 additions & 0 deletions arch/mips/include/asm/mach-bcm63xx/irq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef __ASM_MACH_BCM63XX_IRQ_H
#define __ASM_MACH_BCM63XX_IRQ_H

#define NR_IRQS 128
#define MIPS_CPU_IRQ_BASE 0

#endif

0 comments on commit 37c42a7

Please sign in to comment.