1/*
2 * Copyright (c) 2012, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
8 */
9
10#include <kernel.h>
11
12#include <dev/pl130_gic_dev.h>
13#include <arch/arm/gic.h>
14#include <platform.h>
15#include <paging_kernel_arch.h>
16
17static pl130_gic_t gic;
18static uint32_t it_num_lines;
19static pl130_gic_ICDICTR_t gic_config;
20static uint8_t cpu_number;
21
22#define MSG(format, ...) printk( LOG_NOTE, "GIC: "format, ## __VA_ARGS__ )
23
24enum IrqType {
25    IrqType_SGI,
26    IrqType_PPI,
27    IrqType_SPI
28};
29
30#define DIST_SIZE 0x1000
31#define CPU_SIZE  0x1000
32
33/**
34 * \brief Returns the IRQ type based on the interrupt ID
35 *
36 * We have three types of interrupts
37 * 1) Software generated Interrupts (SGI): IDs 0-15
38 * 2) Private Peripheral Interrupts (PPI): IDs 16-31
39 * 3) Shared Peripheral Interrups (SPI): IDs 32-
40 *
41 * \return The type of the interrupt.
42 */
43static enum IrqType get_irq_type(uint32_t int_id)
44{
45    if (int_id < 16) {
46        return IrqType_SGI;
47    } else if (int_id < 32) {
48        return IrqType_PPI;
49    } else {
50        return IrqType_SPI;
51    }
52}
53
54/*
55 * Initialize the global interrupt controller
56 *
57 * There are three types of interrupts
58 * 1) Software generated Interrupts (SGI) - IDs 0-15
59 * 2) Private Peripheral Interrupts (PPI) - IDs 16-31
60 * 3) Shared Peripheral Interrups (SPI) - IDs 32...
61 */
62void gic_init(void)
63{
64    lvaddr_t gic_dist_base =
65        paging_map_device( platform_get_distributor_address(), DIST_SIZE );
66    lvaddr_t gic_cpu_base =
67        paging_map_device( platform_get_gic_cpu_address(), CPU_SIZE );
68    pl130_gic_initialize(&gic, (mackerel_addr_t)gic_dist_base,
69                               (mackerel_addr_t)gic_cpu_base );
70
71    // read GIC configuration
72    gic_config = pl130_gic_ICDICTR_rd(&gic);
73
74    // ARM GIC 2.0 TRM, Table 4-6
75    // This is the number of ICDISERs, i.e. #SPIs
76    // Number of SGIs (0-15) and PPIs (16-31) is fixed
77    uint32_t it_num_lines_tmp =
78        pl130_gic_ICDICTR_it_lines_num_extract(gic_config);
79    it_num_lines = 32*(it_num_lines_tmp + 1);
80
81    MSG("%d interrupt lines detected\n", it_num_lines);
82
83    cpu_number = pl130_gic_ICDICTR_cpu_number_extract(gic_config) + 1;
84
85    // set priority mask of cpu interface, currently set to lowest priority
86    // to accept all interrupts
87    pl130_gic_ICCPMR_wr(&gic, 0xff);
88
89    // set binary point to define split of group- and subpriority
90    // currently we allow for 8 subpriorities
91    pl130_gic_ICCBPR_wr(&gic, 0x2);
92
93    // enable interrupt forwarding to processor
94    pl130_gic_ICCICR_enable_wrf(&gic, 0x1);
95
96    // Distributor:
97    // enable interrupt forwarding from distributor to cpu interface
98    pl130_gic_ICDDCR_enable_wrf(&gic, 0x1);
99    MSG("gic_init done\n");
100}
101
102size_t
103gic_cpu_count(void) {
104    return cpu_number;
105}
106
107void  __attribute__((noreturn)) gic_disable_all_irqs(void)
108{
109    panic("gic_disable_all_irqs NYI for armv7");
110    // XXX Rewrite according to pl130 interface changes!
111    // ALSO remove noreturn option
112
113    /* //disable PPI interrupts */
114    /* pl130_gic_PPI_ICDICER_wr(&gic, (uint16_t)0xffff); */
115
116    /* //disable SPI interrupts */
117    /* for(uint8_t i=0; i < it_num_lines; i++) { */
118    /*     pl130_gic_SPI_ICDICER_wr(&gic, i, (uint32_t)0xffffffff); */
119    /* } */
120}
121
122uint32_t gic_get_active_irq(void)
123{
124    uint32_t regval = pl130_gic_ICCIAR_rd(&gic);
125
126    return regval;
127}
128
129void gic_raise_softirq(uint8_t cpumask, uint8_t irq)
130{
131    uint32_t regval = (cpumask << 16) | irq;
132    pl130_gic_ICDSGIR_wr(&gic, regval);
133}
134
135void gic_ack_irq(uint32_t irq)
136{
137    pl130_gic_ICCEOIR_rawwr(&gic, irq);
138}
139
140//enable interrupt forwarding to processor
141void gic_cpu_interface_enable(void)
142{
143    pl130_gic_ICCICR_wr(&gic, 0x1);
144}
145
146
147/**
148 * \brief Enable an interrupt
149 *
150 * \see ARM Generic Interrupt Controller Architecture Specification v1.0
151 *
152 * \param int_id
153 * \param cpu_targets 8 Bit mask. One bit for each core in the system.
154 *    (chapter 4.3.11)
155 * \param prio Priority of the interrupt (lower is higher). We allow 0..15.
156 *    The number of priority bits is implementation specific, but at least 16
157 *    (using bits [7:4] of the priority field, chapter 3.3)
158 * \param 0 is level-sensitive, 1 is edge-triggered
159 * \param 0 is N-to-N, 1 is 1-N
160 */
161void gic_enable_interrupt(uint32_t int_id, uint8_t cpu_targets, uint16_t prio,
162                          bool edge_triggered, bool one_to_n)
163{
164    // Set Interrupt Set-Enable Register
165    uint32_t ind = int_id / 32;
166    uint32_t bit_mask = (1U << (int_id % 32));
167    uint32_t regval;
168
169    MSG("gic_enable_interrupt for id=0x%"PRIx32", "
170           "offset=0x%"PRIx32", index=0x%"PRIx32"\n",
171           int_id, bit_mask, ind);
172
173    enum IrqType irq_type = get_irq_type(int_id);
174
175    // Set the Interrupt Set Enable register to enable the interupt
176    // See ARM GIC TRM
177    if (irq_type == IrqType_SGI) {
178        MSG("unhandled SGI IRQ %d\n", int_id);
179        return;    // Do nothing for SGI interrupts
180    }
181
182    // XXX: check what we need to do if int_id > it_num_lines
183    //  -SG, 2012/12/13
184    assert(int_id <= it_num_lines);
185
186    // Enable
187    // 1 Bit per interrupt
188    regval = pl130_gic_ICDISER_rd(&gic, ind);
189    regval |= bit_mask;
190    pl130_gic_ICDISER_wr(&gic, ind, regval);
191
192    // TODO: cleanup pl130 mackerel file so that we don't need bit magic
193    // here.  -SG, 2012/12/13
194
195    // Priority
196    // 8 Bit per interrupt
197    // chp 4.3.10
198    ind = int_id/4;
199    // XXX: check that priorities work properly, -SG, 2012/12/13
200    prio = (prio & 0xF)<<4;
201    switch(int_id % 4) {
202    case 0:
203        pl130_gic_ICDIPR_prio_off0_wrf(&gic, ind, prio);
204        break;
205    case 1:
206        pl130_gic_ICDIPR_prio_off1_wrf(&gic, ind, prio);
207        break;
208    case 2:
209        pl130_gic_ICDIPR_prio_off2_wrf(&gic, ind, prio);
210        break;
211    case 3:
212        pl130_gic_ICDIPR_prio_off3_wrf(&gic, ind, prio);
213        break;
214    }
215
216    // Target processors (only SPIs)
217    // 8 Bit per interrupt
218    ind = int_id/4;
219    if (irq_type == IrqType_SPI) { // rest is ro
220        switch (int_id % 4) {
221        case 0:
222            pl130_gic_ICDIPTR_targets_off0_wrf(&gic, ind, cpu_targets);
223            break;
224        case 1:
225            pl130_gic_ICDIPTR_targets_off1_wrf(&gic, ind, cpu_targets);
226            break;
227        case 2:
228            pl130_gic_ICDIPTR_targets_off2_wrf(&gic, ind, cpu_targets);
229            break;
230        case 3:
231            pl130_gic_ICDIPTR_targets_off3_wrf(&gic, ind, cpu_targets);
232            break;
233        }
234    }
235
236    // Configuration registers
237    // 2 Bit per IRQ
238    ind = int_id/16;
239    uint8_t val = ((edge_triggered&0x1) << 1) | (one_to_n&0x1);
240    switch (int_id % 16) {
241    case 0:
242        pl130_gic_ICDICR_conf0_wrf(&gic, ind, val);
243        break;
244    case 1:
245        pl130_gic_ICDICR_conf1_wrf(&gic, ind, val);
246        break;
247    case 2:
248        pl130_gic_ICDICR_conf2_wrf(&gic, ind, val);
249        break;
250    case 3:
251        pl130_gic_ICDICR_conf3_wrf(&gic, ind, val);
252        break;
253    case 4:
254        pl130_gic_ICDICR_conf4_wrf(&gic, ind, val);
255        break;
256    case 5:
257        pl130_gic_ICDICR_conf5_wrf(&gic, ind, val);
258        break;
259    case 6:
260        pl130_gic_ICDICR_conf6_wrf(&gic, ind, val);
261        break;
262    case 7:
263        pl130_gic_ICDICR_conf7_wrf(&gic, ind, val);
264        break;
265    case 8:
266        pl130_gic_ICDICR_conf8_wrf(&gic, ind, val);
267        break;
268    case 9:
269        pl130_gic_ICDICR_conf9_wrf(&gic, ind, val);
270        break;
271    case 10:
272        pl130_gic_ICDICR_conf10_wrf(&gic, ind, val);
273        break;
274    case 11:
275        pl130_gic_ICDICR_conf11_wrf(&gic, ind, val);
276        break;
277    case 12:
278        pl130_gic_ICDICR_conf12_wrf(&gic, ind, val);
279        break;
280    case 13:
281        pl130_gic_ICDICR_conf13_wrf(&gic, ind, val);
282        break;
283    case 14:
284        pl130_gic_ICDICR_conf14_wrf(&gic, ind, val);
285        break;
286    case 15:
287        pl130_gic_ICDICR_conf15_wrf(&gic, ind, val);
288        break;
289    }
290}
291
292