• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/mips/kernel/
1/*
2 * Based on linux/arch/mips/jmr3927/rbhma3100/irq.c,
3 *          linux/arch/mips/tx4927/common/tx4927_irq.c,
4 *          linux/arch/mips/tx4938/common/irq.c
5 *
6 * Copyright 2001, 2003-2005 MontaVista Software Inc.
7 * Author: MontaVista Software, Inc.
8 *         ahennessy@mvista.com
9 *         source@mvista.com
10 * Copyright (C) 2000-2001 Toshiba Corporation
11 *
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License.  See the file "COPYING" in the main directory of this archive
14 * for more details.
15 */
16#include <linux/init.h>
17#include <linux/interrupt.h>
18#include <linux/types.h>
19#include <asm/txx9irq.h>
20
21struct txx9_irc_reg {
22	u32 cer;
23	u32 cr[2];
24	u32 unused0;
25	u32 ilr[8];
26	u32 unused1[4];
27	u32 imr;
28	u32 unused2[7];
29	u32 scr;
30	u32 unused3[7];
31	u32 ssr;
32	u32 unused4[7];
33	u32 csr;
34};
35
36/* IRCER : Int. Control Enable */
37#define TXx9_IRCER_ICE	0x00000001
38
39/* IRCR : Int. Control */
40#define TXx9_IRCR_LOW	0x00000000
41#define TXx9_IRCR_HIGH	0x00000001
42#define TXx9_IRCR_DOWN	0x00000002
43#define TXx9_IRCR_UP	0x00000003
44#define TXx9_IRCR_EDGE(cr)	((cr) & 0x00000002)
45
46/* IRSCR : Int. Status Control */
47#define TXx9_IRSCR_EIClrE	0x00000100
48#define TXx9_IRSCR_EIClr_MASK	0x0000000f
49
50/* IRCSR : Int. Current Status */
51#define TXx9_IRCSR_IF	0x00010000
52#define TXx9_IRCSR_ILV_MASK	0x00000700
53#define TXx9_IRCSR_IVL_MASK	0x0000001f
54
55#define irc_dlevel	0
56#define irc_elevel	1
57
58static struct txx9_irc_reg __iomem *txx9_ircptr __read_mostly;
59
60static struct {
61	unsigned char level;
62	unsigned char mode;
63} txx9irq[TXx9_MAX_IR] __read_mostly;
64
65static void txx9_irq_unmask(unsigned int irq)
66{
67	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
68	u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2];
69	int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8;
70
71	__raw_writel((__raw_readl(ilrp) & ~(0xff << ofs))
72		     | (txx9irq[irq_nr].level << ofs),
73		     ilrp);
74#ifdef CONFIG_CPU_TX39XX
75	/* update IRCSR */
76	__raw_writel(0, &txx9_ircptr->imr);
77	__raw_writel(irc_elevel, &txx9_ircptr->imr);
78#endif
79}
80
81static inline void txx9_irq_mask(unsigned int irq)
82{
83	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
84	u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2];
85	int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8;
86
87	__raw_writel((__raw_readl(ilrp) & ~(0xff << ofs))
88		     | (irc_dlevel << ofs),
89		     ilrp);
90#ifdef CONFIG_CPU_TX39XX
91	/* update IRCSR */
92	__raw_writel(0, &txx9_ircptr->imr);
93	__raw_writel(irc_elevel, &txx9_ircptr->imr);
94	/* flush write buffer */
95	__raw_readl(&txx9_ircptr->ssr);
96#else
97	mmiowb();
98#endif
99}
100
101static void txx9_irq_mask_ack(unsigned int irq)
102{
103	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
104
105	txx9_irq_mask(irq);
106	/* clear edge detection */
107	if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode)))
108		__raw_writel(TXx9_IRSCR_EIClrE | irq_nr, &txx9_ircptr->scr);
109}
110
111static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type)
112{
113	unsigned int irq_nr = irq - TXX9_IRQ_BASE;
114	u32 cr;
115	u32 __iomem *crp;
116	int ofs;
117	int mode;
118
119	if (flow_type & IRQF_TRIGGER_PROBE)
120		return 0;
121	switch (flow_type & IRQF_TRIGGER_MASK) {
122	case IRQF_TRIGGER_RISING:	mode = TXx9_IRCR_UP;	break;
123	case IRQF_TRIGGER_FALLING:	mode = TXx9_IRCR_DOWN;	break;
124	case IRQF_TRIGGER_HIGH:	mode = TXx9_IRCR_HIGH;	break;
125	case IRQF_TRIGGER_LOW:	mode = TXx9_IRCR_LOW;	break;
126	default:
127		return -EINVAL;
128	}
129	crp = &txx9_ircptr->cr[(unsigned int)irq_nr / 8];
130	cr = __raw_readl(crp);
131	ofs = (irq_nr & (8 - 1)) * 2;
132	cr &= ~(0x3 << ofs);
133	cr |= (mode & 0x3) << ofs;
134	__raw_writel(cr, crp);
135	txx9irq[irq_nr].mode = mode;
136	return 0;
137}
138
139static struct irq_chip txx9_irq_chip = {
140	.name		= "TXX9",
141	.ack		= txx9_irq_mask_ack,
142	.mask		= txx9_irq_mask,
143	.mask_ack	= txx9_irq_mask_ack,
144	.unmask		= txx9_irq_unmask,
145	.set_type	= txx9_irq_set_type,
146};
147
148void __init txx9_irq_init(unsigned long baseaddr)
149{
150	int i;
151
152	txx9_ircptr = ioremap(baseaddr, sizeof(struct txx9_irc_reg));
153	for (i = 0; i < TXx9_MAX_IR; i++) {
154		txx9irq[i].level = 4; /* middle level */
155		txx9irq[i].mode = TXx9_IRCR_LOW;
156		set_irq_chip_and_handler(TXX9_IRQ_BASE + i,
157					 &txx9_irq_chip, handle_level_irq);
158	}
159
160	/* mask all IRC interrupts */
161	__raw_writel(0, &txx9_ircptr->imr);
162	for (i = 0; i < 8; i++)
163		__raw_writel(0, &txx9_ircptr->ilr[i]);
164	/* setup IRC interrupt mode (Low Active) */
165	for (i = 0; i < 2; i++)
166		__raw_writel(0, &txx9_ircptr->cr[i]);
167	/* enable interrupt control */
168	__raw_writel(TXx9_IRCER_ICE, &txx9_ircptr->cer);
169	__raw_writel(irc_elevel, &txx9_ircptr->imr);
170}
171
172int __init txx9_irq_set_pri(int irc_irq, int new_pri)
173{
174	int old_pri;
175
176	if ((unsigned int)irc_irq >= TXx9_MAX_IR)
177		return 0;
178	old_pri = txx9irq[irc_irq].level;
179	txx9irq[irc_irq].level = new_pri;
180	return old_pri;
181}
182
183int txx9_irq(void)
184{
185	u32 csr = __raw_readl(&txx9_ircptr->csr);
186
187	if (likely(!(csr & TXx9_IRCSR_IF)))
188		return TXX9_IRQ_BASE + (csr & (TXx9_MAX_IR - 1));
189	return -1;
190}
191