xref: /openbmc/linux/arch/mips/kernel/irq_txx9.c (revision fd589a8f)
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 
21 struct 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 
58 static struct txx9_irc_reg __iomem *txx9_ircptr __read_mostly;
59 
60 static struct {
61 	unsigned char level;
62 	unsigned char mode;
63 } txx9irq[TXx9_MAX_IR] __read_mostly;
64 
65 static 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 
81 static 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 
101 static 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 
111 static 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 
139 static 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 
148 void __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 
172 int __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 
183 int 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