1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * intc.c -- support for the old ColdFire interrupt controller
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
7*4882a593Smuzhiyun * License. See the file COPYING in the main directory of this archive
8*4882a593Smuzhiyun * for more details.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/types.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/irq.h>
16*4882a593Smuzhiyun #include <linux/io.h>
17*4882a593Smuzhiyun #include <asm/traps.h>
18*4882a593Smuzhiyun #include <asm/coldfire.h>
19*4882a593Smuzhiyun #include <asm/mcfsim.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /*
22*4882a593Smuzhiyun * The mapping of irq number to a mask register bit is not one-to-one.
23*4882a593Smuzhiyun * The irq numbers are either based on "level" of interrupt or fixed
24*4882a593Smuzhiyun * for an autovector-able interrupt. So we keep a local data structure
25*4882a593Smuzhiyun * that maps from irq to mask register. Not all interrupts will have
26*4882a593Smuzhiyun * an IMR bit.
27*4882a593Smuzhiyun */
28*4882a593Smuzhiyun unsigned char mcf_irq2imr[NR_IRQS];
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /*
31*4882a593Smuzhiyun * Define the miniumun and maximum external interrupt numbers.
32*4882a593Smuzhiyun * This is also used as the "level" interrupt numbers.
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun #define EIRQ1 25
35*4882a593Smuzhiyun #define EIRQ7 31
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun * In the early version 2 core ColdFire parts the IMR register was 16 bits
39*4882a593Smuzhiyun * in size. Version 3 (and later version 2) core parts have a 32 bit
40*4882a593Smuzhiyun * sized IMR register. Provide some size independent methods to access the
41*4882a593Smuzhiyun * IMR register.
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun #ifdef MCFSIM_IMR_IS_16BITS
44*4882a593Smuzhiyun
mcf_setimr(int index)45*4882a593Smuzhiyun void mcf_setimr(int index)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun u16 imr;
48*4882a593Smuzhiyun imr = __raw_readw(MCFSIM_IMR);
49*4882a593Smuzhiyun __raw_writew(imr | (0x1 << index), MCFSIM_IMR);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
mcf_clrimr(int index)52*4882a593Smuzhiyun void mcf_clrimr(int index)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun u16 imr;
55*4882a593Smuzhiyun imr = __raw_readw(MCFSIM_IMR);
56*4882a593Smuzhiyun __raw_writew(imr & ~(0x1 << index), MCFSIM_IMR);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
mcf_maskimr(unsigned int mask)59*4882a593Smuzhiyun void mcf_maskimr(unsigned int mask)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun u16 imr;
62*4882a593Smuzhiyun imr = __raw_readw(MCFSIM_IMR);
63*4882a593Smuzhiyun imr |= mask;
64*4882a593Smuzhiyun __raw_writew(imr, MCFSIM_IMR);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun #else
68*4882a593Smuzhiyun
mcf_setimr(int index)69*4882a593Smuzhiyun void mcf_setimr(int index)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun u32 imr;
72*4882a593Smuzhiyun imr = __raw_readl(MCFSIM_IMR);
73*4882a593Smuzhiyun __raw_writel(imr | (0x1 << index), MCFSIM_IMR);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
mcf_clrimr(int index)76*4882a593Smuzhiyun void mcf_clrimr(int index)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun u32 imr;
79*4882a593Smuzhiyun imr = __raw_readl(MCFSIM_IMR);
80*4882a593Smuzhiyun __raw_writel(imr & ~(0x1 << index), MCFSIM_IMR);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
mcf_maskimr(unsigned int mask)83*4882a593Smuzhiyun void mcf_maskimr(unsigned int mask)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun u32 imr;
86*4882a593Smuzhiyun imr = __raw_readl(MCFSIM_IMR);
87*4882a593Smuzhiyun imr |= mask;
88*4882a593Smuzhiyun __raw_writel(imr, MCFSIM_IMR);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /*
94*4882a593Smuzhiyun * Interrupts can be "vectored" on the ColdFire cores that support this old
95*4882a593Smuzhiyun * interrupt controller. That is, the device raising the interrupt can also
96*4882a593Smuzhiyun * supply the vector number to interrupt through. The AVR register of the
97*4882a593Smuzhiyun * interrupt controller enables or disables this for each external interrupt,
98*4882a593Smuzhiyun * so provide generic support for this. Setting this up is out-of-band for
99*4882a593Smuzhiyun * the interrupt system API's, and needs to be done by the driver that
100*4882a593Smuzhiyun * supports this device. Very few devices actually use this.
101*4882a593Smuzhiyun */
mcf_autovector(int irq)102*4882a593Smuzhiyun void mcf_autovector(int irq)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun #ifdef MCFSIM_AVR
105*4882a593Smuzhiyun if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
106*4882a593Smuzhiyun u8 avec;
107*4882a593Smuzhiyun avec = __raw_readb(MCFSIM_AVR);
108*4882a593Smuzhiyun avec |= (0x1 << (irq - EIRQ1 + 1));
109*4882a593Smuzhiyun __raw_writeb(avec, MCFSIM_AVR);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun #endif
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
intc_irq_mask(struct irq_data * d)114*4882a593Smuzhiyun static void intc_irq_mask(struct irq_data *d)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun if (mcf_irq2imr[d->irq])
117*4882a593Smuzhiyun mcf_setimr(mcf_irq2imr[d->irq]);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
intc_irq_unmask(struct irq_data * d)120*4882a593Smuzhiyun static void intc_irq_unmask(struct irq_data *d)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun if (mcf_irq2imr[d->irq])
123*4882a593Smuzhiyun mcf_clrimr(mcf_irq2imr[d->irq]);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
intc_irq_set_type(struct irq_data * d,unsigned int type)126*4882a593Smuzhiyun static int intc_irq_set_type(struct irq_data *d, unsigned int type)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun return 0;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun static struct irq_chip intc_irq_chip = {
132*4882a593Smuzhiyun .name = "CF-INTC",
133*4882a593Smuzhiyun .irq_mask = intc_irq_mask,
134*4882a593Smuzhiyun .irq_unmask = intc_irq_unmask,
135*4882a593Smuzhiyun .irq_set_type = intc_irq_set_type,
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
init_IRQ(void)138*4882a593Smuzhiyun void __init init_IRQ(void)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun int irq;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun mcf_maskimr(0xffffffff);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun for (irq = 0; (irq < NR_IRQS); irq++) {
145*4882a593Smuzhiyun irq_set_chip(irq, &intc_irq_chip);
146*4882a593Smuzhiyun irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
147*4882a593Smuzhiyun irq_set_handler(irq, handle_level_irq);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151