gt-irq.c 5.46 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
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
/*
 *
 * Copyright 2002 Momentum Computer
 * Author: mdharm@momenco.com
 *
 * arch/mips/momentum/ocelot_g/gt_irq.c
 *     Interrupt routines for gt64240.  Currently it only handles timer irq.
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <asm/gt64240.h>
#include <asm/io.h>

unsigned long bus_clock;

/*
 * These are interrupt handlers for the GT on-chip interrupts.  They
 * all come in to the MIPS on a single interrupt line, and have to
 * be handled and ack'ed differently than other MIPS interrupts.
 */

30
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH];
void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr);

/*
 * Hooks IRQ handler to the system. When the system is interrupted
 * the interrupt service routine is called.
 *
 * Inputs :
 * int_cause - The interrupt cause number. In EVB64120 two parameters
 *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
 * bit_num   - Indicates which bit number in the cause register
 * isr_ptr   - Pointer to the interrupt service routine
 */
void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr)
{
	irq_handlers[int_cause][bit_num].routine = isr_ptr;
}


/*
 * Enables the IRQ on Galileo Chip
 *
 * Inputs :
 * int_cause - The interrupt cause number. In EVB64120 two parameters
 *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
 * bit_num   - Indicates which bit number in the cause register
 *
 * Outputs :
Andreas Mohr's avatar
Andreas Mohr committed
60
 * 1 if successful, 0 if failure
Linus Torvalds's avatar
Linus Torvalds committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
 */
int enable_galileo_irq(int int_cause, int bit_num)
{
	if (int_cause == INT_CAUSE_MAIN)
		SET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER, (1 << bit_num));
	else if (int_cause == INT_CAUSE_HIGH)
		SET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
			     (1 << bit_num));
	else
		return 0;

	return 1;
}

/*
 * Disables the IRQ on Galileo Chip
 *
 * Inputs :
 * int_cause - The interrupt cause number. In EVB64120 two parameters
 *             are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
 * bit_num   - Indicates which bit number in the cause register
 *
 * Outputs :
Andreas Mohr's avatar
Andreas Mohr committed
84
 * 1 if successful, 0 if failure
Linus Torvalds's avatar
Linus Torvalds committed
85 86 87 88 89 90 91 92 93 94 95 96 97
 */
int disable_galileo_irq(int int_cause, int bit_num)
{
	if (int_cause == INT_CAUSE_MAIN)
		RESET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER,
			       (1 << bit_num));
	else if (int_cause == INT_CAUSE_HIGH)
		RESET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
			       (1 << bit_num));
	else
		return 0;
	return 1;
}
98
#endif /* 0 */
Linus Torvalds's avatar
Linus Torvalds committed
99 100 101 102 103 104 105 106 107 108 109

/*
 * Interrupt handler for interrupts coming from the Galileo chip via P0_INT#.
 *
 * We route the timer interrupt to P0_INT# (IRQ 6), and that's all this
 * routine can handle, for now.
 *
 * In the future, we'll route more interrupts to this pin, and that's why
 * we keep this particular structure in the function.
 */

110
static irqreturn_t gt64240_p0int_irq(int irq, void *dev)
Linus Torvalds's avatar
Linus Torvalds committed
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
{
	uint32_t irq_src, irq_src_mask;
	int handled;

	/* get the low interrupt cause register */
	irq_src = MV_READ(LOW_INTERRUPT_CAUSE_REGISTER);

	/* get the mask register for this pin */
	irq_src_mask = MV_READ(PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW);

	/* mask off only the interrupts we're interested in */
	irq_src = irq_src & irq_src_mask;

	handled = IRQ_NONE;

	/* Check for timer interrupt */
	if (irq_src & 0x00000100) {
		handled = IRQ_HANDLED;
		irq_src &= ~0x00000100;

		/* Clear any pending cause bits */
		MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);

		/* handle the timer call */
135
		do_timer(1);
Linus Torvalds's avatar
Linus Torvalds committed
136
#ifndef CONFIG_SMP
137
		update_process_times(user_mode(get_irq_regs()));
Linus Torvalds's avatar
Linus Torvalds committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
#endif
	}

	if (irq_src) {
		printk(KERN_INFO
		       "UNKNOWN P0_INT# interrupt received, irq_src=0x%x\n",
		       irq_src);
	}

	return handled;
}

/*
 * Initializes timer using galileo's built in timer.
 */

/*
 * This will ignore the standard MIPS timer interrupt handler
 * that is passed in as *irq (=irq0 in ../kernel/time.c).
 * We will do our own timer interrupt handling.
 */
void gt64240_time_init(void)
{
	static struct irqaction timer;

	/* Stop the timer -- we'll use timer #0 */
	MV_WRITE(TIMER_COUNTER_0_3_CONTROL, 0x0);

	/* Load timer value for 100 Hz */
	MV_WRITE(TIMER_COUNTER0, bus_clock / 100);

	/*
	 * Create the IRQ structure entry for the timer.  Since we're too early
	 * in the boot process to use the "request_irq()" call, we'll hard-code
	 * the values to the correct interrupt line.
	 */
	timer.handler = &gt64240_p0int_irq;
175
	timer.flags = IRQF_SHARED | IRQF_DISABLED;
Linus Torvalds's avatar
Linus Torvalds committed
176 177 178
	timer.name = "timer";
	timer.dev_id = NULL;
	timer.next = NULL;
179
	timer.mask = CPU_MASK_NONE;
Linus Torvalds's avatar
Linus Torvalds committed
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	irq_desc[6].action = &timer;

	enable_irq(6);

	/* Clear any pending cause bits */
	MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);

	/* Enable the interrupt for timer 0 */
	MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_MASK, 0x1);

	/* Enable the timer interrupt for GT-64240 pin P0_INT# */
	MV_WRITE (PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW, 0x100);

	/* Configure and start the timer */
	MV_WRITE(TIMER_COUNTER_0_3_CONTROL, 0x3);
}

void gt64240_irq_init(void)
{
199
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
200 201 202 203 204 205 206 207 208 209 210
	int i, j;

	/* Reset irq handlers pointers to NULL */
	for (i = 0; i < MAX_CAUSE_REGS; i++) {
		for (j = 0; j < MAX_CAUSE_REG_WIDTH; j++) {
			irq_handlers[i][j].next = NULL;
			irq_handlers[i][j].sync = 0;
			irq_handlers[i][j].routine = NULL;
			irq_handlers[i][j].data = NULL;
		}
	}
211
#endif /* 0 */
Linus Torvalds's avatar
Linus Torvalds committed
212
}