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_v3_redist_dev.h>
15#include <platform.h>
16#include <paging_kernel_arch.h>
17#include <arch/armv8/gic_v3.h>
18
19static gic_v3_dist_t gic_v3_dist_dev;
20static gic_v3_redist_t gic_v3_redist_dev;
21
22lpaddr_t platform_gic_cpu_base = 0; // no memory-mapped cpu interface
23
24/*
25 * Initialize the global interrupt controller
26 *
27 * There are three types of interrupts
28 * 1) Software generated Interrupts (SGI) - IDs 0-15
29 * 2) Private Peripheral Interrupts (PPI) - IDs 16-31
30 * 3) Shared Peripheral Interrups (SPI) - IDs 32-1019
31 * 4) Special - IDs 1020-1023
32 * 5) Locality-specific Peripheral Interrups (LPI) - IDs 8192-...
33 */
34void gic_init(void)
35{
36    printk(LOG_NOTE, "GICv3: Initializing\n");
37    lvaddr_t gic_dist = local_phys_to_mem(platform_gic_dist_base);
38    gic_v3_dist_initialize(&gic_v3_dist_dev, (char *)gic_dist);
39
40    printf("%s: dist:%lx\n", __func__, gic_dist);
41
42    printk(LOG_NOTE, "GICD IIDR "
43            "implementer=0x%x, revision=0x%x, variant=0x%x,prodid=0x%x\n",
44            gic_v3_dist_GICD_IIDR_Implementer_rdf(&gic_v3_dist_dev),
45            gic_v3_dist_GICD_IIDR_Revision_rdf(&gic_v3_dist_dev),
46            gic_v3_dist_GICD_IIDR_Variant_rdf(&gic_v3_dist_dev),
47            gic_v3_dist_GICD_IIDR_ProductID_rdf(&gic_v3_dist_dev)
48            );
49
50    uint32_t itlines = gic_v3_dist_GICD_TYPER_ITLinesNumber_rdf(&gic_v3_dist_dev);
51    itlines = (itlines + 1) * 32;
52    if (itlines > 1020)
53        itlines = 1020;
54    printk(LOG_NOTE, "gic: #INTIDs supported: %" PRIu32 "\n", itlines);
55
56    // Put all interrupts into Group 1 and enable them
57    #define MASK_32     0xffffffff
58    for (int i = 0; i * 32 < itlines; i++) {
59        // Clear
60        gic_v3_dist_GICD_ICACTIVER_wr(&gic_v3_dist_dev, i, MASK_32);
61        // Enable
62        gic_v3_dist_GICD_ISENABLER_wr(&gic_v3_dist_dev, i, MASK_32);
63        // And put in group 1
64        gic_v3_dist_GICD_IGROUPR_rawwr(&gic_v3_dist_dev, i, MASK_32);
65    }
66    gic_v3_dist_GICD_CTLR_secure_t ctrl = 0;
67    // Set affinity routing (redundant on CN88xx)
68    ctrl = gic_v3_dist_GICD_CTLR_secure_ARE_NS_insert(ctrl, 1);
69    // Enable group 1 interrupts
70    ctrl = gic_v3_dist_GICD_CTLR_secure_EnableGrp1NS_insert(ctrl, 1);
71    gic_v3_dist_GICD_CTLR_secure_wr(&gic_v3_dist_dev, ctrl);
72
73    printk(LOG_NOTE, "GICv3: Initialized\n");
74}
75
76/*
77 * Returns active interrupt of group 1
78 */
79uint32_t gic_get_active_irq(void)
80{
81    return armv8_ICC_IAR1_EL1_INTID_rdf(NULL);
82}
83
84/*
85 * ACKs group 1 interrupt
86 */
87void gic_ack_irq(uint32_t irq)
88{
89    armv8_ICC_EOIR1_EL1_rawwr(NULL, irq);
90}
91
92/*
93 * Raise an SGI on a core.
94 */
95void gic_raise_softirq(coreid_t cpuid, uint8_t irq)
96{
97    assert(irq <= 15);
98    armv8_ICC_SGI1R_EL1_t reg = 0;
99    reg = armv8_ICC_SGI1R_EL1_INTID_insert(reg, 1);
100    // TODO: make that work for cpuids > 15
101    reg = armv8_ICC_SGI1R_EL1_TargetList_insert(reg, 1<<cpuid);
102    reg = armv8_ICC_SGI1R_EL1_Aff3_insert(reg, 0);
103    reg = armv8_ICC_SGI1R_EL1_Aff2_insert(reg, 0);
104    reg = armv8_ICC_SGI1R_EL1_Aff1_insert(reg, 0);
105    armv8_ICC_SGI1R_EL1_wr(NULL, reg);
106}
107
108/*
109 * Enable GIC CPU-IF and a redistributor
110 */
111void gic_cpu_interface_enable(void)
112{
113    printk(LOG_NOTE, "GICv3: Enabling CPU interface\n");
114
115    lvaddr_t gic_redist = local_phys_to_mem(platform_gic_redist_base);
116
117    // Enable system register access
118    armv8_ICC_SRE_EL1_SRE_wrf(NULL, 1);
119
120    gic_v3_redist_initialize(&gic_v3_redist_dev, (char *)gic_redist + 0x20000 * my_core_id);
121    printf("%s: redist:%lx\n", __func__, (char *)gic_redist + 0x20000 * my_core_id);
122
123    // Linux does:
124    // sets priority mode: PMR to 0xf0
125    armv8_ICC_PMR_EL1_wr(NULL, 0xf0);
126    // Set binary point to 1, 6 group priority bits, 2 subpriority bits
127    armv8_ICC_BPR1_EL1_wr(NULL, 1);
128
129    //Enable group 1
130    armv8_ICC_IGRPEN1_EL1_wr(NULL, 0x1);
131
132    gic_v3_redist_GICR_TYPER_t gicr_typer;
133    gicr_typer = gic_v3_redist_GICR_TYPER_rd(&gic_v3_redist_dev);
134    printf("%s: GICR_TYPER: affinity:%x  cpu_no:%x\n", __func__, gic_v3_redist_GICR_TYPER_Affinity_Value_extract(gicr_typer), gic_v3_redist_GICR_TYPER_Processor_Number_extract(gicr_typer));
135
136    gic_v3_redist_GICR_ICACTIVER0_rawwr(&gic_v3_redist_dev, MASK_32);
137    gic_v3_redist_GICR_ISENABLER0_rawwr(&gic_v3_redist_dev, MASK_32);
138
139    gic_v3_redist_GICR_IGROUPR0_rawwr(&gic_v3_redist_dev, MASK_32);
140    gic_v3_redist_GICR_IGRPMODR0_rawwr(&gic_v3_redist_dev, 0);
141
142    printk(LOG_NOTE, "GICv3: CPU interface enabled\n");
143}
144
145/**
146 * \brief Enable an interrupt
147 *
148 * \see ARM Generic Interrupt Controller Architecture Specification v1.0
149 *
150 * \param int_id
151 * \param cpu_targets 8 Bit mask. One bit for each core in the system.
152 *    (chapter 4.3.11)
153 * \param prio Priority of the interrupt (lower is higher). We allow 0..15.
154 *    The number of priority bits is implementation specific, but at least 16
155 *    (using bits [7:4] of the priority field, chapter 3.3)
156 * \param 0 is level-sensitive, 1 is edge-triggered
157 * \param 0 is N-to-N, 1 is 1-N
158 */
159void gic_enable_interrupt(uint32_t int_id, uint8_t cpu_targets, uint16_t prio,
160                          bool edge_triggered, bool one_to_n)
161{
162}
163
164errval_t platform_gic_init(void) {
165    gic_init();
166    return SYS_ERR_OK;
167}
168
169errval_t platform_gic_cpu_interface_enable(void) {
170    gic_cpu_interface_enable();
171    return SYS_ERR_OK;
172}
173