18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Interrupt handing routines for NEC VR4100 series.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2005-2007  Yoichi Yuasa <yuasa@linux-mips.org>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/export.h>
88c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
98c2ecf20Sopenharmony_ci#include <linux/irq.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/irq_cpu.h>
128c2ecf20Sopenharmony_ci#include <asm/vr41xx/irq.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_citypedef struct irq_cascade {
158c2ecf20Sopenharmony_ci	int (*get_irq)(unsigned int);
168c2ecf20Sopenharmony_ci} irq_cascade_t;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ciint cascade_irq(unsigned int irq, int (*get_irq)(unsigned int))
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	int retval = 0;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	if (irq >= NR_IRQS)
258c2ecf20Sopenharmony_ci		return -EINVAL;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	if (irq_cascade[irq].get_irq != NULL)
288c2ecf20Sopenharmony_ci		free_irq(irq, NULL);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	irq_cascade[irq].get_irq = get_irq;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (get_irq != NULL) {
338c2ecf20Sopenharmony_ci		retval = request_irq(irq, no_action, IRQF_NO_THREAD,
348c2ecf20Sopenharmony_ci				     "cascade", NULL);
358c2ecf20Sopenharmony_ci		if (retval < 0)
368c2ecf20Sopenharmony_ci			irq_cascade[irq].get_irq = NULL;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return retval;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cascade_irq);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic void irq_dispatch(unsigned int irq)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	irq_cascade_t *cascade;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (irq >= NR_IRQS) {
498c2ecf20Sopenharmony_ci		atomic_inc(&irq_err_count);
508c2ecf20Sopenharmony_ci		return;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	cascade = irq_cascade + irq;
548c2ecf20Sopenharmony_ci	if (cascade->get_irq != NULL) {
558c2ecf20Sopenharmony_ci		struct irq_desc *desc = irq_to_desc(irq);
568c2ecf20Sopenharmony_ci		struct irq_data *idata = irq_desc_get_irq_data(desc);
578c2ecf20Sopenharmony_ci		struct irq_chip *chip = irq_desc_get_chip(desc);
588c2ecf20Sopenharmony_ci		int ret;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		if (chip->irq_mask_ack)
618c2ecf20Sopenharmony_ci			chip->irq_mask_ack(idata);
628c2ecf20Sopenharmony_ci		else {
638c2ecf20Sopenharmony_ci			chip->irq_mask(idata);
648c2ecf20Sopenharmony_ci			chip->irq_ack(idata);
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci		ret = cascade->get_irq(irq);
678c2ecf20Sopenharmony_ci		irq = ret;
688c2ecf20Sopenharmony_ci		if (ret < 0)
698c2ecf20Sopenharmony_ci			atomic_inc(&irq_err_count);
708c2ecf20Sopenharmony_ci		else
718c2ecf20Sopenharmony_ci			irq_dispatch(irq);
728c2ecf20Sopenharmony_ci		if (!irqd_irq_disabled(idata) && chip->irq_unmask)
738c2ecf20Sopenharmony_ci			chip->irq_unmask(idata);
748c2ecf20Sopenharmony_ci	} else
758c2ecf20Sopenharmony_ci		do_IRQ(irq);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciasmlinkage void plat_irq_dispatch(void)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (pending & CAUSEF_IP7)
838c2ecf20Sopenharmony_ci		do_IRQ(TIMER_IRQ);
848c2ecf20Sopenharmony_ci	else if (pending & 0x7800) {
858c2ecf20Sopenharmony_ci		if (pending & CAUSEF_IP3)
868c2ecf20Sopenharmony_ci			irq_dispatch(INT1_IRQ);
878c2ecf20Sopenharmony_ci		else if (pending & CAUSEF_IP4)
888c2ecf20Sopenharmony_ci			irq_dispatch(INT2_IRQ);
898c2ecf20Sopenharmony_ci		else if (pending & CAUSEF_IP5)
908c2ecf20Sopenharmony_ci			irq_dispatch(INT3_IRQ);
918c2ecf20Sopenharmony_ci		else if (pending & CAUSEF_IP6)
928c2ecf20Sopenharmony_ci			irq_dispatch(INT4_IRQ);
938c2ecf20Sopenharmony_ci	} else if (pending & CAUSEF_IP2)
948c2ecf20Sopenharmony_ci		irq_dispatch(INT0_IRQ);
958c2ecf20Sopenharmony_ci	else if (pending & CAUSEF_IP0)
968c2ecf20Sopenharmony_ci		do_IRQ(MIPS_SOFTINT0_IRQ);
978c2ecf20Sopenharmony_ci	else if (pending & CAUSEF_IP1)
988c2ecf20Sopenharmony_ci		do_IRQ(MIPS_SOFTINT1_IRQ);
998c2ecf20Sopenharmony_ci	else
1008c2ecf20Sopenharmony_ci		spurious_interrupt();
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_civoid __init arch_init_irq(void)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	mips_cpu_irq_init();
1068c2ecf20Sopenharmony_ci}
107