xref: /openbmc/linux/arch/mips/kernel/irq-msc01.c (revision ab6c15bc6620ebe220970cc040b29bcb2757f373)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * This program is free software; you can redistribute	it and/or modify it
31da177e4SLinus Torvalds  * under  the terms of	the GNU General	 Public License as published by the
41da177e4SLinus Torvalds  * Free Software Foundation;  either version 2 of the  License, or (at your
51da177e4SLinus Torvalds  * option) any later version.
627f76819SRalf Baechle  *
727f76819SRalf Baechle  * Copyright (c) 2004 MIPS Inc
827f76819SRalf Baechle  * Author: chris@mips.com
927f76819SRalf Baechle  *
1027f76819SRalf Baechle  * Copyright (C) 2004, 06 Ralf Baechle <ralf@linux-mips.org>
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds #include <linux/interrupt.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/sched.h>
151da177e4SLinus Torvalds #include <linux/kernel_stat.h>
161da177e4SLinus Torvalds #include <asm/io.h>
171da177e4SLinus Torvalds #include <asm/irq.h>
181da177e4SLinus Torvalds #include <asm/msc01_ic.h>
19411ba7fcSAtsushi Nemoto #include <asm/traps.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds static unsigned long _icctrl_msc;
221da177e4SLinus Torvalds #define MSC01_IC_REG_BASE	_icctrl_msc
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #define MSCIC_WRITE(reg, data)	do { *(volatile u32 *)(reg) = data; } while (0)
251da177e4SLinus Torvalds #define MSCIC_READ(reg, data)	do { data = *(volatile u32 *)(reg); } while (0)
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds static unsigned int irq_base;
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds /* mask off an interrupt */
30e15883daSThomas Gleixner static inline void mask_msc_irq(struct irq_data *d)
311da177e4SLinus Torvalds {
32e15883daSThomas Gleixner 	unsigned int irq = d->irq;
33e15883daSThomas Gleixner 
341da177e4SLinus Torvalds 	if (irq < (irq_base + 32))
351da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base));
361da177e4SLinus Torvalds 	else
371da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32));
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds /* unmask an interrupt */
41e15883daSThomas Gleixner static inline void unmask_msc_irq(struct irq_data *d)
421da177e4SLinus Torvalds {
43e15883daSThomas Gleixner 	unsigned int irq = d->irq;
44e15883daSThomas Gleixner 
451da177e4SLinus Torvalds 	if (irq < (irq_base + 32))
461da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base));
471da177e4SLinus Torvalds 	else
481da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32));
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds /*
521da177e4SLinus Torvalds  * Masks and ACKs an IRQ
531da177e4SLinus Torvalds  */
54e15883daSThomas Gleixner static void level_mask_and_ack_msc_irq(struct irq_data *d)
551da177e4SLinus Torvalds {
56e15883daSThomas Gleixner 	mask_msc_irq(d);
57e01402b1SRalf Baechle 	if (!cpu_has_veic)
581da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_EOI, 0);
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds  * Masks and ACKs an IRQ
631da177e4SLinus Torvalds  */
64e15883daSThomas Gleixner static void edge_mask_and_ack_msc_irq(struct irq_data *d)
651da177e4SLinus Torvalds {
66e15883daSThomas Gleixner 	unsigned int irq = d->irq;
67e15883daSThomas Gleixner 
68e15883daSThomas Gleixner 	mask_msc_irq(d);
69e01402b1SRalf Baechle 	if (!cpu_has_veic)
701da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_EOI, 0);
711da177e4SLinus Torvalds 	else {
721da177e4SLinus Torvalds 		u32 r;
731da177e4SLinus Torvalds 		MSCIC_READ(MSC01_IC_SUP+irq*8, r);
741da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
751da177e4SLinus Torvalds 		MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
761da177e4SLinus Torvalds 	}
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds /*
801da177e4SLinus Torvalds  * Interrupt handler for interrupts coming from SOC-it.
811da177e4SLinus Torvalds  */
82937a8015SRalf Baechle void ll_msc_irq(void)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds 	unsigned int irq;
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	/* read the interrupt vector register */
871da177e4SLinus Torvalds 	MSCIC_READ(MSC01_IC_VEC, irq);
881da177e4SLinus Torvalds 	if (irq < 64)
89937a8015SRalf Baechle 		do_IRQ(irq + irq_base);
901da177e4SLinus Torvalds 	else {
911da177e4SLinus Torvalds 		/* Ignore spurious interrupt */
921da177e4SLinus Torvalds 	}
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
95411ba7fcSAtsushi Nemoto static void msc_bind_eic_interrupt(int irq, int set)
961da177e4SLinus Torvalds {
971da177e4SLinus Torvalds 	MSCIC_WRITE(MSC01_IC_RAMW,
981da177e4SLinus Torvalds 		    (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF));
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds 
101411ba7fcSAtsushi Nemoto static struct irq_chip msc_levelirq_type = {
10270d21cdeSAtsushi Nemoto 	.name = "SOC-it-Level",
103e15883daSThomas Gleixner 	.irq_ack = level_mask_and_ack_msc_irq,
104e15883daSThomas Gleixner 	.irq_mask = mask_msc_irq,
105e15883daSThomas Gleixner 	.irq_mask_ack = level_mask_and_ack_msc_irq,
106e15883daSThomas Gleixner 	.irq_unmask = unmask_msc_irq,
107e15883daSThomas Gleixner 	.irq_eoi = unmask_msc_irq,
1081da177e4SLinus Torvalds };
1091da177e4SLinus Torvalds 
110411ba7fcSAtsushi Nemoto static struct irq_chip msc_edgeirq_type = {
11170d21cdeSAtsushi Nemoto 	.name = "SOC-it-Edge",
112e15883daSThomas Gleixner 	.irq_ack = edge_mask_and_ack_msc_irq,
113e15883daSThomas Gleixner 	.irq_mask = mask_msc_irq,
114e15883daSThomas Gleixner 	.irq_mask_ack = edge_mask_and_ack_msc_irq,
115e15883daSThomas Gleixner 	.irq_unmask = unmask_msc_irq,
116e15883daSThomas Gleixner 	.irq_eoi = unmask_msc_irq,
1171da177e4SLinus Torvalds };
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 
120d725cf38SChris Dearman void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq)
1211da177e4SLinus Torvalds {
122d725cf38SChris Dearman 	_icctrl_msc = (unsigned long) ioremap(icubase, 0x40000);
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	/* Reset interrupt controller - initialises all registers to 0 */
1251da177e4SLinus Torvalds 	MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT);
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	board_bind_eic_interrupt = &msc_bind_eic_interrupt;
1281da177e4SLinus Torvalds 
129*ab6c15bcSMarkos Chandras 	for (; nirq > 0; nirq--, imp++) {
1301da177e4SLinus Torvalds 		int n = imp->im_irq;
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 		switch (imp->im_type) {
1331da177e4SLinus Torvalds 		case MSC01_IRQ_EDGE:
134e4ec7989SThomas Gleixner 			irq_set_chip_and_handler_name(irqbase + n,
135e4ec7989SThomas Gleixner 						      &msc_edgeirq_type,
136e4ec7989SThomas Gleixner 						      handle_edge_irq,
137e4ec7989SThomas Gleixner 						      "edge");
138e01402b1SRalf Baechle 			if (cpu_has_veic)
1391da177e4SLinus Torvalds 				MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT);
1401da177e4SLinus Torvalds 			else
1411da177e4SLinus Torvalds 				MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl);
1421da177e4SLinus Torvalds 			break;
1431da177e4SLinus Torvalds 		case MSC01_IRQ_LEVEL:
144e4ec7989SThomas Gleixner 			irq_set_chip_and_handler_name(irqbase + n,
145e4ec7989SThomas Gleixner 						      &msc_levelirq_type,
146e4ec7989SThomas Gleixner 						      handle_level_irq,
147e4ec7989SThomas Gleixner 						      "level");
148e01402b1SRalf Baechle 			if (cpu_has_veic)
1491da177e4SLinus Torvalds 				MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
1501da177e4SLinus Torvalds 			else
1511da177e4SLinus Torvalds 				MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl);
1521da177e4SLinus Torvalds 		}
1531da177e4SLinus Torvalds 	}
1541da177e4SLinus Torvalds 
155d725cf38SChris Dearman 	irq_base = irqbase;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT);	/* Enable interrupt generation */
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds }
160