#include <bcm63xx_io.h>
#include <bcm63xx_irq.h>
-static void __dispatch_internal(void) __maybe_unused;
-static void __dispatch_internal_64(void) __maybe_unused;
-static void __internal_irq_mask_32(unsigned int irq) __maybe_unused;
-static void __internal_irq_mask_64(unsigned int irq) __maybe_unused;
-static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused;
-static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused;
-
-#ifndef BCMCPU_RUNTIME_DETECT
-#ifdef CONFIG_BCM63XX_CPU_6328
-#define irq_stat_reg PERF_IRQSTAT_6328_REG
-#define irq_mask_reg PERF_IRQMASK_6328_REG
-#define irq_bits 64
-#define is_ext_irq_cascaded 1
-#define ext_irq_start (BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE)
-#define ext_irq_end (BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE)
-#define ext_irq_count 4
-#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6328
-#define ext_irq_cfg_reg2 0
-#endif
-#ifdef CONFIG_BCM63XX_CPU_6338
-#define irq_stat_reg PERF_IRQSTAT_6338_REG
-#define irq_mask_reg PERF_IRQMASK_6338_REG
-#define irq_bits 32
-#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
-#define irq_mask_reg PERF_IRQMASK_6345_REG
-#define irq_bits 32
-#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_6345
-#define ext_irq_cfg_reg2 0
-#endif
-#ifdef CONFIG_BCM63XX_CPU_6348
-#define irq_stat_reg PERF_IRQSTAT_6348_REG
-#define irq_mask_reg PERF_IRQMASK_6348_REG
-#define irq_bits 32
-#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
-#define irq_mask_reg PERF_IRQMASK_6358_REG
-#define irq_bits 32
-#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
-#ifdef CONFIG_BCM63XX_CPU_6362
-#define irq_stat_reg PERF_IRQSTAT_6362_REG
-#define irq_mask_reg PERF_IRQMASK_6362_REG
-#define irq_bits 64
-#define is_ext_irq_cascaded 1
-#define ext_irq_start (BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE)
-#define ext_irq_end (BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE)
-#define ext_irq_count 4
-#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6362
-#define ext_irq_cfg_reg2 0
-#endif
-#ifdef CONFIG_BCM63XX_CPU_6368
-#define irq_stat_reg PERF_IRQSTAT_6368_REG
-#define irq_mask_reg PERF_IRQMASK_6368_REG
-#define irq_bits 64
-#define is_ext_irq_cascaded 1
-#define ext_irq_start (BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE)
-#define ext_irq_end (BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE)
-#define ext_irq_count 6
-#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6368
-#define ext_irq_cfg_reg2 PERF_EXTIRQ_CFG_REG2_6368
-#endif
-
-#if irq_bits == 32
-#define dispatch_internal __dispatch_internal
-#define internal_irq_mask __internal_irq_mask_32
-#define internal_irq_unmask __internal_irq_unmask_32
-#else
-#define dispatch_internal __dispatch_internal_64
-#define internal_irq_mask __internal_irq_mask_64
-#define internal_irq_unmask __internal_irq_unmask_64
-#endif
-
-#define irq_stat_addr (bcm63xx_regset_address(RSET_PERF) + irq_stat_reg)
-#define irq_mask_addr (bcm63xx_regset_address(RSET_PERF) + irq_mask_reg)
-
-static inline void bcm63xx_init_irq(void)
-{
-}
-#else /* ! BCMCPU_RUNTIME_DETECT */
-
-static u32 irq_stat_addr, irq_mask_addr;
+static u32 irq_stat_addr[2];
+static u32 irq_mask_addr[2];
static void (*dispatch_internal)(void);
static int is_ext_irq_cascaded;
static unsigned int ext_irq_count;
static void (*internal_irq_mask)(unsigned int irq);
static void (*internal_irq_unmask)(unsigned int irq);
-static void bcm63xx_init_irq(void)
-{
- int irq_bits;
-
- irq_stat_addr = bcm63xx_regset_address(RSET_PERF);
- irq_mask_addr = bcm63xx_regset_address(RSET_PERF);
-
- switch (bcm63xx_get_cpu_id()) {
- case BCM6328_CPU_ID:
- irq_stat_addr += PERF_IRQSTAT_6328_REG;
- irq_mask_addr += PERF_IRQMASK_6328_REG;
- irq_bits = 64;
- ext_irq_count = 4;
- is_ext_irq_cascaded = 1;
- ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
- ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
- break;
- case BCM6338_CPU_ID:
- irq_stat_addr += PERF_IRQSTAT_6338_REG;
- irq_mask_addr += PERF_IRQMASK_6338_REG;
- irq_bits = 32;
- ext_irq_count = 4;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
- break;
- case BCM6345_CPU_ID:
- irq_stat_addr += PERF_IRQSTAT_6345_REG;
- irq_mask_addr += PERF_IRQMASK_6345_REG;
- irq_bits = 32;
- ext_irq_count = 4;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
- break;
- case BCM6348_CPU_ID:
- 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;
- case BCM6362_CPU_ID:
- irq_stat_addr += PERF_IRQSTAT_6362_REG;
- irq_mask_addr += PERF_IRQMASK_6362_REG;
- irq_bits = 64;
- ext_irq_count = 4;
- is_ext_irq_cascaded = 1;
- ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
- ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
- break;
- case BCM6368_CPU_ID:
- irq_stat_addr += PERF_IRQSTAT_6368_REG;
- irq_mask_addr += PERF_IRQMASK_6368_REG;
- irq_bits = 64;
- ext_irq_count = 6;
- is_ext_irq_cascaded = 1;
- ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
- ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
- ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
- ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
- break;
- default:
- BUG();
- }
-
- if (irq_bits == 32) {
- dispatch_internal = __dispatch_internal;
- internal_irq_mask = __internal_irq_mask_32;
- internal_irq_unmask = __internal_irq_unmask_32;
- } else {
- dispatch_internal = __dispatch_internal_64;
- internal_irq_mask = __internal_irq_mask_64;
- internal_irq_unmask = __internal_irq_unmask_64;
- }
-}
-#endif /* ! BCMCPU_RUNTIME_DETECT */
static inline u32 get_ext_irq_perf_reg(int irq)
{
* will resume the loop where it ended the last time we left this
* function.
*/
-static void __dispatch_internal(void)
-{
- u32 pending;
- static int i;
-
- pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr);
- if (!pending)
- return ;
-
- while (1) {
- int to_call = i;
-
- i = (i + 1) & 0x1f;
- if (pending & (1 << to_call)) {
- handle_internal(to_call);
- break;
- }
- }
+#define BUILD_IPIC_INTERNAL(width) \
+void __dispatch_internal_##width(void) \
+{ \
+ u32 pending[width / 32]; \
+ unsigned int src, tgt; \
+ bool irqs_pending = false; \
+ static unsigned int i; \
+ \
+ /* read registers in reverse order */ \
+ for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \
+ u32 val; \
+ \
+ val = bcm_readl(irq_stat_addr[0] + src * sizeof(u32)); \
+ val &= bcm_readl(irq_mask_addr[0] + src * sizeof(u32)); \
+ pending[--tgt] = val; \
+ \
+ if (val) \
+ irqs_pending = true; \
+ } \
+ \
+ if (!irqs_pending) \
+ return; \
+ \
+ while (1) { \
+ unsigned int to_call = i; \
+ \
+ i = (i + 1) & (width - 1); \
+ if (pending[to_call / 32] & (1 << (to_call & 0x1f))) { \
+ handle_internal(to_call); \
+ break; \
+ } \
+ } \
+} \
+ \
+static void __internal_irq_mask_##width(unsigned int irq) \
+{ \
+ u32 val; \
+ unsigned reg = (irq / 32) ^ (width/32 - 1); \
+ unsigned bit = irq & 0x1f; \
+ \
+ val = bcm_readl(irq_mask_addr[0] + reg * sizeof(u32)); \
+ val &= ~(1 << bit); \
+ bcm_writel(val, irq_mask_addr[0] + reg * sizeof(u32)); \
+} \
+ \
+static void __internal_irq_unmask_##width(unsigned int irq) \
+{ \
+ u32 val; \
+ unsigned reg = (irq / 32) ^ (width/32 - 1); \
+ unsigned bit = irq & 0x1f; \
+ \
+ val = bcm_readl(irq_mask_addr[0] + reg * sizeof(u32)); \
+ val |= (1 << bit); \
+ bcm_writel(val, irq_mask_addr[0] + reg * sizeof(u32)); \
}
-static void __dispatch_internal_64(void)
-{
- u64 pending;
- static int i;
-
- pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr);
-
- if (!pending)
- return ;
-
- while (1) {
- int to_call = i;
-
- i = (i + 1) & 0x3f;
- if (pending & (1ull << to_call)) {
- handle_internal(to_call);
- break;
- }
- }
-}
+BUILD_IPIC_INTERNAL(32);
+BUILD_IPIC_INTERNAL(64);
asmlinkage void plat_irq_dispatch(void)
{
if (cause & CAUSEF_IP7)
do_IRQ(7);
+ if (cause & CAUSEF_IP0)
+ do_IRQ(0);
+ if (cause & CAUSEF_IP1)
+ do_IRQ(1);
if (cause & CAUSEF_IP2)
dispatch_internal();
if (!is_ext_irq_cascaded) {
* internal IRQs operations: only mask/unmask on PERF irq mask
* register.
*/
-static void __internal_irq_mask_32(unsigned int irq)
-{
- u32 mask;
-
- mask = bcm_readl(irq_mask_addr);
- mask &= ~(1 << irq);
- bcm_writel(mask, irq_mask_addr);
-}
-
-static void __internal_irq_mask_64(unsigned int irq)
-{
- u64 mask;
-
- mask = bcm_readq(irq_mask_addr);
- mask &= ~(1ull << irq);
- bcm_writeq(mask, irq_mask_addr);
-}
-
-static void __internal_irq_unmask_32(unsigned int irq)
-{
- u32 mask;
-
- mask = bcm_readl(irq_mask_addr);
- mask |= (1 << irq);
- bcm_writel(mask, irq_mask_addr);
-}
-
-static void __internal_irq_unmask_64(unsigned int irq)
-{
- u64 mask;
-
- mask = bcm_readq(irq_mask_addr);
- mask |= (1ull << irq);
- bcm_writeq(mask, irq_mask_addr);
-}
-
static void bcm63xx_internal_irq_mask(struct irq_data *d)
{
internal_irq_mask(d->irq - IRQ_INTERNAL_BASE);
reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
break;
+ case BCM3368_CPU_ID:
case BCM6328_CPU_ID:
case BCM6338_CPU_ID:
case BCM6345_CPU_ID:
.flags = IRQF_NO_THREAD,
};
+static void bcm63xx_init_irq(void)
+{
+ int irq_bits;
+
+ irq_stat_addr[0] = bcm63xx_regset_address(RSET_PERF);
+ irq_mask_addr[0] = bcm63xx_regset_address(RSET_PERF);
+ irq_stat_addr[1] = bcm63xx_regset_address(RSET_PERF);
+ irq_mask_addr[1] = bcm63xx_regset_address(RSET_PERF);
+
+ switch (bcm63xx_get_cpu_id()) {
+ case BCM3368_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_3368_REG;
+ irq_mask_addr[0] += PERF_IRQMASK_3368_REG;
+ irq_stat_addr[1] = 0;
+ irq_stat_addr[1] = 0;
+ irq_bits = 32;
+ ext_irq_count = 4;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368;
+ break;
+ case BCM6328_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6328_REG(0);
+ irq_mask_addr[0] += PERF_IRQMASK_6328_REG(0);
+ irq_stat_addr[1] += PERF_IRQSTAT_6328_REG(1);
+ irq_stat_addr[1] += PERF_IRQMASK_6328_REG(1);
+ irq_bits = 64;
+ ext_irq_count = 4;
+ is_ext_irq_cascaded = 1;
+ ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+ ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
+ break;
+ case BCM6338_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6338_REG;
+ irq_mask_addr[0] += PERF_IRQMASK_6338_REG;
+ irq_stat_addr[1] = 0;
+ irq_mask_addr[1] = 0;
+ irq_bits = 32;
+ ext_irq_count = 4;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338;
+ break;
+ case BCM6345_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6345_REG;
+ irq_mask_addr[0] += PERF_IRQMASK_6345_REG;
+ irq_stat_addr[1] = 0;
+ irq_mask_addr[1] = 0;
+ irq_bits = 32;
+ ext_irq_count = 4;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345;
+ break;
+ case BCM6348_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6348_REG;
+ irq_mask_addr[0] += PERF_IRQMASK_6348_REG;
+ irq_stat_addr[1] = 0;
+ irq_mask_addr[1] = 0;
+ irq_bits = 32;
+ ext_irq_count = 4;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
+ break;
+ case BCM6358_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6358_REG(0);
+ irq_mask_addr[0] += PERF_IRQMASK_6358_REG(0);
+ irq_stat_addr[1] += PERF_IRQSTAT_6358_REG(1);
+ irq_mask_addr[1] += PERF_IRQMASK_6358_REG(1);
+ 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;
+ case BCM6362_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6362_REG(0);
+ irq_mask_addr[0] += PERF_IRQMASK_6362_REG(0);
+ irq_stat_addr[1] += PERF_IRQSTAT_6362_REG(1);
+ irq_mask_addr[1] += PERF_IRQMASK_6362_REG(1);
+ irq_bits = 64;
+ ext_irq_count = 4;
+ is_ext_irq_cascaded = 1;
+ ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+ ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362;
+ break;
+ case BCM6368_CPU_ID:
+ irq_stat_addr[0] += PERF_IRQSTAT_6368_REG(0);
+ irq_mask_addr[0] += PERF_IRQMASK_6368_REG(0);
+ irq_stat_addr[1] += PERF_IRQSTAT_6368_REG(1);
+ irq_mask_addr[1] += PERF_IRQMASK_6368_REG(1);
+ irq_bits = 64;
+ ext_irq_count = 6;
+ is_ext_irq_cascaded = 1;
+ ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+ ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
+ ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
+ ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
+ break;
+ default:
+ BUG();
+ }
+
+ if (irq_bits == 32) {
+ dispatch_internal = __dispatch_internal_32;
+ internal_irq_mask = __internal_irq_mask_32;
+ internal_irq_unmask = __internal_irq_unmask_32;
+ } else {
+ dispatch_internal = __dispatch_internal_64;
+ internal_irq_mask = __internal_irq_mask_64;
+ internal_irq_unmask = __internal_irq_unmask_64;
+ }
+}
+
void __init arch_init_irq(void)
{
int i;