summaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/irq_onchip.c
blob: b4ba54f31ea2426161d0c264b1658082c0b3e5f7 (plain)
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
42
43
44
45
46
47
48
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
/* $Id$
 *
 * linux/arch/sh/kernel/irq_onchip.c
 *
 * Copyright (C) 1999  Niibe Yutaka
 *
 * Interrupt handling for on-chip supporting modules (TMU, RTC, etc.).
 *
 */

#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/malloc.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/smp.h>
#include <asm/pgtable.h>
#include <asm/delay.h>

#include <linux/irq.h>

struct ipr_data {
	int offset;
	int priority;
};
static struct ipr_data ipr_data[NR_IRQS-TIMER_IRQ];

void set_ipr_data(unsigned int irq, int offset, int priority)
{
	ipr_data[irq-TIMER_IRQ].offset = offset;
	ipr_data[irq-TIMER_IRQ].priority = priority;
}

static void enable_onChip_irq(unsigned int irq);
void disable_onChip_irq(unsigned int irq);

/* shutdown is same as "disable" */
#define shutdown_onChip_irq	disable_onChip_irq

static void mask_and_ack_onChip(unsigned int);
static void end_onChip_irq(unsigned int irq);

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

static struct hw_interrupt_type onChip_irq_type = {
	"On-Chip Supporting Module",
	startup_onChip_irq,
	shutdown_onChip_irq,
	enable_onChip_irq,
	disable_onChip_irq,
	mask_and_ack_onChip,
	end_onChip_irq
};

/*
 * These have to be protected by the irq controller spinlock
 * before being called.
 *
 *
 * IPRA  15-12  11-8  7-4  3-0
 * IPRB  15-12  11-8  7-4  3-0
 * IPRC  15-12  11-8  7-4  3-0
 *
 */
#if defined(__sh3__)
#define INTC_IPR	0xfffffee2UL	/* Word access */
#define INTC_SIZE	0x2
#elif defined(__SH4__)
#define INTC_IPR	0xffd00004UL	/* Word access */
#define INTC_SIZE	0x4
#endif

void disable_onChip_irq(unsigned int irq)
{
	/* Set priority in IPR to 0 */
	int offset = ipr_data[irq-TIMER_IRQ].offset;
	unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE);
	unsigned short mask = 0xffff ^ (0xf << (offset%16));
	unsigned long val;

	val = ctrl_inw(intc_ipr_address);
	val &= mask;
	ctrl_outw(val, intc_ipr_address);
}

static void enable_onChip_irq(unsigned int irq)
{
	/* Set priority in IPR back to original value */
	int offset = ipr_data[irq-TIMER_IRQ].offset;
	int priority = ipr_data[irq-TIMER_IRQ].priority;
	unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE);
	unsigned short value = (priority << (offset%16));
	unsigned long val;

	val = ctrl_inw(intc_ipr_address);
	val |= value;
	ctrl_outw(val, intc_ipr_address);
}

void make_onChip_irq(unsigned int irq)
{
	disable_irq_nosync(irq);
	irq_desc[irq].handler = &onChip_irq_type;
	enable_irq(irq);
}

static void mask_and_ack_onChip(unsigned int irq)
{
	disable_onChip_irq(irq);
}

static void end_onChip_irq(unsigned int irq)
{
	enable_onChip_irq(irq);
}

void __init init_IRQ(void)
{
	int i;

	for (i = TIMER_IRQ; i < NR_IRQS; i++) {
		irq_desc[i].handler = &onChip_irq_type;
	}
}