162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * intc.c  -- support for the old ColdFire interrupt controller
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
762306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
862306a36Sopenharmony_ci * for more details.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/irq.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci#include <asm/traps.h>
1862306a36Sopenharmony_ci#include <asm/coldfire.h>
1962306a36Sopenharmony_ci#include <asm/mcfsim.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * The mapping of irq number to a mask register bit is not one-to-one.
2362306a36Sopenharmony_ci * The irq numbers are either based on "level" of interrupt or fixed
2462306a36Sopenharmony_ci * for an autovector-able interrupt. So we keep a local data structure
2562306a36Sopenharmony_ci * that maps from irq to mask register. Not all interrupts will have
2662306a36Sopenharmony_ci * an IMR bit.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ciunsigned char mcf_irq2imr[NR_IRQS];
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * Define the minimum and maximum external interrupt numbers.
3262306a36Sopenharmony_ci * This is also used as the "level" interrupt numbers.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci#define	EIRQ1	25
3562306a36Sopenharmony_ci#define	EIRQ7	31
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * In the early version 2 core ColdFire parts the IMR register was 16 bits
3962306a36Sopenharmony_ci * in size. Version 3 (and later version 2) core parts have a 32 bit
4062306a36Sopenharmony_ci * sized IMR register. Provide some size independent methods to access the
4162306a36Sopenharmony_ci * IMR register.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci#ifdef MCFSIM_IMR_IS_16BITS
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_civoid mcf_setimr(int index)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	u16 imr;
4862306a36Sopenharmony_ci	imr = __raw_readw(MCFSIM_IMR);
4962306a36Sopenharmony_ci	__raw_writew(imr | (0x1 << index), MCFSIM_IMR);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_civoid mcf_clrimr(int index)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	u16 imr;
5562306a36Sopenharmony_ci	imr = __raw_readw(MCFSIM_IMR);
5662306a36Sopenharmony_ci	__raw_writew(imr & ~(0x1 << index), MCFSIM_IMR);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_civoid mcf_maskimr(unsigned int mask)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	u16 imr;
6262306a36Sopenharmony_ci	imr = __raw_readw(MCFSIM_IMR);
6362306a36Sopenharmony_ci	imr |= mask;
6462306a36Sopenharmony_ci	__raw_writew(imr, MCFSIM_IMR);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#else
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_civoid mcf_setimr(int index)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	u32 imr;
7262306a36Sopenharmony_ci	imr = __raw_readl(MCFSIM_IMR);
7362306a36Sopenharmony_ci	__raw_writel(imr | (0x1 << index), MCFSIM_IMR);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_civoid mcf_clrimr(int index)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	u32 imr;
7962306a36Sopenharmony_ci	imr = __raw_readl(MCFSIM_IMR);
8062306a36Sopenharmony_ci	__raw_writel(imr & ~(0x1 << index), MCFSIM_IMR);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_civoid mcf_maskimr(unsigned int mask)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	u32 imr;
8662306a36Sopenharmony_ci	imr = __raw_readl(MCFSIM_IMR);
8762306a36Sopenharmony_ci	imr |= mask;
8862306a36Sopenharmony_ci	__raw_writel(imr, MCFSIM_IMR);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#endif
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*
9462306a36Sopenharmony_ci * Interrupts can be "vectored" on the ColdFire cores that support this old
9562306a36Sopenharmony_ci * interrupt controller. That is, the device raising the interrupt can also
9662306a36Sopenharmony_ci * supply the vector number to interrupt through. The AVR register of the
9762306a36Sopenharmony_ci * interrupt controller enables or disables this for each external interrupt,
9862306a36Sopenharmony_ci * so provide generic support for this. Setting this up is out-of-band for
9962306a36Sopenharmony_ci * the interrupt system API's, and needs to be done by the driver that
10062306a36Sopenharmony_ci * supports this device. Very few devices actually use this.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_civoid mcf_autovector(int irq)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci#ifdef MCFSIM_AVR
10562306a36Sopenharmony_ci	if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
10662306a36Sopenharmony_ci		u8 avec;
10762306a36Sopenharmony_ci		avec = __raw_readb(MCFSIM_AVR);
10862306a36Sopenharmony_ci		avec |= (0x1 << (irq - EIRQ1 + 1));
10962306a36Sopenharmony_ci		__raw_writeb(avec, MCFSIM_AVR);
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void intc_irq_mask(struct irq_data *d)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	if (mcf_irq2imr[d->irq])
11762306a36Sopenharmony_ci		mcf_setimr(mcf_irq2imr[d->irq]);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void intc_irq_unmask(struct irq_data *d)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	if (mcf_irq2imr[d->irq])
12362306a36Sopenharmony_ci		mcf_clrimr(mcf_irq2imr[d->irq]);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic int intc_irq_set_type(struct irq_data *d, unsigned int type)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return 0;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic struct irq_chip intc_irq_chip = {
13262306a36Sopenharmony_ci	.name		= "CF-INTC",
13362306a36Sopenharmony_ci	.irq_mask	= intc_irq_mask,
13462306a36Sopenharmony_ci	.irq_unmask	= intc_irq_unmask,
13562306a36Sopenharmony_ci	.irq_set_type	= intc_irq_set_type,
13662306a36Sopenharmony_ci};
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_civoid __init init_IRQ(void)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	int irq;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	mcf_maskimr(0xffffffff);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	for (irq = 0; (irq < NR_IRQS); irq++) {
14562306a36Sopenharmony_ci		irq_set_chip(irq, &intc_irq_chip);
14662306a36Sopenharmony_ci		irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
14762306a36Sopenharmony_ci		irq_set_handler(irq, handle_level_irq);
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
151