cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intc-5272.c (5982B)


      1/*
      2 * intc.c  --  interrupt controller or ColdFire 5272 SoC
      3 *
      4 * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
      5 *
      6 * This file is subject to the terms and conditions of the GNU General Public
      7 * License.  See the file COPYING in the main directory of this archive
      8 * for more details.
      9 */
     10
     11#include <linux/types.h>
     12#include <linux/init.h>
     13#include <linux/kernel.h>
     14#include <linux/interrupt.h>
     15#include <linux/kernel_stat.h>
     16#include <linux/irq.h>
     17#include <linux/io.h>
     18#include <asm/coldfire.h>
     19#include <asm/mcfsim.h>
     20#include <asm/traps.h>
     21
     22/*
     23 * The 5272 ColdFire interrupt controller is nothing like any other
     24 * ColdFire interrupt controller - it truly is completely different.
     25 * Given its age it is unlikely to be used on any other ColdFire CPU.
     26 */
     27
     28/*
     29 * The masking and priproty setting of interrupts on the 5272 is done
     30 * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
     31 * loose mapping of vector number to register and internal bits, but
     32 * a table is the easiest and quickest way to map them.
     33 *
     34 * Note that the external interrupts are edge triggered (unlike the
     35 * internal interrupt sources which are level triggered). Which means
     36 * they also need acknowledging via acknowledge bits.
     37 */
     38struct irqmap {
     39	unsigned int	icr;
     40	unsigned char	index;
     41	unsigned char	ack;
     42};
     43
     44static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
     45	/*MCF_IRQ_SPURIOUS*/	{ .icr = 0,           .index = 0,  .ack = 0, },
     46	/*MCF_IRQ_EINT1*/	{ .icr = MCFSIM_ICR1, .index = 28, .ack = 1, },
     47	/*MCF_IRQ_EINT2*/	{ .icr = MCFSIM_ICR1, .index = 24, .ack = 1, },
     48	/*MCF_IRQ_EINT3*/	{ .icr = MCFSIM_ICR1, .index = 20, .ack = 1, },
     49	/*MCF_IRQ_EINT4*/	{ .icr = MCFSIM_ICR1, .index = 16, .ack = 1, },
     50	/*MCF_IRQ_TIMER1*/	{ .icr = MCFSIM_ICR1, .index = 12, .ack = 0, },
     51	/*MCF_IRQ_TIMER2*/	{ .icr = MCFSIM_ICR1, .index = 8,  .ack = 0, },
     52	/*MCF_IRQ_TIMER3*/	{ .icr = MCFSIM_ICR1, .index = 4,  .ack = 0, },
     53	/*MCF_IRQ_TIMER4*/	{ .icr = MCFSIM_ICR1, .index = 0,  .ack = 0, },
     54	/*MCF_IRQ_UART1*/	{ .icr = MCFSIM_ICR2, .index = 28, .ack = 0, },
     55	/*MCF_IRQ_UART2*/	{ .icr = MCFSIM_ICR2, .index = 24, .ack = 0, },
     56	/*MCF_IRQ_PLIP*/	{ .icr = MCFSIM_ICR2, .index = 20, .ack = 0, },
     57	/*MCF_IRQ_PLIA*/	{ .icr = MCFSIM_ICR2, .index = 16, .ack = 0, },
     58	/*MCF_IRQ_USB0*/	{ .icr = MCFSIM_ICR2, .index = 12, .ack = 0, },
     59	/*MCF_IRQ_USB1*/	{ .icr = MCFSIM_ICR2, .index = 8,  .ack = 0, },
     60	/*MCF_IRQ_USB2*/	{ .icr = MCFSIM_ICR2, .index = 4,  .ack = 0, },
     61	/*MCF_IRQ_USB3*/	{ .icr = MCFSIM_ICR2, .index = 0,  .ack = 0, },
     62	/*MCF_IRQ_USB4*/	{ .icr = MCFSIM_ICR3, .index = 28, .ack = 0, },
     63	/*MCF_IRQ_USB5*/	{ .icr = MCFSIM_ICR3, .index = 24, .ack = 0, },
     64	/*MCF_IRQ_USB6*/	{ .icr = MCFSIM_ICR3, .index = 20, .ack = 0, },
     65	/*MCF_IRQ_USB7*/	{ .icr = MCFSIM_ICR3, .index = 16, .ack = 0, },
     66	/*MCF_IRQ_DMA*/		{ .icr = MCFSIM_ICR3, .index = 12, .ack = 0, },
     67	/*MCF_IRQ_ERX*/		{ .icr = MCFSIM_ICR3, .index = 8,  .ack = 0, },
     68	/*MCF_IRQ_ETX*/		{ .icr = MCFSIM_ICR3, .index = 4,  .ack = 0, },
     69	/*MCF_IRQ_ENTC*/	{ .icr = MCFSIM_ICR3, .index = 0,  .ack = 0, },
     70	/*MCF_IRQ_QSPI*/	{ .icr = MCFSIM_ICR4, .index = 28, .ack = 0, },
     71	/*MCF_IRQ_EINT5*/	{ .icr = MCFSIM_ICR4, .index = 24, .ack = 1, },
     72	/*MCF_IRQ_EINT6*/	{ .icr = MCFSIM_ICR4, .index = 20, .ack = 1, },
     73	/*MCF_IRQ_SWTO*/	{ .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
     74};
     75
     76/*
     77 * The act of masking the interrupt also has a side effect of 'ack'ing
     78 * an interrupt on this irq (for the external irqs). So this mask function
     79 * is also an ack_mask function.
     80 */
     81static void intc_irq_mask(struct irq_data *d)
     82{
     83	unsigned int irq = d->irq;
     84
     85	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
     86		u32 v;
     87		irq -= MCFINT_VECBASE;
     88		v = 0x8 << intc_irqmap[irq].index;
     89		writel(v, intc_irqmap[irq].icr);
     90	}
     91}
     92
     93static void intc_irq_unmask(struct irq_data *d)
     94{
     95	unsigned int irq = d->irq;
     96
     97	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
     98		u32 v;
     99		irq -= MCFINT_VECBASE;
    100		v = 0xd << intc_irqmap[irq].index;
    101		writel(v, intc_irqmap[irq].icr);
    102	}
    103}
    104
    105static void intc_irq_ack(struct irq_data *d)
    106{
    107	unsigned int irq = d->irq;
    108
    109	/* Only external interrupts are acked */
    110	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
    111		irq -= MCFINT_VECBASE;
    112		if (intc_irqmap[irq].ack) {
    113			u32 v;
    114			v = readl(intc_irqmap[irq].icr);
    115			v &= (0x7 << intc_irqmap[irq].index);
    116			v |= (0x8 << intc_irqmap[irq].index);
    117			writel(v, intc_irqmap[irq].icr);
    118		}
    119	}
    120}
    121
    122static int intc_irq_set_type(struct irq_data *d, unsigned int type)
    123{
    124	unsigned int irq = d->irq;
    125
    126	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
    127		irq -= MCFINT_VECBASE;
    128		if (intc_irqmap[irq].ack) {
    129			u32 v;
    130			v = readl(MCFSIM_PITR);
    131			if (type == IRQ_TYPE_EDGE_FALLING)
    132				v &= ~(0x1 << (32 - irq));
    133			else
    134				v |= (0x1 << (32 - irq));
    135			writel(v, MCFSIM_PITR);
    136		}
    137	}
    138	return 0;
    139}
    140
    141/*
    142 * Simple flow handler to deal with the external edge triggered interrupts.
    143 * We need to be careful with the masking/acking due to the side effects
    144 * of masking an interrupt.
    145 */
    146static void intc_external_irq(struct irq_desc *desc)
    147{
    148	irq_desc_get_chip(desc)->irq_ack(&desc->irq_data);
    149	handle_simple_irq(desc);
    150}
    151
    152static struct irq_chip intc_irq_chip = {
    153	.name		= "CF-INTC",
    154	.irq_mask	= intc_irq_mask,
    155	.irq_unmask	= intc_irq_unmask,
    156	.irq_mask_ack	= intc_irq_mask,
    157	.irq_ack	= intc_irq_ack,
    158	.irq_set_type	= intc_irq_set_type,
    159};
    160
    161void __init init_IRQ(void)
    162{
    163	int irq, edge;
    164
    165	/* Mask all interrupt sources */
    166	writel(0x88888888, MCFSIM_ICR1);
    167	writel(0x88888888, MCFSIM_ICR2);
    168	writel(0x88888888, MCFSIM_ICR3);
    169	writel(0x88888888, MCFSIM_ICR4);
    170
    171	for (irq = 0; (irq < NR_IRQS); irq++) {
    172		irq_set_chip(irq, &intc_irq_chip);
    173		edge = 0;
    174		if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
    175			edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
    176		if (edge) {
    177			irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
    178			irq_set_handler(irq, intc_external_irq);
    179		} else {
    180			irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
    181			irq_set_handler(irq, handle_level_irq);
    182		}
    183	}
    184}
    185