162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * ints.c - Generic interrupt controller support
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
562306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
662306a36Sopenharmony_ci * for more details.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright 1996 Roman Zippel
962306a36Sopenharmony_ci * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/types.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/irq.h>
1762306a36Sopenharmony_ci#include <asm/traps.h>
1862306a36Sopenharmony_ci#include <asm/io.h>
1962306a36Sopenharmony_ci#include <asm/machdep.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#if defined(CONFIG_M68EZ328)
2262306a36Sopenharmony_ci#include <asm/MC68EZ328.h>
2362306a36Sopenharmony_ci#elif defined(CONFIG_M68VZ328)
2462306a36Sopenharmony_ci#include <asm/MC68VZ328.h>
2562306a36Sopenharmony_ci#else
2662306a36Sopenharmony_ci#include <asm/MC68328.h>
2762306a36Sopenharmony_ci#endif
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* assembler routines */
3062306a36Sopenharmony_ciasmlinkage void system_call(void);
3162306a36Sopenharmony_ciasmlinkage void buserr(void);
3262306a36Sopenharmony_ciasmlinkage void trap(void);
3362306a36Sopenharmony_ciasmlinkage void trap3(void);
3462306a36Sopenharmony_ciasmlinkage void trap4(void);
3562306a36Sopenharmony_ciasmlinkage void trap5(void);
3662306a36Sopenharmony_ciasmlinkage void trap6(void);
3762306a36Sopenharmony_ciasmlinkage void trap7(void);
3862306a36Sopenharmony_ciasmlinkage void trap8(void);
3962306a36Sopenharmony_ciasmlinkage void trap9(void);
4062306a36Sopenharmony_ciasmlinkage void trap10(void);
4162306a36Sopenharmony_ciasmlinkage void trap11(void);
4262306a36Sopenharmony_ciasmlinkage void trap12(void);
4362306a36Sopenharmony_ciasmlinkage void trap13(void);
4462306a36Sopenharmony_ciasmlinkage void trap14(void);
4562306a36Sopenharmony_ciasmlinkage void trap15(void);
4662306a36Sopenharmony_ciasmlinkage void trap33(void);
4762306a36Sopenharmony_ciasmlinkage void trap34(void);
4862306a36Sopenharmony_ciasmlinkage void trap35(void);
4962306a36Sopenharmony_ciasmlinkage void trap36(void);
5062306a36Sopenharmony_ciasmlinkage void trap37(void);
5162306a36Sopenharmony_ciasmlinkage void trap38(void);
5262306a36Sopenharmony_ciasmlinkage void trap39(void);
5362306a36Sopenharmony_ciasmlinkage void trap40(void);
5462306a36Sopenharmony_ciasmlinkage void trap41(void);
5562306a36Sopenharmony_ciasmlinkage void trap42(void);
5662306a36Sopenharmony_ciasmlinkage void trap43(void);
5762306a36Sopenharmony_ciasmlinkage void trap44(void);
5862306a36Sopenharmony_ciasmlinkage void trap45(void);
5962306a36Sopenharmony_ciasmlinkage void trap46(void);
6062306a36Sopenharmony_ciasmlinkage void trap47(void);
6162306a36Sopenharmony_ciasmlinkage irqreturn_t bad_interrupt(int, void *);
6262306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler(void);
6362306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler1(void);
6462306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler2(void);
6562306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler3(void);
6662306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler4(void);
6762306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler5(void);
6862306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler6(void);
6962306a36Sopenharmony_ciasmlinkage irqreturn_t inthandler7(void);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* The 68k family did not have a good way to determine the source
7262306a36Sopenharmony_ci * of interrupts until later in the family.  The EC000 core does
7362306a36Sopenharmony_ci * not provide the vector number on the stack, we vector everything
7462306a36Sopenharmony_ci * into one vector and look in the blasted mask register...
7562306a36Sopenharmony_ci * This code is designed to be fast, almost constant time, not clean!
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_civoid process_int(int vec, struct pt_regs *fp)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	int irq;
8062306a36Sopenharmony_ci	int mask;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	unsigned long pend = ISR;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	while (pend) {
8562306a36Sopenharmony_ci		if (pend & 0x0000ffff) {
8662306a36Sopenharmony_ci			if (pend & 0x000000ff) {
8762306a36Sopenharmony_ci				if (pend & 0x0000000f) {
8862306a36Sopenharmony_ci					mask = 0x00000001;
8962306a36Sopenharmony_ci					irq = 0;
9062306a36Sopenharmony_ci				} else {
9162306a36Sopenharmony_ci					mask = 0x00000010;
9262306a36Sopenharmony_ci					irq = 4;
9362306a36Sopenharmony_ci				}
9462306a36Sopenharmony_ci			} else {
9562306a36Sopenharmony_ci				if (pend & 0x00000f00) {
9662306a36Sopenharmony_ci					mask = 0x00000100;
9762306a36Sopenharmony_ci					irq = 8;
9862306a36Sopenharmony_ci				} else {
9962306a36Sopenharmony_ci					mask = 0x00001000;
10062306a36Sopenharmony_ci					irq = 12;
10162306a36Sopenharmony_ci				}
10262306a36Sopenharmony_ci			}
10362306a36Sopenharmony_ci		} else {
10462306a36Sopenharmony_ci			if (pend & 0x00ff0000) {
10562306a36Sopenharmony_ci				if (pend & 0x000f0000) {
10662306a36Sopenharmony_ci					mask = 0x00010000;
10762306a36Sopenharmony_ci					irq = 16;
10862306a36Sopenharmony_ci				} else {
10962306a36Sopenharmony_ci					mask = 0x00100000;
11062306a36Sopenharmony_ci					irq = 20;
11162306a36Sopenharmony_ci				}
11262306a36Sopenharmony_ci			} else {
11362306a36Sopenharmony_ci				if (pend & 0x0f000000) {
11462306a36Sopenharmony_ci					mask = 0x01000000;
11562306a36Sopenharmony_ci					irq = 24;
11662306a36Sopenharmony_ci				} else {
11762306a36Sopenharmony_ci					mask = 0x10000000;
11862306a36Sopenharmony_ci					irq = 28;
11962306a36Sopenharmony_ci				}
12062306a36Sopenharmony_ci			}
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		while (! (mask & pend)) {
12462306a36Sopenharmony_ci			mask <<=1;
12562306a36Sopenharmony_ci			irq++;
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		do_IRQ(irq, fp);
12962306a36Sopenharmony_ci		pend &= ~mask;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void intc_irq_unmask(struct irq_data *d)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	IMR &= ~(1 << d->irq);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic void intc_irq_mask(struct irq_data *d)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	IMR |= (1 << d->irq);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic struct irq_chip intc_irq_chip = {
14462306a36Sopenharmony_ci	.name		= "M68K-INTC",
14562306a36Sopenharmony_ci	.irq_mask	= intc_irq_mask,
14662306a36Sopenharmony_ci	.irq_unmask	= intc_irq_unmask,
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/*
15062306a36Sopenharmony_ci * This function should be called during kernel startup to initialize
15162306a36Sopenharmony_ci * the machine vector table.
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_civoid __init trap_init(void)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	int i;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* set up the vectors */
15862306a36Sopenharmony_ci	for (i = 72; i < 256; ++i)
15962306a36Sopenharmony_ci		_ramvec[i] = (e_vector) bad_interrupt;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	_ramvec[32] = system_call;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	_ramvec[65] = (e_vector) inthandler1;
16462306a36Sopenharmony_ci	_ramvec[66] = (e_vector) inthandler2;
16562306a36Sopenharmony_ci	_ramvec[67] = (e_vector) inthandler3;
16662306a36Sopenharmony_ci	_ramvec[68] = (e_vector) inthandler4;
16762306a36Sopenharmony_ci	_ramvec[69] = (e_vector) inthandler5;
16862306a36Sopenharmony_ci	_ramvec[70] = (e_vector) inthandler6;
16962306a36Sopenharmony_ci	_ramvec[71] = (e_vector) inthandler7;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_civoid __init init_IRQ(void)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	int i;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* turn off all interrupts */
17962306a36Sopenharmony_ci	IMR = ~0;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	for (i = 0; (i < NR_IRQS); i++) {
18262306a36Sopenharmony_ci		irq_set_chip(i, &intc_irq_chip);
18362306a36Sopenharmony_ci		irq_set_handler(i, handle_level_irq);
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
187