irq.c 2.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/* 
 * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See linux/COPYING for more information.                            
 *
 * Looks after interrupts on the HARP board.
 *
 * Bases on the IPR irq system
 */

#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/harp/harp.h>


#define NUM_EXTERNAL_IRQS 16

// Early versions of the STB1 Overdrive required this nasty frig
//#define INVERT_INTMASK_WRITES

static void enable_harp_irq(unsigned int irq);
static void disable_harp_irq(unsigned int irq);

/* shutdown is same as "disable" */
#define shutdown_harp_irq disable_harp_irq

static void mask_and_ack_harp(unsigned int);
static void end_harp_irq(unsigned int irq);

static unsigned int startup_harp_irq(unsigned int irq)
{
	enable_harp_irq(irq);
	return 0;		/* never anything pending */
}

static struct hw_interrupt_type harp_irq_type = {
42 43 44 45 46 47 48
	.typename = "Harp-IRQ",
	.startup = startup_harp_irq,
	.shutdown = shutdown_harp_irq,
	.enable = enable_harp_irq,
	.disable = disable_harp_irq,
	.ack = mask_and_ack_harp,
	.end = end_harp_irq
L
Linus Torvalds 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
};

static void disable_harp_irq(unsigned int irq)
{
	unsigned val, flags;
	unsigned maskReg;
	unsigned mask;
	int pri;

	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
		return;

	pri = 15 - irq;

	if (pri < 8) {
		maskReg = EPLD_INTMASK0;
	} else {
		maskReg = EPLD_INTMASK1;
		pri -= 8;
	}

	local_irq_save(flags);
	mask = ctrl_inl(maskReg);
	mask &= (~(1 << pri));
#if defined(INVERT_INTMASK_WRITES)
	mask ^= 0xff;
#endif
	ctrl_outl(mask, maskReg);
	local_irq_restore(flags);
}

static void enable_harp_irq(unsigned int irq)
{
	unsigned flags;
	unsigned maskReg;
	unsigned mask;
	int pri;

	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
		return;

	pri = 15 - irq;

	if (pri < 8) {
		maskReg = EPLD_INTMASK0;
	} else {
		maskReg = EPLD_INTMASK1;
		pri -= 8;
	}

	local_irq_save(flags);
	mask = ctrl_inl(maskReg);


	mask |= (1 << pri);

#if defined(INVERT_INTMASK_WRITES)
	mask ^= 0xff;
#endif
	ctrl_outl(mask, maskReg);

	local_irq_restore(flags);
}

/* This functions sets the desired irq handler to be an overdrive type */
static void __init make_harp_irq(unsigned int irq)
{
	disable_irq_nosync(irq);
	irq_desc[irq].handler = &harp_irq_type;
	disable_harp_irq(irq);
}

static void mask_and_ack_harp(unsigned int irq)
{
	disable_harp_irq(irq);
}

static void end_harp_irq(unsigned int irq)
{
	enable_harp_irq(irq);
}

void __init init_harp_irq(void)
{
	int i;

#if !defined(INVERT_INTMASK_WRITES)
	// On the harp these are set to enable an interrupt
	ctrl_outl(0x00, EPLD_INTMASK0);
	ctrl_outl(0x00, EPLD_INTMASK1);
#else
	// On the Overdrive the data is inverted before being stored in the reg
	ctrl_outl(0xff, EPLD_INTMASK0);
	ctrl_outl(0xff, EPLD_INTMASK1);
#endif

	for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
		make_harp_irq(i);
	}
}