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 <linux/irq.h> |
20 | #include <asm/txx9irq.h> |
21 | |
22 | struct txx9_irc_reg { |
23 | u32 cer; |
24 | u32 cr[2]; |
25 | u32 unused0; |
26 | u32 ilr[8]; |
27 | u32 unused1[4]; |
28 | u32 imr; |
29 | u32 unused2[7]; |
30 | u32 scr; |
31 | u32 unused3[7]; |
32 | u32 ssr; |
33 | u32 unused4[7]; |
34 | u32 csr; |
35 | }; |
36 | |
37 | /* IRCER : Int. Control Enable */ |
38 | #define TXx9_IRCER_ICE 0x00000001 |
39 | |
40 | /* IRCR : Int. Control */ |
41 | #define TXx9_IRCR_LOW 0x00000000 |
42 | #define TXx9_IRCR_HIGH 0x00000001 |
43 | #define TXx9_IRCR_DOWN 0x00000002 |
44 | #define TXx9_IRCR_UP 0x00000003 |
45 | #define TXx9_IRCR_EDGE(cr) ((cr) & 0x00000002) |
46 | |
47 | /* IRSCR : Int. Status Control */ |
48 | #define TXx9_IRSCR_EIClrE 0x00000100 |
49 | #define TXx9_IRSCR_EIClr_MASK 0x0000000f |
50 | |
51 | /* IRCSR : Int. Current Status */ |
52 | #define TXx9_IRCSR_IF 0x00010000 |
53 | #define TXx9_IRCSR_ILV_MASK 0x00000700 |
54 | #define TXx9_IRCSR_IVL_MASK 0x0000001f |
55 | |
56 | #define irc_dlevel 0 |
57 | #define irc_elevel 1 |
58 | |
59 | static struct txx9_irc_reg __iomem *txx9_ircptr __read_mostly; |
60 | |
61 | static struct { |
62 | unsigned char level; |
63 | unsigned char mode; |
64 | } txx9irq[TXx9_MAX_IR] __read_mostly; |
65 | |
66 | static void txx9_irq_unmask(struct irq_data *d) |
67 | { |
68 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
69 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2]; |
70 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; |
71 | |
72 | __raw_writel(val: (__raw_readl(addr: ilrp) & ~(0xff << ofs)) |
73 | | (txx9irq[irq_nr].level << ofs), |
74 | addr: ilrp); |
75 | } |
76 | |
77 | static inline void txx9_irq_mask(struct irq_data *d) |
78 | { |
79 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
80 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2]; |
81 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; |
82 | |
83 | __raw_writel(val: (__raw_readl(addr: ilrp) & ~(0xff << ofs)) |
84 | | (irc_dlevel << ofs), |
85 | addr: ilrp); |
86 | mmiowb(); |
87 | } |
88 | |
89 | static void txx9_irq_mask_ack(struct irq_data *d) |
90 | { |
91 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
92 | |
93 | txx9_irq_mask(d); |
94 | /* clear edge detection */ |
95 | if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode))) |
96 | __raw_writel(TXx9_IRSCR_EIClrE | irq_nr, addr: &txx9_ircptr->scr); |
97 | } |
98 | |
99 | static int txx9_irq_set_type(struct irq_data *d, unsigned int flow_type) |
100 | { |
101 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
102 | u32 cr; |
103 | u32 __iomem *crp; |
104 | int ofs; |
105 | int mode; |
106 | |
107 | if (flow_type & IRQF_TRIGGER_PROBE) |
108 | return 0; |
109 | switch (flow_type & IRQF_TRIGGER_MASK) { |
110 | case IRQF_TRIGGER_RISING: mode = TXx9_IRCR_UP; break; |
111 | case IRQF_TRIGGER_FALLING: mode = TXx9_IRCR_DOWN; break; |
112 | case IRQF_TRIGGER_HIGH: mode = TXx9_IRCR_HIGH; break; |
113 | case IRQF_TRIGGER_LOW: mode = TXx9_IRCR_LOW; break; |
114 | default: |
115 | return -EINVAL; |
116 | } |
117 | crp = &txx9_ircptr->cr[(unsigned int)irq_nr / 8]; |
118 | cr = __raw_readl(addr: crp); |
119 | ofs = (irq_nr & (8 - 1)) * 2; |
120 | cr &= ~(0x3 << ofs); |
121 | cr |= (mode & 0x3) << ofs; |
122 | __raw_writel(val: cr, addr: crp); |
123 | txx9irq[irq_nr].mode = mode; |
124 | return 0; |
125 | } |
126 | |
127 | static struct irq_chip txx9_irq_chip = { |
128 | .name = "TXX9" , |
129 | .irq_ack = txx9_irq_mask_ack, |
130 | .irq_mask = txx9_irq_mask, |
131 | .irq_mask_ack = txx9_irq_mask_ack, |
132 | .irq_unmask = txx9_irq_unmask, |
133 | .irq_set_type = txx9_irq_set_type, |
134 | }; |
135 | |
136 | void __init txx9_irq_init(unsigned long baseaddr) |
137 | { |
138 | int i; |
139 | |
140 | txx9_ircptr = ioremap(offset: baseaddr, size: sizeof(struct txx9_irc_reg)); |
141 | for (i = 0; i < TXx9_MAX_IR; i++) { |
142 | txx9irq[i].level = 4; /* middle level */ |
143 | txx9irq[i].mode = TXx9_IRCR_LOW; |
144 | irq_set_chip_and_handler(irq: TXX9_IRQ_BASE + i, chip: &txx9_irq_chip, |
145 | handle: handle_level_irq); |
146 | } |
147 | |
148 | /* mask all IRC interrupts */ |
149 | __raw_writel(val: 0, addr: &txx9_ircptr->imr); |
150 | for (i = 0; i < 8; i++) |
151 | __raw_writel(val: 0, addr: &txx9_ircptr->ilr[i]); |
152 | /* setup IRC interrupt mode (Low Active) */ |
153 | for (i = 0; i < 2; i++) |
154 | __raw_writel(val: 0, addr: &txx9_ircptr->cr[i]); |
155 | /* enable interrupt control */ |
156 | __raw_writel(TXx9_IRCER_ICE, addr: &txx9_ircptr->cer); |
157 | __raw_writel(irc_elevel, addr: &txx9_ircptr->imr); |
158 | } |
159 | |
160 | int __init txx9_irq_set_pri(int irc_irq, int new_pri) |
161 | { |
162 | int old_pri; |
163 | |
164 | if ((unsigned int)irc_irq >= TXx9_MAX_IR) |
165 | return 0; |
166 | old_pri = txx9irq[irc_irq].level; |
167 | txx9irq[irc_irq].level = new_pri; |
168 | return old_pri; |
169 | } |
170 | |
171 | int txx9_irq(void) |
172 | { |
173 | u32 csr = __raw_readl(addr: &txx9_ircptr->csr); |
174 | |
175 | if (likely(!(csr & TXx9_IRCSR_IF))) |
176 | return TXX9_IRQ_BASE + (csr & (TXx9_MAX_IR - 1)); |
177 | return -1; |
178 | } |
179 | |