Hi Maxime, On 4 November 2011 19:09, Maxime Bizon <mbizon@xxxxxxxxxx> wrote: > Signed-off-by: Maxime Bizon <mbizon@xxxxxxxxxx> > --- > arch/mips/bcm63xx/irq.c | 131 ++++++++++++++++----- > arch/mips/bcm63xx/setup.c | 30 ++++- > arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 31 ++++-- > 3 files changed, 149 insertions(+), 43 deletions(-) > > diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c > index fde8bb4..d159ba7 100644 > --- a/arch/mips/bcm63xx/irq.c > +++ b/arch/mips/bcm63xx/irq.c > @@ -34,6 +34,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; > #define is_ext_irq_cascaded 0 > #define ext_irq_start 0 > #define ext_irq_end 0 > +#define ext_irq_count 4 > +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6338 > +#define ext_irq_cfg_reg2 0 > #endif > #ifdef CONFIG_BCM63XX_CPU_6345 > #define irq_stat_reg PERF_IRQSTAT_6345_REG > @@ -42,6 +45,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; > #define is_ext_irq_cascaded 0 > #define ext_irq_start 0 > #define ext_irq_end 0 > +#define ext_irq_count 0 > +#define ext_irq_cfg_reg1 0 According to my sources BCM6345 has an EXTIRQ_CFG_REG, too (same place as the others; 0x14). > +#define ext_irq_cfg_reg2 0 > #endif > #ifdef CONFIG_BCM63XX_CPU_6348 > #define irq_stat_reg PERF_IRQSTAT_6348_REG > @@ -50,6 +56,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; > #define is_ext_irq_cascaded 0 > #define ext_irq_start 0 > #define ext_irq_end 0 > +#define ext_irq_count 4 > +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6348 > +#define ext_irq_cfg_reg2 0 > #endif > #ifdef CONFIG_BCM63XX_CPU_6358 > #define irq_stat_reg PERF_IRQSTAT_6358_REG > @@ -58,6 +67,9 @@ static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; > #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) > +#define ext_irq_count 4 > +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6358 > +#define ext_irq_cfg_reg2 0 > #endif > > #if irq_bits == 32 > @@ -81,7 +93,9 @@ 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_count; > static unsigned int ext_irq_start, ext_irq_end; > +static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; > static void (*internal_irq_mask)(unsigned int irq); > static void (*internal_irq_unmask)(unsigned int irq); > > @@ -107,14 +121,18 @@ static void bcm63xx_init_irq(void) > irq_stat_addr += PERF_IRQSTAT_6348_REG; > irq_mask_addr += PERF_IRQMASK_6348_REG; > irq_bits = 32; > + ext_irq_count = 4; > + ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; > break; > case BCM6358_CPU_ID: > irq_stat_addr += PERF_IRQSTAT_6358_REG; > irq_mask_addr += PERF_IRQMASK_6358_REG; > irq_bits = 32; > + ext_irq_count = 4; > 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; > + ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; > break; You missed BCM6338 (and BCM6345) here. > default: > BUG(); (snip) > @@ -297,58 +335,93 @@ static void bcm63xx_external_irq_unmask(struct irq_data *d) > static void bcm63xx_external_irq_clear(struct irq_data *d) > { > unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; > - u32 reg; > + u32 reg, regaddr; > + > + regaddr = get_ext_irq_perf_reg(irq); > + reg = bcm_perf_readl(regaddr); > > - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); > - reg |= EXTIRQ_CFG_CLEAR(irq); > - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); > + if (BCMCPU_IS_6348()) > + reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4); > + else > + reg |= EXTIRQ_CFG_CLEAR(irq % 4); > + > + bcm_perf_writel(reg, regaddr); > } > > static int bcm63xx_external_irq_set_type(struct irq_data *d, > unsigned int flow_type) > { > unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; > - u32 reg; > + u32 reg, regaddr; > + int levelsense, sense, bothedge; > > flow_type &= IRQ_TYPE_SENSE_MASK; > > if (flow_type == IRQ_TYPE_NONE) > flow_type = IRQ_TYPE_LEVEL_LOW; > > - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); > + levelsense = sense = bothedge = 0; > switch (flow_type) { > case IRQ_TYPE_EDGE_BOTH: > - reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); > - reg |= EXTIRQ_CFG_BOTHEDGE(irq); > + bothedge = 1; > break; > > case IRQ_TYPE_EDGE_RISING: > - reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); > - reg |= EXTIRQ_CFG_SENSE(irq); > - reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); > + sense = 1; > break; > > case IRQ_TYPE_EDGE_FALLING: > - reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); > - reg &= ~EXTIRQ_CFG_SENSE(irq); > - reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); > break; > > case IRQ_TYPE_LEVEL_HIGH: > - reg |= EXTIRQ_CFG_LEVELSENSE(irq); > - reg |= EXTIRQ_CFG_SENSE(irq); > + levelsense = 1; > + sense = 1; > break; > > case IRQ_TYPE_LEVEL_LOW: > - reg |= EXTIRQ_CFG_LEVELSENSE(irq); > - reg &= ~EXTIRQ_CFG_SENSE(irq); > + levelsense = 1; > break; > > default: > printk(KERN_ERR "bogus flow type combination given !\n"); > return -EINVAL; > } > - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); > + > + regaddr = get_ext_irq_perf_reg(irq); > + reg = bcm_perf_readl(regaddr); > + irq %= 4; > + > + if (BCMCPU_IS_6348()) { > + if (levelsense) > + reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq); > + else > + reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq); > + if (sense) > + reg |= EXTIRQ_CFG_SENSE_6348(irq); > + else > + reg &= ~EXTIRQ_CFG_SENSE_6348(irq); > + if (bothedge) > + reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq); > + else > + reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq); > + } > + > + if (BCMCPU_IS_6338() || BCMCPU_IS_6358()) { This is also valid for BCM6345. Also you can make this an else if () of the if() above. > + if (levelsense) > + reg |= EXTIRQ_CFG_LEVELSENSE(irq); > + else > + reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); > + if (sense) > + reg |= EXTIRQ_CFG_SENSE(irq); > + else > + reg &= ~EXTIRQ_CFG_SENSE(irq); > + if (bothedge) > + reg |= EXTIRQ_CFG_BOTHEDGE(irq); > + else > + reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); > + } > + > + bcm_perf_writel(reg, regaddr); > > irqd_set_trigger_type(d, flow_type); > if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) (snip) > diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c > index 04a3499..d209f85 100644 > --- a/arch/mips/bcm63xx/setup.c > +++ b/arch/mips/bcm63xx/setup.c > @@ -63,13 +63,33 @@ static void bcm6348_a1_reboot(void) > > void bcm63xx_machine_reboot(void) > { > - u32 reg; > + u32 reg, perf_regs[2] = { 0, 0 }; > + unsigned int i; > > /* mask and clear all external irq */ > - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); > - reg &= ~EXTIRQ_CFG_MASK_ALL; > - reg |= EXTIRQ_CFG_CLEAR_ALL; > - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); > + switch (bcm63xx_get_cpu_id()) { > + case BCM6338_CPU_ID: > + perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338; > + break; > + case BCM6348_CPU_ID: > + perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348; > + break; > + case BCM6358_CPU_ID: > + perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358; > + break; Missing the BCM6345 again. > + } > + > + for (i = 0; i < 2; i++) { > + reg = bcm_perf_readl(perf_regs[i]); perf_regs[1] is (currently) always 0, so you are actually reading ... > + if (BCMCPU_IS_6348()) { > + reg &= ~EXTIRQ_CFG_MASK_ALL_6348; > + reg |= EXTIRQ_CFG_CLEAR_ALL_6348; > + } else { > + reg &= ~EXTIRQ_CFG_MASK_ALL; > + reg |= EXTIRQ_CFG_CLEAR_ALL; > + } > + bcm_perf_writel(reg, perf_regs[i]); ... and writing to the REV_ID register. While it's probably harmless as this is a read-only register, it doesn't look right. Since BCM6368 and BCM6816 seem to be the only two actually having more than one EXTIRQ register, I think it would make more sense to just modify the first and check for the CPUID for the second instead of a two element loop. so I would do something like if (BCMCPU_IS_6348()) { /* do the 6348 modify of the first extirq reg */ } else { /* do the normal modify of the first extirq reg */ } And then add in your 6368 patch (maybe to the else branch) if (BCMCPU_IS_6368()) { /* modify the second ext_irq reg */ } > + } > > if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1)) > bcm6348_a1_reboot(); > diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h > index 25676cd..2b3a2d6 100644 > --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h > +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h > @@ -100,16 +100,29 @@ > #define PERF_IRQSTAT_6358_REG 0x10 > > /* External Interrupt Configuration register */ > -#define PERF_EXTIRQ_CFG_REG 0x14 > +#define PERF_EXTIRQ_CFG_REG_6338 0x14 Missing the 6345 here again. > +#define PERF_EXTIRQ_CFG_REG_6348 0x14 > +#define PERF_EXTIRQ_CFG_REG_6358 0x14 (snip) Regards Jonas