OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [src/] [drivers/] [irq/] [gic/] [gic.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Generic Interrupt Controller support.
3
 *
4
 * Copyright (C) 2009-2010 B Labs Ltd.
5
 *
6
 * Authors: Prem Mallappa, Bahadir Balban
7
 */
8
#include <l4/lib/bit.h>
9
#include <l4/lib/printk.h>
10
#include <l4/generic/irq.h>
11
#include INC_PLAT(irq.h)
12
#include INC_SUBARCH(mmu_ops.h)
13
#include <l4/drivers/irq/gic/gic.h>
14
#include <l4/generic/smp.h>
15
 
16
#define GIC_ACK_IRQ_MASK                0x1FF
17
#define GIC_ACK_CPU_MASK                0xE00
18
#define GIC_IRQ_SPURIOUS                0x3FF
19
 
20
volatile struct gic_data gic_data[IRQ_CHIPS_MAX];
21
 
22
static inline struct gic_data *get_gic_data(l4id_t irq)
23
{
24
        volatile struct irq_chip *chip = irq_desc_array[irq].chip;
25
 
26
        if (chip)
27
                return (struct gic_data *)chip->data;
28
        else
29
                return 0;
30
}
31
 
32
/* Returns the irq number on this chip converting the irq bitvector */
33
l4id_t gic_read_irq(void *data)
34
{
35
        volatile struct gic_data *gic = (struct gic_data *)data;
36
        l4id_t irq = gic->cpu->ack;
37
 
38
        /* This is an IPI - EOI it here, since it requires cpu field */
39
        if ((irq & GIC_ACK_IRQ_MASK) < 16) {
40
                gic_eoi_irq(irq);
41
                /* Get the actual irq number */
42
                irq &= GIC_ACK_IRQ_MASK;
43
        }
44
 
45
        /* Detect GIC spurious magic value and return generic one */
46
        if (irq == GIC_IRQ_SPURIOUS)
47
                return IRQ_SPURIOUS;
48
        return irq;
49
}
50
 
51
void gic_mask_irq(l4id_t irq)
52
{
53
        volatile struct gic_data *gic = get_gic_data(irq);
54
        u32 offset = irq >> 5; /* irq / 32 */
55
 
56
        gic->dist->clr_en[offset] = 1 << (irq % 32);
57
}
58
 
59
void gic_unmask_irq(l4id_t irq)
60
{
61
        volatile struct gic_data *gic = get_gic_data(irq);
62
        u32 offset = irq >> 5 ; /* irq / 32 */
63
 
64
        gic->dist->set_en[offset] = 1 << (irq % 32);
65
}
66
 
67
void gic_eoi_irq(l4id_t irq)
68
{
69
        /* Careful, irq may have cpu field encoded */
70
        volatile struct gic_data *gic =
71
                get_gic_data(irq & GIC_ACK_IRQ_MASK);
72
 
73
        gic->cpu->eoi = irq;
74
}
75
 
76
void gic_ack_and_mask(l4id_t irq)
77
{
78
        //printk("disable/eoi irq %d\n", irq);
79
        gic_mask_irq(irq);
80
        gic_eoi_irq(irq);
81
}
82
 
83
void gic_set_pending(l4id_t irq)
84
{
85
        volatile struct gic_data *gic = get_gic_data(irq);
86
        u32 offset = irq >> 5; /* irq / 32 */
87
        gic->dist->set_pending[offset] = 1 << (irq % 32);
88
}
89
 
90
void gic_clear_pending(l4id_t irq)
91
{
92
        volatile struct gic_data *gic = get_gic_data(irq);
93
        u32 offset = irq >> 5; /* irq / 32 */
94
 
95
        gic->dist->clr_pending[offset] = 1 << (irq % 32);
96
}
97
 
98
 
99
void gic_cpu_init(int idx, unsigned long base)
100
{
101
        volatile struct gic_cpu *cpu;
102
 
103
        gic_data[idx].cpu = (struct gic_cpu *)base;
104
 
105
        cpu = gic_data[idx].cpu;
106
 
107
        /* Disable */
108
        cpu->control = 0;
109
 
110
        /* Set */
111
        cpu->prio_mask = 0xf0;
112
        cpu->bin_point = 3;
113
 
114
        /* Enable */
115
        cpu->control = 1;
116
}
117
 
118
void gic_dist_init(int idx, unsigned long base)
119
{
120
        volatile struct gic_dist *dist;
121
        int irqs_per_word;
122
        int nirqs;
123
 
124
        gic_data[idx].dist = (struct gic_dist *)(base);
125
 
126
        dist = gic_data[idx].dist;
127
 
128
        /* Disable gic */
129
        dist->control = 0;
130
 
131
        /* 32*(N+1) interrupts supported */
132
        nirqs = 32 * ((dist->type & 0x1f) + 1);
133
        if (nirqs > IRQS_MAX)
134
                nirqs = IRQS_MAX;
135
 
136
        /* Disable all interrupts */
137
        irqs_per_word = 32;
138
        for (int i = 0; i < nirqs; i += irqs_per_word)
139
                dist->clr_en[i/irqs_per_word] = 0xffffffff;
140
 
141
        /* Clear all pending interrupts */
142
        for (int i = 0; i < nirqs; i += irqs_per_word)
143
                dist->clr_pending[i/irqs_per_word] = 0xffffffff;
144
 
145
        /* Set all irqs as normal priority, 8 bits per interrupt */
146
        irqs_per_word = 4;
147
        for (int i = 32; i < nirqs; i += irqs_per_word)
148
                dist->priority[i/irqs_per_word] = 0xa0a0a0a0;
149
 
150
        /* Set all target to cpu0, 8 bits per interrupt */
151
        for (int i = 32; i < nirqs; i += irqs_per_word)
152
                dist->target[i/irqs_per_word] = 0x01010101;
153
 
154
        /* Configure all to be level-sensitive, 2 bits per interrupt */
155
        irqs_per_word = 16;
156
        for (int i = 32; i < nirqs; i += irqs_per_word)
157
                dist->config[i/irqs_per_word] = 0x00000000;
158
 
159
        /* Enable GIC Distributor */
160
        dist->control = 1;
161
}
162
 
163
 
164
/* Some functions, may be helpful */
165
void gic_set_target(l4id_t irq, u32 cpu)
166
{
167
        volatile struct gic_data *gic = get_gic_data(irq);
168
        u32 offset = irq >> 2; /* irq / 4 */
169
 
170
        if (cpu > 1) {
171
                printk("Setting irqs to reach multiple cpu targets requires a"
172
                       "lock on the irq controller\n"
173
                       "GIC is a racy hardware in this respect\n");
174
                BUG();
175
        }
176
 
177
        gic->dist->target[offset] |= (cpu << ((irq % 4) * 8));
178
}
179
 
180
u32 gic_get_target(u32 irq)
181
{
182
        volatile struct gic_data *gic = get_gic_data(irq);
183
        u32 offset = irq >> 2; /* irq / 4 */
184
        unsigned int target = gic->dist->target[offset];
185
 
186
        BUG_ON(irq > 0xFF);
187
        target >>= ((irq % 4) * 8);
188
 
189
        return target & 0xFF;
190
}
191
 
192
void gic_set_priority(u32 irq, u32 prio)
193
{
194
        volatile struct gic_data *gic = get_gic_data(irq);
195
        u32 offset = irq >> 3; /* irq / 8 */
196
 
197
        BUG_ON(prio > 0xF);
198
        BUG_ON(irq > 0xFF);
199
 
200
        /* target = cpu << ((irq % 4) * 4) */
201
        gic->dist->target[offset] |= (prio << (irq & 0x1C));
202
}
203
 
204
u32 gic_get_priority(u32 irq)
205
{
206
        volatile struct gic_data *gic = get_gic_data(irq);
207
        u32 offset = irq >> 3; /* offset = irq / 8 */
208
        u32 prio = gic->dist->target[offset] & (irq & 0xFC);
209
 
210
        return prio;
211
}
212
 
213
#define IPI_CPU_SHIFT   16
214
 
215
void gic_send_ipi(int cpumask, int ipi_cmd)
216
{
217
        volatile struct gic_dist *dist = gic_data[0].dist;
218
        unsigned int ipi_word = (cpumask << IPI_CPU_SHIFT) | ipi_cmd;
219
 
220
        dist->soft_int = ipi_word;
221
}
222
 
223
void gic_print_cpu()
224
{
225
        volatile struct gic_cpu *cpu = gic_data[0].cpu;
226
 
227
        printk("GIC CPU%d highest pending: %d\n", smp_get_cpuid(), cpu->high_pending);
228
        printk("GIC CPU%d running: %d\n", smp_get_cpuid(), cpu->running);
229
}
230
 
231
/* Make the generic code happy */
232
void gic_dummy_init()
233
{
234
 
235
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.