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