1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11#include <config.h>
12#include <arch/machine/gic_pl390.h>
13
14#define TARGET_CPU_ALLINT(CPU) ( \
15        ( ((CPU)&0xff)<<0u  ) |\
16        ( ((CPU)&0xff)<<8u  ) |\
17        ( ((CPU)&0xff)<<16u ) |\
18        ( ((CPU)&0xff)<<24u ) \
19    )
20#define TARGET_CPU0_ALLINT   TARGET_CPU_ALLINT(BIT(0))
21
22/* Use this to forward interrupts to all CPUs when debugging */
23#define TARGET_CPU_ALL_ALLINT   TARGET_CPU_ALLINT(0xff)
24
25#define IRQ_SET_ALL 0xffffffff;
26
27/* Shift positions for GICD_SGIR register */
28#define GICD_SGIR_SGIINTID_SHIFT          0
29#define GICD_SGIR_CPUTARGETLIST_SHIFT     16
30#define GICD_SGIR_TARGETLISTFILTER_SHIFT  24
31
32#ifndef GIC_PL390_DISTRIBUTOR_PPTR
33#error GIC_PL390_DISTRIBUTOR_PPTR must be defined for virtual memory access to the gic distributer
34#else  /* GIC_DISTRIBUTOR_PPTR */
35volatile struct gic_dist_map * const gic_dist =
36    (volatile struct gic_dist_map*)(GIC_PL390_DISTRIBUTOR_PPTR);
37#endif /* GIC_DISTRIBUTOR_PPTR */
38
39#ifndef GIC_PL390_CONTROLLER_PPTR
40#error GIC_PL390_CONTROLLER_PPTR must be defined for virtual memory access to the gic cpu interface
41#else  /* GIC_CONTROLLER_PPTR */
42volatile struct gic_cpu_iface_map * const gic_cpuiface =
43    (volatile struct gic_cpu_iface_map*)(GIC_PL390_CONTROLLER_PPTR);
44#endif /* GIC_CONTROLLER_PPTR */
45
46uint32_t active_irq[CONFIG_MAX_NUM_NODES] = {IRQ_NONE};
47
48/* Get the target id for this processor. We rely on the constraint that the registers
49 * for PPI are read only and return only the current processor as the target.
50 * If this doesn't lead to a valid ID, we emit a warning and default to core 0.
51 */
52BOOT_CODE static uint8_t
53infer_cpu_gic_id(int nirqs)
54{
55    word_t i;
56    uint32_t target = 0;
57    for (i = 0; i < nirqs; i += 4) {
58        target = gic_dist->targets[i >> 2];
59        target |= target >> 16;
60        target |= target >> 8;
61        if (target) {
62            break;
63        }
64    }
65    if (!target) {
66        printf("Warning: Could not infer GIC interrupt target ID, assuming 0.\n");
67        target = BIT(0);
68    }
69    return target & 0xff;
70}
71
72BOOT_CODE static void
73dist_init(void)
74{
75    word_t i;
76    int nirqs = 32 * ((gic_dist->ic_type & 0x1f) + 1);
77    gic_dist->enable = 0;
78
79    for (i = 0; i < nirqs; i += 32) {
80        /* disable */
81        gic_dist->enable_clr[i >> 5] = IRQ_SET_ALL;
82        /* clear pending */
83        gic_dist->pending_clr[i >> 5] = IRQ_SET_ALL;
84    }
85
86    /* reset interrupts priority */
87    for (i = 32; i < nirqs; i += 4) {
88        if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) {
89            gic_dist->priority[i >> 2] = 0x80808080;
90        } else {
91            gic_dist->priority[i >> 2] = 0;
92        }
93    }
94
95    /*
96     * reset int target to current cpu
97     * We query which id that the GIC uses for us and use that.
98     */
99    uint8_t target = infer_cpu_gic_id(nirqs);
100    for (i = 0; i < nirqs; i += 4) {
101        gic_dist->targets[i >> 2] = TARGET_CPU_ALLINT(target);
102    }
103
104    /* level-triggered, 1-N */
105    for (i = 64; i < nirqs; i += 32) {
106        gic_dist->config[i >> 5] = 0x55555555;
107    }
108
109    /* group 0 for secure; group 1 for non-secure */
110    for (i = 0; i < nirqs; i += 32) {
111        if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) {
112            gic_dist->security[i >> 5] = 0xffffffff;
113        } else {
114            gic_dist->security[i >> 5] = 0;
115        }
116    }
117    /* enable the int controller */
118    gic_dist->enable = 1;
119}
120
121BOOT_CODE static void
122cpu_iface_init(void)
123{
124    uint32_t i;
125
126    /* For non-Exynos4, the registers are banked per CPU, need to clear them */
127    gic_dist->enable_clr[0] = IRQ_SET_ALL;
128    gic_dist->pending_clr[0] = IRQ_SET_ALL;
129
130    /* put everything in group 0; group 1 if in hyp mode */
131    if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) {
132        gic_dist->security[0] = 0xffffffff;
133        gic_dist->priority[0] = 0x80808080;
134    } else {
135        gic_dist->security[0] = 0;
136        gic_dist->priority[0] = 0x0;
137    }
138
139    /* clear any software generated interrupts */
140    for (i = 0; i < 16; i += 4) {
141        gic_dist->sgi_pending_clr[i >> 2] = IRQ_SET_ALL;
142    }
143
144    gic_cpuiface->icontrol = 0;
145    /* the write to priority mask is ignored if the kernel is
146     * in non-secure mode and the priority mask is already configured
147     * by secure mode software. the elfloader should config the
148     * interrupt routing properly to ensure that the hyp-mode kernel
149     * can get interrupts
150     */
151    gic_cpuiface->pri_msk_c = 0x000000f0;
152    gic_cpuiface->pb_c = 0x00000003;
153
154    i = gic_cpuiface->int_ack;
155    while ((i & IRQ_MASK) != IRQ_NONE) {
156        gic_cpuiface->eoi = i;
157        i = gic_cpuiface->int_ack;
158    }
159    gic_cpuiface->icontrol = 1;
160}
161
162void setIRQTrigger(irq_t irq, bool_t trigger)
163{
164    /* in the gic_config, there is a 2 bit field for each irq,
165     * setting the most significant bit of this field makes the irq edge-triggered,
166     * while 0 indicates that it is level-triggered */
167    word_t index = irq / 16u;
168    word_t offset = (irq % 16u) * 2;
169    if (trigger) {
170        /* set the bit */
171        gic_dist->config[index] |= BIT(offset + 1);
172    } else {
173        gic_dist->config[index] &= ~BIT(offset + 1);
174    }
175}
176
177BOOT_CODE void
178initIRQController(void)
179{
180    dist_init();
181}
182
183BOOT_CODE void cpu_initLocalIRQController(void)
184{
185    cpu_iface_init();
186}
187
188#ifdef ENABLE_SMP_SUPPORT
189/*
190* 25-24: target lister filter
191* 0b00 - send the ipi to the CPU interfaces specified in the CPU target list
192* 0b01 - send the ipi to all CPU interfaces except the cpu interface.
193*        that requrested teh ipi
194* 0b10 - send the ipi only to the CPU interface that requested the IPI.
195* 0b11 - reserved
196*.
197* 23-16: CPU targets list
198* each bit of CPU target list [7:0] refers to the corresponding CPU interface.
199* 3-0:   SGIINTID
200* software generated interrupt id, from 0 to 15...
201*/
202void ipiBroadcast(irq_t irq, bool_t includeSelfCPU)
203{
204    gic_dist->sgi_control = (!includeSelfCPU << GICD_SGIR_TARGETLISTFILTER_SHIFT) | (irq << GICD_SGIR_SGIINTID_SHIFT);
205}
206
207void ipi_send_target(irq_t irq, word_t cpuTargetList)
208{
209    gic_dist->sgi_control = (cpuTargetList << GICD_SGIR_CPUTARGETLIST_SHIFT) | (irq << GICD_SGIR_SGIINTID_SHIFT);
210}
211#endif /* ENABLE_SMP_SUPPORT */
212
213#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
214
215#ifndef GIC_PL400_VCPUCTRL_PPTR
216#error GIC_PL400_VCPUCTRL_PPTR must be defined for virtual memory access to the gic virtual cpu interface control
217#else  /* GIC_PL400_GICVCPUCTRL_PPTR */
218volatile struct gich_vcpu_ctrl_map *gic_vcpu_ctrl =
219    (volatile struct gich_vcpu_ctrl_map*)(GIC_PL400_VCPUCTRL_PPTR);
220#endif /* GIC_PL400_GICVCPUCTRL_PPTR */
221
222unsigned int gic_vcpu_num_list_regs;
223
224#endif /* End of CONFIG_ARM_HYPERVISOR_SUPPORT */
225