• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/mips/pmc-sierra/msp71xx/
1/*
2 * This file define the irq handler for MSP SLM subsystem interrupts.
3 *
4 * Copyright 2005-2007 PMC-Sierra, Inc, derived from irq_cpu.c
5 * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
6 *
7 * This program is free software; you can redistribute  it and/or modify it
8 * under  the terms of  the GNU General  Public License as published by the
9 * Free Software Foundation;  either version 2 of the  License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/kernel.h>
16#include <linux/bitops.h>
17
18#include <asm/system.h>
19
20#include <msp_cic_int.h>
21#include <msp_regs.h>
22
23/*
24 * NOTE: We are only enabling support for VPE0 right now.
25 */
26
27static inline void unmask_msp_cic_irq(unsigned int irq)
28{
29
30	/* check for PER interrupt range */
31	if (irq < MSP_PER_INTBASE)
32		*CIC_VPE0_MSK_REG |= (1 << (irq - MSP_CIC_INTBASE));
33	else
34		*PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
35}
36
37static inline void mask_msp_cic_irq(unsigned int irq)
38{
39	/* check for PER interrupt range */
40	if (irq < MSP_PER_INTBASE)
41		*CIC_VPE0_MSK_REG &= ~(1 << (irq - MSP_CIC_INTBASE));
42	else
43		*PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
44}
45
46/*
47 * While we ack the interrupt interrupts are disabled and thus we don't need
48 * to deal with concurrency issues.  Same for msp_cic_irq_end.
49 */
50static inline void ack_msp_cic_irq(unsigned int irq)
51{
52	mask_msp_cic_irq(irq);
53
54	/*
55	 * only really necessary for 18, 16-14 and sometimes 3:0 (since
56	 * these can be edge sensitive) but it doesn't hurt for the others.
57	 */
58
59	/* check for PER interrupt range */
60	if (irq < MSP_PER_INTBASE)
61		*CIC_STS_REG = (1 << (irq - MSP_CIC_INTBASE));
62	else
63		*PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
64}
65
66static struct irq_chip msp_cic_irq_controller = {
67	.name = "MSP_CIC",
68	.ack = ack_msp_cic_irq,
69	.mask = ack_msp_cic_irq,
70	.mask_ack = ack_msp_cic_irq,
71	.unmask = unmask_msp_cic_irq,
72};
73
74
75void __init msp_cic_irq_init(void)
76{
77	int i;
78
79	/* Mask/clear interrupts. */
80	*CIC_VPE0_MSK_REG = 0x00000000;
81	*PER_INT_MSK_REG  = 0x00000000;
82	*CIC_STS_REG      = 0xFFFFFFFF;
83	*PER_INT_STS_REG  = 0xFFFFFFFF;
84
85#if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL)
86	/*
87	 * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
88	 * These inputs map to EXT_INT_POL[6:4] inside the CIC.
89	 * They are to be active low, level sensitive.
90	 */
91	*CIC_EXT_CFG_REG &= 0xFFFF8F8F;
92#endif
93
94	/* initialize all the IRQ descriptors */
95	for (i = MSP_CIC_INTBASE; i < MSP_PER_INTBASE + 32; i++)
96		set_irq_chip_and_handler(i, &msp_cic_irq_controller,
97					 handle_level_irq);
98}
99
100void msp_cic_irq_dispatch(void)
101{
102	u32 pending;
103	int intbase;
104
105	intbase = MSP_CIC_INTBASE;
106	pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG;
107
108	/* check for PER interrupt */
109	if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
110		intbase = MSP_PER_INTBASE;
111		pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
112	}
113
114	/* check for spurious interrupt */
115	if (pending == 0x00000000) {
116		printk(KERN_ERR
117			"Spurious %s interrupt? status %08x, mask %08x\n",
118			(intbase == MSP_CIC_INTBASE) ? "CIC" : "PER",
119			(intbase == MSP_CIC_INTBASE) ?
120				*CIC_STS_REG : *PER_INT_STS_REG,
121			(intbase == MSP_CIC_INTBASE) ?
122				*CIC_VPE0_MSK_REG : *PER_INT_MSK_REG);
123		return;
124	}
125
126	/* check for the timer and dispatch it first */
127	if ((intbase == MSP_CIC_INTBASE) &&
128	    (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))))
129		do_IRQ(MSP_INT_VPE0_TIMER);
130	else
131		do_IRQ(ffs(pending) + intbase - 1);
132}
133