162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/kernel.h> 662306a36Sopenharmony_ci#include <linux/init.h> 762306a36Sopenharmony_ci#include <linux/linkage.h> 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/smp.h> 1062306a36Sopenharmony_ci#include <linux/spinlock.h> 1162306a36Sopenharmony_ci#include <linux/mm.h> 1262306a36Sopenharmony_ci#include <linux/kernel_stat.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <asm/errno.h> 1562306a36Sopenharmony_ci#include <asm/irq_regs.h> 1662306a36Sopenharmony_ci#include <asm/signal.h> 1762306a36Sopenharmony_ci#include <asm/io.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <asm/sibyte/bcm1480_regs.h> 2062306a36Sopenharmony_ci#include <asm/sibyte/bcm1480_int.h> 2162306a36Sopenharmony_ci#include <asm/sibyte/bcm1480_scd.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <asm/sibyte/sb1250_uart.h> 2462306a36Sopenharmony_ci#include <asm/sibyte/sb1250.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * These are the routines that handle all the low level interrupt stuff. 2862306a36Sopenharmony_ci * Actions handled here are: initialization of the interrupt map, requesting of 2962306a36Sopenharmony_ci * interrupt lines by handlers, dispatching if interrupts to handlers, probing 3062306a36Sopenharmony_ci * for interrupt lines 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#ifdef CONFIG_PCI 3462306a36Sopenharmony_ciextern unsigned long ht_eoi_space; 3562306a36Sopenharmony_ci#endif 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Store the CPU id (not the logical number) */ 3862306a36Sopenharmony_ciint bcm1480_irq_owner[BCM1480_NR_IRQS]; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(bcm1480_imr_lock); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_civoid bcm1480_mask_irq(int cpu, int irq) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci unsigned long flags, hl_spacing; 4562306a36Sopenharmony_ci u64 cur_ints; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci raw_spin_lock_irqsave(&bcm1480_imr_lock, flags); 4862306a36Sopenharmony_ci hl_spacing = 0; 4962306a36Sopenharmony_ci if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) { 5062306a36Sopenharmony_ci hl_spacing = BCM1480_IMR_HL_SPACING; 5162306a36Sopenharmony_ci irq -= BCM1480_NR_IRQS_HALF; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); 5462306a36Sopenharmony_ci cur_ints |= (((u64) 1) << irq); 5562306a36Sopenharmony_ci ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); 5662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_civoid bcm1480_unmask_irq(int cpu, int irq) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci unsigned long flags, hl_spacing; 6262306a36Sopenharmony_ci u64 cur_ints; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci raw_spin_lock_irqsave(&bcm1480_imr_lock, flags); 6562306a36Sopenharmony_ci hl_spacing = 0; 6662306a36Sopenharmony_ci if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) { 6762306a36Sopenharmony_ci hl_spacing = BCM1480_IMR_HL_SPACING; 6862306a36Sopenharmony_ci irq -= BCM1480_NR_IRQS_HALF; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); 7162306a36Sopenharmony_ci cur_ints &= ~(((u64) 1) << irq); 7262306a36Sopenharmony_ci ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing)); 7362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#ifdef CONFIG_SMP 7762306a36Sopenharmony_cistatic int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask, 7862306a36Sopenharmony_ci bool force) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci unsigned int irq_dirty, irq = d->irq; 8162306a36Sopenharmony_ci int i = 0, old_cpu, cpu, int_on, k; 8262306a36Sopenharmony_ci u64 cur_ints; 8362306a36Sopenharmony_ci unsigned long flags; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci i = cpumask_first_and(mask, cpu_online_mask); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Convert logical CPU to physical CPU */ 8862306a36Sopenharmony_ci cpu = cpu_logical_map(i); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* Protect against other affinity changers and IMR manipulation */ 9162306a36Sopenharmony_ci raw_spin_lock_irqsave(&bcm1480_imr_lock, flags); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Swizzle each CPU's IMR (but leave the IP selection alone) */ 9462306a36Sopenharmony_ci old_cpu = bcm1480_irq_owner[irq]; 9562306a36Sopenharmony_ci irq_dirty = irq; 9662306a36Sopenharmony_ci if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) { 9762306a36Sopenharmony_ci irq_dirty -= BCM1480_NR_IRQS_HALF; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci for (k=0; k<2; k++) { /* Loop through high and low interrupt mask register */ 10162306a36Sopenharmony_ci cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING))); 10262306a36Sopenharmony_ci int_on = !(cur_ints & (((u64) 1) << irq_dirty)); 10362306a36Sopenharmony_ci if (int_on) { 10462306a36Sopenharmony_ci /* If it was on, mask it */ 10562306a36Sopenharmony_ci cur_ints |= (((u64) 1) << irq_dirty); 10662306a36Sopenharmony_ci ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING))); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci bcm1480_irq_owner[irq] = cpu; 10962306a36Sopenharmony_ci if (int_on) { 11062306a36Sopenharmony_ci /* unmask for the new CPU */ 11162306a36Sopenharmony_ci cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING))); 11262306a36Sopenharmony_ci cur_ints &= ~(((u64) 1) << irq_dirty); 11362306a36Sopenharmony_ci ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING))); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&bcm1480_imr_lock, flags); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci#endif 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/*****************************************************************************/ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void disable_bcm1480_irq(struct irq_data *d) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci unsigned int irq = d->irq; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic void enable_bcm1480_irq(struct irq_data *d) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci unsigned int irq = d->irq; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void ack_bcm1480_irq(struct irq_data *d) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci unsigned int irq_dirty, irq = d->irq; 14362306a36Sopenharmony_ci u64 pending; 14462306a36Sopenharmony_ci int k; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * If the interrupt was an HT interrupt, now is the time to 14862306a36Sopenharmony_ci * clear it. NOTE: we assume the HT bridge was set up to 14962306a36Sopenharmony_ci * deliver the interrupts to all CPUs (which makes affinity 15062306a36Sopenharmony_ci * changing easier for us) 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci irq_dirty = irq; 15362306a36Sopenharmony_ci if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) { 15462306a36Sopenharmony_ci irq_dirty -= BCM1480_NR_IRQS_HALF; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci for (k=0; k<2; k++) { /* Loop through high and low LDT interrupts */ 15762306a36Sopenharmony_ci pending = __raw_readq(IOADDR(A_BCM1480_IMR_REGISTER(bcm1480_irq_owner[irq], 15862306a36Sopenharmony_ci R_BCM1480_IMR_LDT_INTERRUPT_H + (k*BCM1480_IMR_HL_SPACING)))); 15962306a36Sopenharmony_ci pending &= ((u64)1 << (irq_dirty)); 16062306a36Sopenharmony_ci if (pending) { 16162306a36Sopenharmony_ci#ifdef CONFIG_SMP 16262306a36Sopenharmony_ci int i; 16362306a36Sopenharmony_ci for (i=0; i<NR_CPUS; i++) { 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * Clear for all CPUs so an affinity switch 16662306a36Sopenharmony_ci * doesn't find an old status 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci __raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(cpu_logical_map(i), 16962306a36Sopenharmony_ci R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING)))); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci#else 17262306a36Sopenharmony_ci __raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING)))); 17362306a36Sopenharmony_ci#endif 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* 17662306a36Sopenharmony_ci * Generate EOI. For Pass 1 parts, EOI is a nop. For 17762306a36Sopenharmony_ci * Pass 2, the LDT world may be edge-triggered, but 17862306a36Sopenharmony_ci * this EOI shouldn't hurt. If they are 17962306a36Sopenharmony_ci * level-sensitive, the EOI is required. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci#ifdef CONFIG_PCI 18262306a36Sopenharmony_ci if (ht_eoi_space) 18362306a36Sopenharmony_ci *(uint32_t *)(ht_eoi_space+(irq<<16)+(7<<2)) = 0; 18462306a36Sopenharmony_ci#endif 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic struct irq_chip bcm1480_irq_type = { 19162306a36Sopenharmony_ci .name = "BCM1480-IMR", 19262306a36Sopenharmony_ci .irq_mask_ack = ack_bcm1480_irq, 19362306a36Sopenharmony_ci .irq_mask = disable_bcm1480_irq, 19462306a36Sopenharmony_ci .irq_unmask = enable_bcm1480_irq, 19562306a36Sopenharmony_ci#ifdef CONFIG_SMP 19662306a36Sopenharmony_ci .irq_set_affinity = bcm1480_set_affinity 19762306a36Sopenharmony_ci#endif 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_civoid __init init_bcm1480_irqs(void) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci int i; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci for (i = 0; i < BCM1480_NR_IRQS; i++) { 20562306a36Sopenharmony_ci irq_set_chip_and_handler(i, &bcm1480_irq_type, 20662306a36Sopenharmony_ci handle_level_irq); 20762306a36Sopenharmony_ci bcm1480_irq_owner[i] = 0; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/* 21262306a36Sopenharmony_ci * init_IRQ is called early in the boot sequence from init/main.c. It 21362306a36Sopenharmony_ci * is responsible for setting up the interrupt mapper and installing the 21462306a36Sopenharmony_ci * handler that will be responsible for dispatching interrupts to the 21562306a36Sopenharmony_ci * "right" place. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * For now, map all interrupts to IP[2]. We could save 21962306a36Sopenharmony_ci * some cycles by parceling out system interrupts to different 22062306a36Sopenharmony_ci * IP lines, but keep it simple for bringup. We'll also direct 22162306a36Sopenharmony_ci * all interrupts to a single CPU; we should probably route 22262306a36Sopenharmony_ci * PCI and LDT to one cpu and everything else to the other 22362306a36Sopenharmony_ci * to balance the load a bit. 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * On the second cpu, everything is set to IP5, which is 22662306a36Sopenharmony_ci * ignored, EXCEPT the mailbox interrupt. That one is 22762306a36Sopenharmony_ci * set to IP[2] so it is handled. This is needed so we 22862306a36Sopenharmony_ci * can do cross-cpu function calls, as required by SMP 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci#define IMR_IP2_VAL K_BCM1480_INT_MAP_I0 23262306a36Sopenharmony_ci#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 23362306a36Sopenharmony_ci#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 23462306a36Sopenharmony_ci#define IMR_IP5_VAL K_BCM1480_INT_MAP_I3 23562306a36Sopenharmony_ci#define IMR_IP6_VAL K_BCM1480_INT_MAP_I4 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_civoid __init arch_init_irq(void) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci unsigned int i, cpu; 24062306a36Sopenharmony_ci u64 tmp; 24162306a36Sopenharmony_ci unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | 24262306a36Sopenharmony_ci STATUSF_IP1 | STATUSF_IP0; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* Default everything to IP2 */ 24562306a36Sopenharmony_ci /* Start with _high registers which has no bit 0 interrupt source */ 24662306a36Sopenharmony_ci for (i = 1; i < BCM1480_NR_IRQS_HALF; i++) { /* was I0 */ 24762306a36Sopenharmony_ci for (cpu = 0; cpu < 4; cpu++) { 24862306a36Sopenharmony_ci __raw_writeq(IMR_IP2_VAL, 24962306a36Sopenharmony_ci IOADDR(A_BCM1480_IMR_REGISTER(cpu, 25062306a36Sopenharmony_ci R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (i << 3))); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* Now do _low registers */ 25562306a36Sopenharmony_ci for (i = 0; i < BCM1480_NR_IRQS_HALF; i++) { 25662306a36Sopenharmony_ci for (cpu = 0; cpu < 4; cpu++) { 25762306a36Sopenharmony_ci __raw_writeq(IMR_IP2_VAL, 25862306a36Sopenharmony_ci IOADDR(A_BCM1480_IMR_REGISTER(cpu, 25962306a36Sopenharmony_ci R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) + (i << 3))); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci init_bcm1480_irqs(); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * Map the high 16 bits of mailbox_0 registers to IP[3], for 26762306a36Sopenharmony_ci * inter-cpu messages 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci /* Was I1 */ 27062306a36Sopenharmony_ci for (cpu = 0; cpu < 4; cpu++) { 27162306a36Sopenharmony_ci __raw_writeq(IMR_IP3_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + 27262306a36Sopenharmony_ci (K_BCM1480_INT_MBOX_0_0 << 3))); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Clear the mailboxes. The firmware may leave them dirty */ 27762306a36Sopenharmony_ci for (cpu = 0; cpu < 4; cpu++) { 27862306a36Sopenharmony_ci __raw_writeq(0xffffffffffffffffULL, 27962306a36Sopenharmony_ci IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_0_CLR_CPU))); 28062306a36Sopenharmony_ci __raw_writeq(0xffffffffffffffffULL, 28162306a36Sopenharmony_ci IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_MAILBOX_1_CLR_CPU))); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* Mask everything except the high 16 bit of mailbox_0 registers for all cpus */ 28662306a36Sopenharmony_ci tmp = ~((u64) 0) ^ ( (((u64) 1) << K_BCM1480_INT_MBOX_0_0)); 28762306a36Sopenharmony_ci for (cpu = 0; cpu < 4; cpu++) { 28862306a36Sopenharmony_ci __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_H))); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci tmp = ~((u64) 0); 29162306a36Sopenharmony_ci for (cpu = 0; cpu < 4; cpu++) { 29262306a36Sopenharmony_ci __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_L))); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* 29662306a36Sopenharmony_ci * Note that the timer interrupts are also mapped, but this is 29762306a36Sopenharmony_ci * done in bcm1480_time_init(). Also, the profiling driver 29862306a36Sopenharmony_ci * does its own management of IP7. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Enable necessary IPs, disable the rest */ 30262306a36Sopenharmony_ci change_c0_status(ST0_IM, imask); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciextern void bcm1480_mailbox_interrupt(void); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic inline void dispatch_ip2(void) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci unsigned long long mask_h, mask_l; 31062306a36Sopenharmony_ci unsigned int cpu = smp_processor_id(); 31162306a36Sopenharmony_ci unsigned long base; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* 31462306a36Sopenharmony_ci * Default...we've hit an IP[2] interrupt, which means we've got to 31562306a36Sopenharmony_ci * check the 1480 interrupt registers to figure out what to do. Need 31662306a36Sopenharmony_ci * to detect which CPU we're on, now that smp_affinity is supported. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci base = A_BCM1480_IMR_MAPPER(cpu); 31962306a36Sopenharmony_ci mask_h = __raw_readq( 32062306a36Sopenharmony_ci IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); 32162306a36Sopenharmony_ci mask_l = __raw_readq( 32262306a36Sopenharmony_ci IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (mask_h) { 32562306a36Sopenharmony_ci if (mask_h ^ 1) 32662306a36Sopenharmony_ci do_IRQ(fls64(mask_h) - 1); 32762306a36Sopenharmony_ci else if (mask_l) 32862306a36Sopenharmony_ci do_IRQ(63 + fls64(mask_l)); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciasmlinkage void plat_irq_dispatch(void) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci unsigned int cpu = smp_processor_id(); 33562306a36Sopenharmony_ci unsigned int pending; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci pending = read_c0_cause() & read_c0_status(); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (pending & CAUSEF_IP4) 34062306a36Sopenharmony_ci do_IRQ(K_BCM1480_INT_TIMER_0 + cpu); 34162306a36Sopenharmony_ci#ifdef CONFIG_SMP 34262306a36Sopenharmony_ci else if (pending & CAUSEF_IP3) 34362306a36Sopenharmony_ci bcm1480_mailbox_interrupt(); 34462306a36Sopenharmony_ci#endif 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci else if (pending & CAUSEF_IP2) 34762306a36Sopenharmony_ci dispatch_ip2(); 34862306a36Sopenharmony_ci} 349