Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-davinci/cp_intc.c
10699 views
1
/*
2
* TI Common Platform Interrupt Controller (cp_intc) driver
3
*
4
* Author: Steve Chen <[email protected]>
5
* Copyright (C) 2008-2009, MontaVista Software, Inc. <[email protected]>
6
*
7
* This file is licensed under the terms of the GNU General Public License
8
* version 2. This program is licensed "as is" without any warranty of any
9
* kind, whether express or implied.
10
*/
11
12
#include <linux/init.h>
13
#include <linux/irq.h>
14
#include <linux/io.h>
15
16
#include <mach/common.h>
17
#include <mach/cp_intc.h>
18
19
static inline unsigned int cp_intc_read(unsigned offset)
20
{
21
return __raw_readl(davinci_intc_base + offset);
22
}
23
24
static inline void cp_intc_write(unsigned long value, unsigned offset)
25
{
26
__raw_writel(value, davinci_intc_base + offset);
27
}
28
29
static void cp_intc_ack_irq(struct irq_data *d)
30
{
31
cp_intc_write(d->irq, CP_INTC_SYS_STAT_IDX_CLR);
32
}
33
34
/* Disable interrupt */
35
static void cp_intc_mask_irq(struct irq_data *d)
36
{
37
/* XXX don't know why we need to disable nIRQ here... */
38
cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR);
39
cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_CLR);
40
cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
41
}
42
43
/* Enable interrupt */
44
static void cp_intc_unmask_irq(struct irq_data *d)
45
{
46
cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_SET);
47
}
48
49
static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type)
50
{
51
unsigned reg = BIT_WORD(d->irq);
52
unsigned mask = BIT_MASK(d->irq);
53
unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg));
54
unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg));
55
56
switch (flow_type) {
57
case IRQ_TYPE_EDGE_RISING:
58
polarity |= mask;
59
type |= mask;
60
break;
61
case IRQ_TYPE_EDGE_FALLING:
62
polarity &= ~mask;
63
type |= mask;
64
break;
65
case IRQ_TYPE_LEVEL_HIGH:
66
polarity |= mask;
67
type &= ~mask;
68
break;
69
case IRQ_TYPE_LEVEL_LOW:
70
polarity &= ~mask;
71
type &= ~mask;
72
break;
73
default:
74
return -EINVAL;
75
}
76
77
cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg));
78
cp_intc_write(type, CP_INTC_SYS_TYPE(reg));
79
80
return 0;
81
}
82
83
/*
84
* Faking this allows us to to work with suspend functions of
85
* generic drivers which call {enable|disable}_irq_wake for
86
* wake up interrupt sources (eg RTC on DA850).
87
*/
88
static int cp_intc_set_wake(struct irq_data *d, unsigned int on)
89
{
90
return 0;
91
}
92
93
static struct irq_chip cp_intc_irq_chip = {
94
.name = "cp_intc",
95
.irq_ack = cp_intc_ack_irq,
96
.irq_mask = cp_intc_mask_irq,
97
.irq_unmask = cp_intc_unmask_irq,
98
.irq_set_type = cp_intc_set_irq_type,
99
.irq_set_wake = cp_intc_set_wake,
100
};
101
102
void __init cp_intc_init(void)
103
{
104
unsigned long num_irq = davinci_soc_info.intc_irq_num;
105
u8 *irq_prio = davinci_soc_info.intc_irq_prios;
106
u32 *host_map = davinci_soc_info.intc_host_map;
107
unsigned num_reg = BITS_TO_LONGS(num_irq);
108
int i;
109
110
davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC;
111
davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K);
112
if (WARN_ON(!davinci_intc_base))
113
return;
114
115
cp_intc_write(0, CP_INTC_GLOBAL_ENABLE);
116
117
/* Disable all host interrupts */
118
cp_intc_write(0, CP_INTC_HOST_ENABLE(0));
119
120
/* Disable system interrupts */
121
for (i = 0; i < num_reg; i++)
122
cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i));
123
124
/* Set to normal mode, no nesting, no priority hold */
125
cp_intc_write(0, CP_INTC_CTRL);
126
cp_intc_write(0, CP_INTC_HOST_CTRL);
127
128
/* Clear system interrupt status */
129
for (i = 0; i < num_reg; i++)
130
cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i));
131
132
/* Enable nIRQ (what about nFIQ?) */
133
cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
134
135
/*
136
* Priority is determined by host channel: lower channel number has
137
* higher priority i.e. channel 0 has highest priority and channel 31
138
* had the lowest priority.
139
*/
140
num_reg = (num_irq + 3) >> 2; /* 4 channels per register */
141
if (irq_prio) {
142
unsigned j, k;
143
u32 val;
144
145
for (k = i = 0; i < num_reg; i++) {
146
for (val = j = 0; j < 4; j++, k++) {
147
val >>= 8;
148
if (k < num_irq)
149
val |= irq_prio[k] << 24;
150
}
151
152
cp_intc_write(val, CP_INTC_CHAN_MAP(i));
153
}
154
} else {
155
/*
156
* Default everything to channel 15 if priority not specified.
157
* Note that channel 0-1 are mapped to nFIQ and channels 2-31
158
* are mapped to nIRQ.
159
*/
160
for (i = 0; i < num_reg; i++)
161
cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i));
162
}
163
164
if (host_map)
165
for (i = 0; host_map[i] != -1; i++)
166
cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i));
167
168
/* Set up genirq dispatching for cp_intc */
169
for (i = 0; i < num_irq; i++) {
170
irq_set_chip(i, &cp_intc_irq_chip);
171
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
172
irq_set_handler(i, handle_edge_irq);
173
}
174
175
/* Enable global interrupt */
176
cp_intc_write(1, CP_INTC_GLOBAL_ENABLE);
177
}
178
179