1/*
2 * Copyright (c) 2016, 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, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <kernel.h>
11#include <sysreg.h>
12#include <dev/armv8_dev.h>
13#include <dev/gic_v3_dist_dev.h>
14#include <dev/gic_v2_cpu_dev.h>
15#include <paging_kernel_arch.h>
16#include <arch/arm/gic.h>
17#include <arch/arm/platform.h>
18#include <getopt/getopt.h>
19
20static gic_v3_dist_t gic_v3_dev;
21static gic_v2_cpu_t gic_v2_cpu_dev;
22
23extern lpaddr_t platform_gic_cpu_interface_base;
24extern lpaddr_t platform_gic_distributor_base;
25
26// Command line arguments
27static struct cmdarg cmdargs[] = {
28    {"gic", ArgType_ULong, { .ulonginteger = &platform_gic_cpu_interface_base }},
29    {"gicdist", ArgType_ULong, { .ulonginteger = &platform_gic_distributor_base }}
30};
31
32/*
33 * This should return 1<<my_core_id
34 */
35static uint8_t gic_get_cpumask(void)
36{
37    uint32_t mask = gic_v3_dist_GICD_ITARGETSR_rd(&gic_v3_dev , 0);
38    mask |= mask >> 16;
39    mask |= mask >> 8;
40    return mask;
41}
42
43/*
44 * Reads th STATUSR register, prints error on error condition
45 */
46static void check_cpu_if_statusr(void)
47{
48    // gic_v2_cpu_STATUSR_t raw =  gic_v2_cpu_STATUSR_rawrd(&gic_v2_cpu_dev);
49    // if (raw) {
50    //     char buf[512];
51    //     gic_v2_cpu_STATUSR_pr(buf,sizeof(buf),&gic_v2_cpu_dev);
52    //     printk(LOG_NOTE, "gic_v2: Error condition! Status: %s\n", buf);
53    // }
54}
55
56/*
57 * Initialize the global interrupt controller
58 *
59 * There are three types of interrupts
60 * 1) Software generated Interrupts (SGI) - IDs 0-15
61 * 2) Private Peripheral Interrupts (PPI) - IDs 16-31
62 * 3) Shared Peripheral Interrups (SPI) - IDs 32...
63 */
64void gic_init(void)
65{
66    printk(LOG_NOTE, "GICv2: Initializing\n");
67    parse_commandline(kernel_command_line, cmdargs);
68
69    lvaddr_t gic_dist = local_phys_to_mem(platform_gic_distributor_base);
70    gic_v3_dist_initialize(&gic_v3_dev, (char *)gic_dist);
71
72    lvaddr_t gic_cpu = local_phys_to_mem(platform_gic_cpu_interface_base);
73    gic_v2_cpu_initialize(&gic_v2_cpu_dev, (char *)gic_cpu);
74
75    if (gic_v3_dist_GICD_TYPER_SecurityExtn_rdf(&gic_v3_dev)) {
76        printk(LOG_NOTE, "gic_v2: In init. GIC supports secure mode\n");
77    } else {
78        printk(LOG_NOTE, "gic_v2: In init. GIC does not support secure mode\n");
79    }
80}
81
82/*
83 * Returns active interrupt of group 1
84 */
85uint32_t platform_get_active_irq(void)
86{
87    uint32_t res = gic_v2_cpu_IAR_intid_rdf(&gic_v2_cpu_dev);
88    check_cpu_if_statusr();
89    return res;
90}
91
92/*
93 * ACKs group 1 interrupt
94 */
95void platform_acknowledge_irq(uint32_t irq)
96{
97    gic_v2_cpu_EOIR_t reg = 0;
98    reg = gic_v2_cpu_EOIR_intid_insert(reg, irq);
99    gic_v2_cpu_EOIR_rawwr(&gic_v2_cpu_dev, irq);
100    check_cpu_if_statusr();
101}
102
103/*
104 * Raise an SGI on a core.
105 */
106void gic_raise_softirq(coreid_t cpuid, uint8_t irq)
107{
108    // assuming affinity routing DISABLED
109    assert(irq <= 15);
110    gic_v3_dist_GICD_SGIR_t reg = 0;
111    reg = gic_v3_dist_GICD_SGIR_INTID_insert(reg, irq);
112    reg = gic_v3_dist_GICD_SGIR_CPUTargetList_insert(reg, 1<<(cpuid));
113    gic_v3_dist_GICD_SGIR_wr(&gic_v3_dev, reg);
114    check_cpu_if_statusr();
115}
116
117/*
118 * Enable GIC CPU-IF and local distributor
119 */
120void gic_cpu_interface_enable(void)
121{
122    printk(LOG_NOTE, "gic_v2: GICC IIDR "
123            "implementer=0x%x, revision=0x%x, variant=0x%x, prodid=0x%x, raw=0x%x\n",
124            gic_v2_cpu_IIDR_Implementer_rdf(&gic_v2_cpu_dev),
125            gic_v2_cpu_IIDR_Revision_rdf(&gic_v2_cpu_dev),
126            gic_v2_cpu_IIDR_Variant_rdf(&gic_v2_cpu_dev),
127            gic_v2_cpu_IIDR_ProductID_rdf(&gic_v2_cpu_dev),
128            gic_v2_cpu_IIDR_rawrd(&gic_v2_cpu_dev)
129            );
130
131    // Do as Linux does:
132    // set priority mode: PMR to 0xf0
133    gic_v2_cpu_PMR_wr(&gic_v2_cpu_dev, 0xf0);
134    check_cpu_if_statusr();
135    // Set binary point to 1: 6 group priority bits, 2 subpriority bits
136    gic_v2_cpu_BPR_wr(&gic_v2_cpu_dev, 1);
137    check_cpu_if_statusr();
138
139    //We enable both group 0 and 1, but let both trigger IRQs (and not FIQs)
140    gic_v2_cpu_CTLR_NS_rawwr(&gic_v2_cpu_dev, 3);  // code for non-secure
141    gic_v2_cpu_CTLR_FIQEn_wrf(&gic_v2_cpu_dev, 0); // route both groups to IRQ
142
143    // Disable all GIC bypassing (no wake-up interrupts). This does not
144    // seem to have any effect?
145    gic_v2_cpu_CTLR_FIQBypDisGrp1_wrf(&gic_v2_cpu_dev, 1);
146    gic_v2_cpu_CTLR_FIQBypDisGrp0_wrf(&gic_v2_cpu_dev, 1);
147    gic_v2_cpu_CTLR_IRQBypDisGrp1_wrf(&gic_v2_cpu_dev, 1);
148    gic_v2_cpu_CTLR_IRQBypDisGrp0_wrf(&gic_v2_cpu_dev, 1);
149    check_cpu_if_statusr();
150
151    gic_v3_dist_GICD_CTLR_secure_t ctrl = 0;
152    // Set affinity routing (redundant on CN88xx)
153    ctrl = gic_v3_dist_GICD_CTLR_secure_ARE_NS_insert(ctrl, 1);
154    // Enable group 1 interrupts
155    ctrl = gic_v3_dist_GICD_CTLR_secure_EnableGrp1NS_insert(ctrl, 1);
156    gic_v3_dist_GICD_CTLR_secure_wr(&gic_v3_dev, ctrl);
157
158    check_cpu_if_statusr();
159
160    printk(LOG_NOTE, "gic_v2: GICD IIDR "
161            "implementer=0x%x, revision=0x%x, variant=0x%x, prodid=0x%x, raw=0x%x\n",
162            gic_v3_dist_GICD_IIDR_Implementer_rdf(&gic_v3_dev),
163            gic_v3_dist_GICD_IIDR_Revision_rdf(&gic_v3_dev),
164            gic_v3_dist_GICD_IIDR_Variant_rdf(&gic_v3_dev),
165            gic_v3_dist_GICD_IIDR_ProductID_rdf(&gic_v3_dev),
166            gic_v3_dist_GICD_IIDR_rawrd(&gic_v3_dev)
167            );
168
169
170    uint32_t itlines = gic_v3_dist_GICD_TYPER_ITLinesNumber_rdf(&gic_v3_dev);
171    itlines = (itlines+1)*32;
172    if(itlines > 1020)
173        itlines = 1020;
174    printk(LOG_NOTE, "gic_v2: #INTIDs supported: %" PRIu32 "\n", itlines);
175
176    uint32_t lspi = gic_v3_dist_GICD_TYPER_LSPI_rdf(&gic_v3_dev);
177    printk(LOG_NOTE, "gic_v2: #LSPIs supported: %" PRIu32 "\n", lspi);
178
179
180    // Setup distributor so it forwards all interrupts to this CPU.
181    uint8_t my_cpumask = gic_get_cpumask();
182    uint32_t dest_cpumask = my_cpumask;
183    dest_cpumask = dest_cpumask | dest_cpumask << 8 | dest_cpumask << 16 | dest_cpumask << 24;
184    for(int i=8; i*4 < itlines; i++)
185        gic_v3_dist_GICD_ITARGETSR_wr(&gic_v3_dev, i, dest_cpumask);
186
187    // Put all interrupts into Group 0 and enable them
188    #define MASK_32     0xffffffff
189    for (int i = 0; i * 32 < itlines; i++) {
190        // Clear
191        gic_v3_dist_GICD_ICACTIVER_wr(&gic_v3_dev, i, MASK_32);
192        // Enable
193        gic_v3_dist_GICD_ISENABLER_wr(&gic_v3_dev, i, MASK_32);
194        // And put in group 0
195        gic_v3_dist_GICD_IGROUPR_rawwr(&gic_v3_dev, i, 0);
196    }
197
198    // Disable interrupt FIQ Bypass interrupt 28
199    gic_v3_dist_GICD_ICENABLER_wr(&gic_v3_dev, 0, (1<<28));
200
201
202    gic_v3_dist_GICD_CTLR_rawwr(&gic_v3_dev, 0x1); // Enable Distributor
203    check_cpu_if_statusr();
204}
205
206errval_t platform_init_ic_bsp(void) {
207    gic_init();
208    gic_cpu_interface_enable();
209    return SYS_ERR_OK;
210}
211
212errval_t platform_init_ic_app(void) {
213    gic_cpu_interface_enable();
214    return SYS_ERR_OK;
215}
216
217/**
218 * \brief Enable an interrupt
219 *
220 * \see ARM Generic Interrupt Controller Architecture Specification v1.0
221 *
222 * \param int_id
223 * \param cpu_targets 8 Bit mask. One bit for each core in the system.
224 *    (chapter 4.3.11)
225 * \param prio Priority of the interrupt (lower is higher). We allow 0..15.
226 *    The number of priority bits is implementation specific, but at least 16
227 *    (using bits [7:4] of the priority field, chapter 3.3)
228 * \param 0 is level-sensitive, 1 is edge-triggered
229 * \param 0 is N-to-N, 1 is 1-N
230 */
231errval_t platform_enable_interrupt(uint32_t int_id, uint16_t prio,
232                          bool edge_triggered, bool one_to_n)
233{
234    return SYS_ERR_OK;
235}
236