11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2b0104773SPascal Brand /*
39e935234SJens Wiklander * Copyright (c) 2016-2017, 2023-2024 Linaro Limited
4b0104773SPascal Brand * Copyright (c) 2014, STMicroelectronics International N.V.
5b0104773SPascal Brand */
6b0104773SPascal Brand
718901324SDavid Wang #include <arm.h>
88ddf5a4eSEtienne Carriere #include <assert.h>
967e55c51SEtienne Carriere #include <compiler.h>
1005089e5fSJens Wiklander #include <config.h>
11b0104773SPascal Brand #include <drivers/gic.h>
129e935234SJens Wiklander #include <dt-bindings/interrupt-controller/arm-gic.h>
139e935234SJens Wiklander #include <initcall.h>
1405089e5fSJens Wiklander #include <io.h>
150f93de74SEtienne Carriere #include <keep.h>
1667729d8dSLudovic Barre #include <kernel/dt.h>
1714885eb1SEtienne Carriere #include <kernel/dt_driver.h>
187315b7b4SJens Wiklander #include <kernel/interrupt.h>
1905089e5fSJens Wiklander #include <kernel/misc.h>
2010cc5912SRunyang Chen #include <kernel/mutex.h>
21d13278b8SEtienne Carriere #include <kernel/panic.h>
2205089e5fSJens Wiklander #include <libfdt.h>
2360801696SVolodymyr Babchuk #include <mm/core_memprot.h>
2460801696SVolodymyr Babchuk #include <mm/core_mmu.h>
254de4bebcSJens Wiklander #include <trace.h>
2605089e5fSJens Wiklander #include <util.h>
27b0104773SPascal Brand
28b0104773SPascal Brand /* Offsets from gic.gicc_base */
29b0104773SPascal Brand #define GICC_CTLR (0x000)
3030a673e3SPeter Maydell #define GICC_PMR (0x004)
31b0104773SPascal Brand #define GICC_IAR (0x00C)
32b0104773SPascal Brand #define GICC_EOIR (0x010)
33b0104773SPascal Brand
34b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0 (1 << 0)
35b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1 (1 << 1)
36b0104773SPascal Brand #define GICC_CTLR_FIQEN (1 << 3)
37b0104773SPascal Brand
38b0104773SPascal Brand /* Offsets from gic.gicd_base */
39b0104773SPascal Brand #define GICD_CTLR (0x000)
40b0104773SPascal Brand #define GICD_TYPER (0x004)
41b0104773SPascal Brand #define GICD_IGROUPR(n) (0x080 + (n) * 4)
42b0104773SPascal Brand #define GICD_ISENABLER(n) (0x100 + (n) * 4)
43b0104773SPascal Brand #define GICD_ICENABLER(n) (0x180 + (n) * 4)
4426ed70ecSGuanchao Liang #define GICD_ISPENDR(n) (0x200 + (n) * 4)
45b0104773SPascal Brand #define GICD_ICPENDR(n) (0x280 + (n) * 4)
46b0104773SPascal Brand #define GICD_IPRIORITYR(n) (0x400 + (n) * 4)
47b0104773SPascal Brand #define GICD_ITARGETSR(n) (0x800 + (n) * 4)
48141876e4SEtienne Carriere #define GICD_ICFGR(n) (0xc00 + (n) * 4)
491fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4)
5026ed70ecSGuanchao Liang #define GICD_SGIR (0xF00)
51b0104773SPascal Brand
5269171becSJens Wiklander #ifdef CFG_ARM_GICV3
5369171becSJens Wiklander #define GICD_PIDR2 (0xFFE8)
5469171becSJens Wiklander #else
5569171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */
5669171becSJens Wiklander #define GICD_PIDR2 (0xFE8)
5769171becSJens Wiklander #endif
5869171becSJens Wiklander
5905089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP0 BIT32(0)
6005089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1NS BIT32(1)
6105089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1S BIT32(2)
6205089e5fSJens Wiklander #define GICD_CTLR_ARE_S BIT32(4)
6305089e5fSJens Wiklander #define GICD_CTLR_ARE_NS BIT32(5)
6405089e5fSJens Wiklander
6505089e5fSJens Wiklander /* Offsets from gic.gicr_base[core_pos] */
6605089e5fSJens Wiklander #define GICR_V3_PCPUBASE_SIZE (2 * 64 * 1024)
6705089e5fSJens Wiklander #define GICR_SGI_BASE_OFFSET (64 * 1024)
6805089e5fSJens Wiklander #define GICR_CTLR (0x00)
6905089e5fSJens Wiklander #define GICR_TYPER (0x08)
7005089e5fSJens Wiklander
7105089e5fSJens Wiklander #define GICR_IGROUPR0 (GICR_SGI_BASE_OFFSET + 0x080)
7205089e5fSJens Wiklander #define GICR_IGRPMODR0 (GICR_SGI_BASE_OFFSET + 0xD00)
7384603456SJens Wiklander #define GICR_ICENABLER0 (GICR_SGI_BASE_OFFSET + 0x180)
7484603456SJens Wiklander #define GICR_ICPENDR0 (GICR_SGI_BASE_OFFSET + 0x280)
759e935234SJens Wiklander #define GICR_ISENABLER0 (GICR_SGI_BASE_OFFSET + 0x100)
769e935234SJens Wiklander #define GICR_ICFGR0 (GICR_SGI_BASE_OFFSET + 0xC00)
779e935234SJens Wiklander #define GICR_ICFGR1 (GICR_SGI_BASE_OFFSET + 0xC04)
789e935234SJens Wiklander #define GICR_IPRIORITYR(n) (GICR_SGI_BASE_OFFSET + 0x400 + (n) * 4)
799e935234SJens Wiklander
806c2d2e8aSJens Wiklander #define GICR_CTLR_RWP BIT32(3)
8105089e5fSJens Wiklander
8205089e5fSJens Wiklander #define GICR_TYPER_LAST BIT64(4)
8305089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT 56
8405089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT 48
8505089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT 40
8605089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT 32
87b0104773SPascal Brand
8869171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */
8969171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT 4
9069171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK 0xF
9169171becSJens Wiklander
9253bd332aSSY Chiu /* Number of Private Peripheral Interrupt */
9353bd332aSSY Chiu #define NUM_PPI 32
9453bd332aSSY Chiu
9526ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */
9626ed70ecSGuanchao Liang #define NUM_SGI 16
9726ed70ecSGuanchao Liang
9826ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */
9926ed70ecSGuanchao Liang #define NUM_NS_SGI 8
10026ed70ecSGuanchao Liang
10153bd332aSSY Chiu /* Number of interrupts in one register */
10253bd332aSSY Chiu #define NUM_INTS_PER_REG 32
10353bd332aSSY Chiu
10453bd332aSSY Chiu /* Number of targets in one register */
10553bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4
10653bd332aSSY Chiu
10753bd332aSSY Chiu /* Accessors to access ITARGETSRn */
10853bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8
10953bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff
11053bd332aSSY Chiu
1111b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK 0x1f
1127315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff
1137315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7
1147315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10
115b0104773SPascal Brand
116ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT 40
117ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT 16
118ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT 32
119ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT 48
120ec740b9fSJens Wiklander
121ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK 0xf
122ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS 0x1
123ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU 0x2
124ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT 24
125ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT 15
126ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT 16
127ec740b9fSJens Wiklander
128141876e4SEtienne Carriere /* GICD ICFGR bit fields */
129141876e4SEtienne Carriere #define GICD_ICFGR_TYPE_EDGE 2
130141876e4SEtienne Carriere #define GICD_ICFGR_TYPE_LEVEL 0
131141876e4SEtienne Carriere #define GICD_ICFGR_FIELD_BITS 2
132141876e4SEtienne Carriere #define GICD_ICFGR_FIELD_MASK 0x3
133141876e4SEtienne Carriere #define GICD_ICFGR_NUM_INTS_PER_REG (NUM_INTS_PER_REG / \
134141876e4SEtienne Carriere GICD_ICFGR_FIELD_BITS)
135141876e4SEtienne Carriere
13667e55c51SEtienne Carriere struct gic_data {
13767e55c51SEtienne Carriere vaddr_t gicc_base;
13867e55c51SEtienne Carriere vaddr_t gicd_base;
13905089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
14005089e5fSJens Wiklander vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE];
14105089e5fSJens Wiklander #endif
14267e55c51SEtienne Carriere size_t max_it;
14305089e5fSJens Wiklander uint32_t per_cpu_group_status;
14405089e5fSJens Wiklander uint32_t per_cpu_group_modifier;
1459e935234SJens Wiklander uint32_t per_cpu_enable;
14667e55c51SEtienne Carriere struct itr_chip chip;
14767e55c51SEtienne Carriere };
14867e55c51SEtienne Carriere
1499e935234SJens Wiklander static bool gic_primary_done __nex_bss;
15067e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss;
15110cc5912SRunyang Chen static struct mutex gic_mutex = MUTEX_INITIALIZER;
15267e55c51SEtienne Carriere
1532a50ce7dSEtienne Carriere static void gic_op_configure(struct itr_chip *chip, size_t it, uint32_t type,
154702fe5a7SClément Léger uint32_t prio);
1557315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
1567315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
15726ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
15826ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
159ec740b9fSJens Wiklander uint32_t cpu_mask);
16026ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
16126ed70ecSGuanchao Liang uint8_t cpu_mask);
1627315b7b4SJens Wiklander
1637315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
1642a50ce7dSEtienne Carriere .configure = gic_op_configure,
16508ded0e1SEtienne Carriere .mask = gic_op_disable,
16608ded0e1SEtienne Carriere .unmask = gic_op_enable,
1677315b7b4SJens Wiklander .enable = gic_op_enable,
1687315b7b4SJens Wiklander .disable = gic_op_disable,
16926ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi,
17026ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi,
17126ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity,
1727315b7b4SJens Wiklander };
1733639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops);
1747315b7b4SJens Wiklander
get_gicr_base(struct gic_data * gd __maybe_unused)17505089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused)
17605089e5fSJens Wiklander {
17705089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
17805089e5fSJens Wiklander return gd->gicr_base[get_core_pos()];
17905089e5fSJens Wiklander #else
18005089e5fSJens Wiklander return 0;
18105089e5fSJens Wiklander #endif
18205089e5fSJens Wiklander }
18305089e5fSJens Wiklander
affinity_routing_is_enabled(struct gic_data * gd)1847c4883aeSJens Wiklander static bool affinity_routing_is_enabled(struct gic_data *gd)
1857c4883aeSJens Wiklander {
1867c4883aeSJens Wiklander return IS_ENABLED(CFG_ARM_GICV3) &&
1877c4883aeSJens Wiklander io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S;
1887c4883aeSJens Wiklander }
1897c4883aeSJens Wiklander
probe_max_it(vaddr_t gicc_base __maybe_unused,vaddr_t gicd_base)19018901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
191b0104773SPascal Brand {
192b012d115SEtienne Carriere int i = 0;
193b012d115SEtienne Carriere uint32_t old_ctlr = 0;
194b0104773SPascal Brand size_t ret = 0;
1951b4c5002SIzhar Nevo size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1961b4c5002SIzhar Nevo GICD_TYPER_IT_LINES_NUM_MASK;
197b0104773SPascal Brand
198b0104773SPascal Brand /*
199b0104773SPascal Brand * Probe which interrupt number is the largest.
200b0104773SPascal Brand */
20118901324SDavid Wang #if defined(CFG_ARM_GICV3)
20218901324SDavid Wang old_ctlr = read_icc_ctlr();
20318901324SDavid Wang write_icc_ctlr(0);
20418901324SDavid Wang #else
205918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR);
206918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0);
20718901324SDavid Wang #endif
20879f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) {
209b012d115SEtienne Carriere uint32_t old_reg = 0;
210b012d115SEtienne Carriere uint32_t reg = 0;
211b012d115SEtienne Carriere int b = 0;
212b0104773SPascal Brand
213918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
214918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
215918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i));
216918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
21779f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
218007a97a2SJens Wiklander if (BIT32(b) & reg) {
21953bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b;
220b0104773SPascal Brand goto out;
221b0104773SPascal Brand }
222b0104773SPascal Brand }
223b0104773SPascal Brand }
224b0104773SPascal Brand out:
22518901324SDavid Wang #if defined(CFG_ARM_GICV3)
22618901324SDavid Wang write_icc_ctlr(old_ctlr);
22718901324SDavid Wang #else
228918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr);
22918901324SDavid Wang #endif
230b0104773SPascal Brand return ret;
231b0104773SPascal Brand }
232b0104773SPascal Brand
gicr_wait_for_pending_write(vaddr_t gicr_base)2336c2d2e8aSJens Wiklander static void gicr_wait_for_pending_write(vaddr_t gicr_base)
2346c2d2e8aSJens Wiklander {
2356c2d2e8aSJens Wiklander /*
2366c2d2e8aSJens Wiklander * Wait for changes to
2376c2d2e8aSJens Wiklander * - GICR_ICENABLER0
2386c2d2e8aSJens Wiklander * - GICR_CTLR.DPG1S
2396c2d2e8aSJens Wiklander * - GICR_CTLR.DPG1NS
2406c2d2e8aSJens Wiklander * - GICR_CTLR.DPG0
2416c2d2e8aSJens Wiklander * to be visible to all agents in the system.
2426c2d2e8aSJens Wiklander */
2436c2d2e8aSJens Wiklander while (io_read32(gicr_base + GICR_CTLR) & GICR_CTLR_RWP)
2446c2d2e8aSJens Wiklander ;
2456c2d2e8aSJens Wiklander }
2466c2d2e8aSJens Wiklander
gicv3_sync_redist_config(struct gic_data * gd)2479e935234SJens Wiklander static void gicv3_sync_redist_config(struct gic_data *gd)
24884603456SJens Wiklander {
24984603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd);
25084603456SJens Wiklander bool need_sync = false;
25184603456SJens Wiklander uint32_t gmod0 = 0;
25284603456SJens Wiklander uint32_t grp0 = 0;
25384603456SJens Wiklander size_t n = 0;
25484603456SJens Wiklander
2557c4883aeSJens Wiklander /*
2567c4883aeSJens Wiklander * If gicr_base isn't available there's no need to synchronize SGI
2577c4883aeSJens Wiklander * configuration since gic_init_donate_sgi_to_ns() would panic.
2587c4883aeSJens Wiklander */
25984603456SJens Wiklander if (!gicr_base)
2607c4883aeSJens Wiklander return;
26184603456SJens Wiklander
26284603456SJens Wiklander grp0 = io_read32(gicr_base + GICR_IGROUPR0);
26384603456SJens Wiklander gmod0 = io_read32(gicr_base + GICR_IGRPMODR0);
2649e935234SJens Wiklander for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) {
26584603456SJens Wiklander /* Ignore matching bits */
26684603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)) &&
26784603456SJens Wiklander !(BIT32(n) & (gmod0 ^ gd->per_cpu_group_modifier)))
26884603456SJens Wiklander continue;
26984603456SJens Wiklander /*
2709e935234SJens Wiklander * SGI/PPI-n differs from primary CPU configuration,
27184603456SJens Wiklander * let's sync up.
27284603456SJens Wiklander */
27384603456SJens Wiklander need_sync = true;
27484603456SJens Wiklander
27584603456SJens Wiklander /* Disable interrupt */
27684603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(n));
27784603456SJens Wiklander
2786c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */
2796c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base);
2806c2d2e8aSJens Wiklander
28184603456SJens Wiklander /* Make interrupt non-pending */
28284603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(n));
28384603456SJens Wiklander
28484603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status)
28584603456SJens Wiklander grp0 |= BIT32(n);
28684603456SJens Wiklander else
28784603456SJens Wiklander grp0 &= ~BIT32(n);
28884603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_modifier)
28984603456SJens Wiklander gmod0 |= BIT32(n);
29084603456SJens Wiklander else
29184603456SJens Wiklander gmod0 &= ~BIT32(n);
29284603456SJens Wiklander }
29384603456SJens Wiklander
29484603456SJens Wiklander if (need_sync) {
29584603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, grp0);
29684603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, gmod0);
2979e935234SJens Wiklander io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable);
29884603456SJens Wiklander }
29984603456SJens Wiklander }
30084603456SJens Wiklander
gic_legacy_sync_dist_config(struct gic_data * gd)3019e935234SJens Wiklander static void gic_legacy_sync_dist_config(struct gic_data *gd)
30284603456SJens Wiklander {
30384603456SJens Wiklander bool need_sync = false;
30484603456SJens Wiklander uint32_t grp0 = 0;
30584603456SJens Wiklander size_t n = 0;
30684603456SJens Wiklander
30784603456SJens Wiklander grp0 = io_read32(gd->gicd_base + GICD_IGROUPR(0));
3089e935234SJens Wiklander for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) {
30984603456SJens Wiklander /* Ignore matching bits */
31084603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)))
31184603456SJens Wiklander continue;
31284603456SJens Wiklander /*
3139e935234SJens Wiklander * SGI/PPI-n differs from primary CPU configuration,
31484603456SJens Wiklander * let's sync up.
31584603456SJens Wiklander */
31684603456SJens Wiklander need_sync = true;
31784603456SJens Wiklander
31884603456SJens Wiklander /* Disable interrupt */
31984603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(n));
32084603456SJens Wiklander
32184603456SJens Wiklander /* Make interrupt non-pending */
32284603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(n));
32384603456SJens Wiklander
32484603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status)
32584603456SJens Wiklander grp0 |= BIT32(n);
32684603456SJens Wiklander else
32784603456SJens Wiklander grp0 &= ~BIT32(n);
32884603456SJens Wiklander }
32984603456SJens Wiklander
3309e935234SJens Wiklander if (need_sync) {
33184603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), grp0);
3329e935234SJens Wiklander io_write32(gd->gicd_base + GICD_ISENABLER(0),
3339e935234SJens Wiklander gd->per_cpu_enable);
3349e935234SJens Wiklander }
33584603456SJens Wiklander }
33684603456SJens Wiklander
init_gic_per_cpu(struct gic_data * gd)3375da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd)
338bedc2b9fSsunny {
33905089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status);
340bedc2b9fSsunny
34105089e5fSJens Wiklander /*
34205089e5fSJens Wiklander * Set the priority mask to permit Non-secure interrupts, and to
34330a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself
34430a673e3SPeter Maydell */
34518901324SDavid Wang #if defined(CFG_ARM_GICV3)
34618901324SDavid Wang write_icc_pmr(0x80);
3471fcac774SSandeep Tripathy write_icc_igrpen1(1);
34818901324SDavid Wang #else
349918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80);
35030a673e3SPeter Maydell
351bedc2b9fSsunny /* Enable GIC */
352918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR,
353918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
354918bb3a5SEtienne Carriere GICC_CTLR_FIQEN);
35518901324SDavid Wang #endif
356bedc2b9fSsunny }
357bedc2b9fSsunny
gic_init_per_cpu(void)3585da157f5SJens Wiklander void gic_init_per_cpu(void)
3595da157f5SJens Wiklander {
3605da157f5SJens Wiklander struct gic_data *gd = &gic_data;
3615da157f5SJens Wiklander
3625da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
3635da157f5SJens Wiklander assert(gd->gicd_base);
3645da157f5SJens Wiklander #else
3655da157f5SJens Wiklander assert(gd->gicd_base && gd->gicc_base);
3665da157f5SJens Wiklander #endif
3675da157f5SJens Wiklander
36884603456SJens Wiklander if (IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) {
36984603456SJens Wiklander /*
37084603456SJens Wiklander * GIC is already initialized by TF-A, we only need to
3719e935234SJens Wiklander * handle eventual SGI or PPI configuration changes.
37284603456SJens Wiklander */
3737c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd))
3749e935234SJens Wiklander gicv3_sync_redist_config(gd);
37584603456SJens Wiklander else
3769e935234SJens Wiklander gic_legacy_sync_dist_config(gd);
37784603456SJens Wiklander } else {
37884603456SJens Wiklander /*
37984603456SJens Wiklander * Non-TF-A case where all CPU specific configuration
38084603456SJens Wiklander * of GIC must be done here.
38184603456SJens Wiklander */
3825da157f5SJens Wiklander init_gic_per_cpu(gd);
3835da157f5SJens Wiklander }
38484603456SJens Wiklander }
3855da157f5SJens Wiklander
gic_init_donate_sgi_to_ns(size_t it)38684603456SJens Wiklander void gic_init_donate_sgi_to_ns(size_t it)
38784603456SJens Wiklander {
38884603456SJens Wiklander struct gic_data *gd = &gic_data;
38984603456SJens Wiklander
39084603456SJens Wiklander assert(it >= GIC_SGI_SEC_BASE && it <= GIC_SGI_SEC_MAX);
39184603456SJens Wiklander
39284603456SJens Wiklander /* Assert it's secure to start with. */
39384603456SJens Wiklander assert(!(gd->per_cpu_group_status & BIT32(it)) &&
39484603456SJens Wiklander (gd->per_cpu_group_modifier & BIT32(it)));
39584603456SJens Wiklander
39684603456SJens Wiklander gd->per_cpu_group_modifier &= ~BIT32(it);
39784603456SJens Wiklander gd->per_cpu_group_status |= BIT32(it);
39884603456SJens Wiklander
3997c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) {
40084603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd);
40184603456SJens Wiklander
4027c4883aeSJens Wiklander if (!gicr_base)
4037c4883aeSJens Wiklander panic("GICR_BASE missing");
4047c4883aeSJens Wiklander
40584603456SJens Wiklander /* Disable interrupt */
40684603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(it));
40784603456SJens Wiklander
4086c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */
4096c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base);
4106c2d2e8aSJens Wiklander
41184603456SJens Wiklander /* Make interrupt non-pending */
41284603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(it));
41384603456SJens Wiklander
41484603456SJens Wiklander /* Make it to non-secure */
41584603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status);
41684603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0,
41784603456SJens Wiklander gd->per_cpu_group_modifier);
41884603456SJens Wiklander } else {
41984603456SJens Wiklander /* Disable interrupt */
42084603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(it));
42184603456SJens Wiklander
42284603456SJens Wiklander /* Make interrupt non-pending */
42384603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(it));
42484603456SJens Wiklander
42584603456SJens Wiklander /* Make it to non-secure */
42684603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0),
42784603456SJens Wiklander gd->per_cpu_group_status);
42884603456SJens Wiklander }
42984603456SJens Wiklander }
43084603456SJens Wiklander
gic_dt_get_irq(const uint32_t * properties,int count,uint32_t * type,uint32_t * prio)4310ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
4320ee3f52eSEtienne Carriere uint32_t *prio)
4330ee3f52eSEtienne Carriere {
4340ee3f52eSEtienne Carriere int it_num = DT_INFO_INVALID_INTERRUPT;
435141876e4SEtienne Carriere uint32_t detection_type = IRQ_TYPE_NONE;
436141876e4SEtienne Carriere uint32_t interrupt_type = GIC_PPI;
4370ee3f52eSEtienne Carriere
438141876e4SEtienne Carriere if (!properties || count < 2 || count > 3)
4390ee3f52eSEtienne Carriere return DT_INFO_INVALID_INTERRUPT;
4400ee3f52eSEtienne Carriere
441141876e4SEtienne Carriere interrupt_type = fdt32_to_cpu(properties[0]);
442141876e4SEtienne Carriere it_num = (int)fdt32_to_cpu(properties[1]);
4430ee3f52eSEtienne Carriere
444141876e4SEtienne Carriere if (count == 3) {
445141876e4SEtienne Carriere detection_type = fdt32_to_cpu(properties[2]) & GENMASK_32(3, 0);
446141876e4SEtienne Carriere if (interrupt_type == GIC_PPI &&
447141876e4SEtienne Carriere detection_type != IRQ_TYPE_EDGE_RISING) {
448141876e4SEtienne Carriere EMSG("PPI must be edge rising");
449141876e4SEtienne Carriere return DT_INFO_INVALID_INTERRUPT;
450141876e4SEtienne Carriere }
451141876e4SEtienne Carriere
452141876e4SEtienne Carriere if (interrupt_type == GIC_SPI &&
453141876e4SEtienne Carriere (detection_type != IRQ_TYPE_EDGE_RISING &&
454141876e4SEtienne Carriere detection_type != IRQ_TYPE_LEVEL_HIGH)) {
455141876e4SEtienne Carriere EMSG("SPI must be edge rising or high level");
456141876e4SEtienne Carriere return DT_INFO_INVALID_INTERRUPT;
457141876e4SEtienne Carriere }
458141876e4SEtienne Carriere }
459141876e4SEtienne Carriere
460141876e4SEtienne Carriere switch (interrupt_type) {
4618c7282beSEtienne Carriere case GIC_PPI:
4620ee3f52eSEtienne Carriere it_num += 16;
463141876e4SEtienne Carriere detection_type = IRQ_TYPE_EDGE_RISING;
4640ee3f52eSEtienne Carriere break;
4658c7282beSEtienne Carriere case GIC_SPI:
4660ee3f52eSEtienne Carriere it_num += 32;
4670ee3f52eSEtienne Carriere break;
4680ee3f52eSEtienne Carriere default:
469141876e4SEtienne Carriere return DT_INFO_INVALID_INTERRUPT;
4700ee3f52eSEtienne Carriere }
4710ee3f52eSEtienne Carriere
472141876e4SEtienne Carriere if (type)
473141876e4SEtienne Carriere *type = detection_type;
474141876e4SEtienne Carriere
475141876e4SEtienne Carriere if (prio)
476141876e4SEtienne Carriere *prio = 0;
477141876e4SEtienne Carriere
4780ee3f52eSEtienne Carriere return it_num;
4790ee3f52eSEtienne Carriere }
4800ee3f52eSEtienne Carriere
probe_redist_base_addrs(vaddr_t * gicr_base_addrs,paddr_t gicr_base_pa)48105089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs,
48205089e5fSJens Wiklander paddr_t gicr_base_pa)
48305089e5fSJens Wiklander {
48405089e5fSJens Wiklander size_t sz = GICR_V3_PCPUBASE_SIZE;
48505089e5fSJens Wiklander paddr_t pa = gicr_base_pa;
48605089e5fSJens Wiklander size_t core_pos = 0;
48705089e5fSJens Wiklander uint64_t mt_bit = 0;
48805089e5fSJens Wiklander uint64_t mpidr = 0;
48905089e5fSJens Wiklander uint64_t tv = 0;
49005089e5fSJens Wiklander vaddr_t va = 0;
49105089e5fSJens Wiklander
49205089e5fSJens Wiklander #ifdef ARM64
49305089e5fSJens Wiklander mt_bit = read_mpidr_el1() & MPIDR_MT_MASK;
49405089e5fSJens Wiklander #endif
49505089e5fSJens Wiklander do {
49605089e5fSJens Wiklander va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
49705089e5fSJens Wiklander if (!va)
49805089e5fSJens Wiklander panic();
49905089e5fSJens Wiklander tv = io_read64(va + GICR_TYPER);
50005089e5fSJens Wiklander
50105089e5fSJens Wiklander /*
50205089e5fSJens Wiklander * Extract an mpidr from the Type register to calculate the
50305089e5fSJens Wiklander * core position of this redistributer instance.
50405089e5fSJens Wiklander */
50505089e5fSJens Wiklander mpidr = mt_bit;
50605089e5fSJens Wiklander mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) &
50705089e5fSJens Wiklander MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT);
50805089e5fSJens Wiklander mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) &
50905089e5fSJens Wiklander (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK);
51005089e5fSJens Wiklander core_pos = get_core_pos_mpidr(mpidr);
51105089e5fSJens Wiklander if (core_pos < CFG_TEE_CORE_NB_CORE) {
51205089e5fSJens Wiklander DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va);
51305089e5fSJens Wiklander gicr_base_addrs[core_pos] = va;
51405089e5fSJens Wiklander } else {
51505089e5fSJens Wiklander EMSG("Skipping too large core_pos %zu from GICR_TYPER",
51605089e5fSJens Wiklander core_pos);
51705089e5fSJens Wiklander }
51805089e5fSJens Wiklander pa += sz;
51905089e5fSJens Wiklander } while (!(tv & GICR_TYPER_LAST));
52005089e5fSJens Wiklander }
52105089e5fSJens Wiklander
gic_init_base_addr(paddr_t gicc_base_pa,paddr_t gicd_base_pa,paddr_t gicr_base_pa __maybe_unused)52205089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
52305089e5fSJens Wiklander paddr_t gicr_base_pa __maybe_unused)
524b0104773SPascal Brand {
52567e55c51SEtienne Carriere struct gic_data *gd = &gic_data;
5260ee3f52eSEtienne Carriere vaddr_t gicc_base = 0;
5270ee3f52eSEtienne Carriere vaddr_t gicd_base = 0;
52869171becSJens Wiklander uint32_t vers __maybe_unused = 0;
5290ee3f52eSEtienne Carriere
5300ee3f52eSEtienne Carriere assert(cpu_mmu_enabled());
5310ee3f52eSEtienne Carriere
5320ee3f52eSEtienne Carriere gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
5330ee3f52eSEtienne Carriere GIC_DIST_REG_SIZE);
5340ee3f52eSEtienne Carriere if (!gicd_base)
5350ee3f52eSEtienne Carriere panic();
5360ee3f52eSEtienne Carriere
53769171becSJens Wiklander vers = io_read32(gicd_base + GICD_PIDR2);
53869171becSJens Wiklander vers >>= GICD_PIDR2_ARCHREV_SHIFT;
53969171becSJens Wiklander vers &= GICD_PIDR2_ARCHREV_MASK;
54069171becSJens Wiklander
54169171becSJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3)) {
542dd18bd87SZiad Elhanafy assert(vers == 4 || vers == 3);
54369171becSJens Wiklander } else {
544d3f6526eSJens Wiklander assert(vers == 2 || vers == 1);
5450ee3f52eSEtienne Carriere gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
5460ee3f52eSEtienne Carriere GIC_CPU_REG_SIZE);
5470ee3f52eSEtienne Carriere if (!gicc_base)
5480ee3f52eSEtienne Carriere panic();
5490ee3f52eSEtienne Carriere }
5500ee3f52eSEtienne Carriere
5510ee3f52eSEtienne Carriere gd->gicc_base = gicc_base;
5520ee3f52eSEtienne Carriere gd->gicd_base = gicd_base;
5530ee3f52eSEtienne Carriere gd->max_it = probe_max_it(gicc_base, gicd_base);
55405089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
5557c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd) && gicr_base_pa)
55605089e5fSJens Wiklander probe_redist_base_addrs(gd->gicr_base, gicr_base_pa);
55705089e5fSJens Wiklander #endif
5580ee3f52eSEtienne Carriere gd->chip.ops = &gic_ops;
5590ee3f52eSEtienne Carriere
5600ee3f52eSEtienne Carriere if (IS_ENABLED(CFG_DT))
5610ee3f52eSEtienne Carriere gd->chip.dt_get_irq = gic_dt_get_irq;
5620ee3f52eSEtienne Carriere }
5630ee3f52eSEtienne Carriere
gic_init_v3(paddr_t gicc_base_pa,paddr_t gicd_base_pa,paddr_t gicr_base_pa)56405089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
56505089e5fSJens Wiklander paddr_t gicr_base_pa)
5660ee3f52eSEtienne Carriere {
5670ee3f52eSEtienne Carriere struct gic_data __maybe_unused *gd = &gic_data;
5680ee3f52eSEtienne Carriere size_t __maybe_unused n = 0;
569b0104773SPascal Brand
57005089e5fSJens Wiklander gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa);
571b0104773SPascal Brand
57205089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW)
5730ee3f52eSEtienne Carriere /* GIC configuration is initialized from TF-A when embedded */
5747c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) {
5757c4883aeSJens Wiklander /* Secure affinity routing enabled */
57605089e5fSJens Wiklander vaddr_t gicr_base = get_gicr_base(gd);
57705089e5fSJens Wiklander
5787c4883aeSJens Wiklander if (gicr_base) {
5797c4883aeSJens Wiklander gd->per_cpu_group_status = io_read32(gicr_base +
5807c4883aeSJens Wiklander GICR_IGROUPR0);
58105089e5fSJens Wiklander gd->per_cpu_group_modifier = io_read32(gicr_base +
58205089e5fSJens Wiklander GICR_IGRPMODR0);
58305089e5fSJens Wiklander } else {
5847c4883aeSJens Wiklander IMSG("GIC redistributor base address not provided");
5857c4883aeSJens Wiklander IMSG("Assuming default GIC group status and modifier");
5867c4883aeSJens Wiklander gd->per_cpu_group_status = 0xffff00ff;
5877c4883aeSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
5887c4883aeSJens Wiklander }
5897c4883aeSJens Wiklander } else {
59005089e5fSJens Wiklander /* Legacy operation with secure affinity routing disabled */
59105089e5fSJens Wiklander gd->per_cpu_group_status = io_read32(gd->gicd_base +
59205089e5fSJens Wiklander GICD_IGROUPR(0));
59305089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
59405089e5fSJens Wiklander }
59505089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/
59605089e5fSJens Wiklander /*
59705089e5fSJens Wiklander * Without TF-A, GIC is always configured in for legacy operation
59805089e5fSJens Wiklander * with secure affinity routing disabled.
59905089e5fSJens Wiklander */
6007315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
601b0104773SPascal Brand /* Disable interrupts */
602918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
603b0104773SPascal Brand
604b0104773SPascal Brand /* Make interrupts non-pending */
605918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
606b0104773SPascal Brand
607b0104773SPascal Brand /* Mark interrupts non-secure */
608bedc2b9fSsunny if (n == 0) {
609bedc2b9fSsunny /* per-CPU inerrupts config:
610bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts
611bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts.
612bedc2b9fSsunny * All PPI config as Non-secure interrupts.
613bedc2b9fSsunny */
61405089e5fSJens Wiklander gd->per_cpu_group_status = 0xffff00ff;
61505089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
61605089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(n),
61705089e5fSJens Wiklander gd->per_cpu_group_status);
618bedc2b9fSsunny } else {
619918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
620b0104773SPascal Brand }
621bedc2b9fSsunny }
622b0104773SPascal Brand
62330a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to
62430a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself
62530a673e3SPeter Maydell */
62618901324SDavid Wang #if defined(CFG_ARM_GICV3)
62718901324SDavid Wang write_icc_pmr(0x80);
6281fcac774SSandeep Tripathy write_icc_igrpen1(1);
6291fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
63018901324SDavid Wang #else
631918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80);
63230a673e3SPeter Maydell
633b0104773SPascal Brand /* Enable GIC */
634918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
635918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
636918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR,
63705089e5fSJens Wiklander GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS);
6381fcac774SSandeep Tripathy #endif
63905089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/
64067e55c51SEtienne Carriere
64101980f3fSEtienne Carriere interrupt_main_init(&gic_data.chip);
642b0104773SPascal Brand }
643b0104773SPascal Brand
gic_it_configure(struct gic_data * gd,size_t it)6442a50ce7dSEtienne Carriere static void gic_it_configure(struct gic_data *gd, size_t it)
645b0104773SPascal Brand {
64653bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG;
64753bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
648b0104773SPascal Brand
64967e55c51SEtienne Carriere assert(gd == &gic_data);
65067e55c51SEtienne Carriere
651b0104773SPascal Brand /* Disable the interrupt */
652918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
653b0104773SPascal Brand /* Make it non-pending */
654918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
655b0104773SPascal Brand /* Assign it to group0 */
656918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
6571fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
6581fcac774SSandeep Tripathy /* Assign it to group1S */
6591fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
6601fcac774SSandeep Tripathy #endif
661b0104773SPascal Brand }
662b0104773SPascal Brand
gic_it_set_cpu_mask(struct gic_data * gd,size_t it,uint8_t cpu_mask)6637315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
6647315b7b4SJens Wiklander uint8_t cpu_mask)
665b0104773SPascal Brand {
6668ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
6678ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
668b012d115SEtienne Carriere uint32_t target = 0;
669b012d115SEtienne Carriere uint32_t target_shift = 0;
670918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base +
671918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
672b0104773SPascal Brand
67367e55c51SEtienne Carriere assert(gd == &gic_data);
67467e55c51SEtienne Carriere
675b0104773SPascal Brand /* Assigned to group0 */
676918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
677b0104773SPascal Brand
678b0104773SPascal Brand /* Route it to selected CPUs */
679918bb3a5SEtienne Carriere target = io_read32(itargetsr);
68053bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
68153bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift);
68253bd332aSSY Chiu target |= cpu_mask << target_shift;
683b012d115SEtienne Carriere DMSG("cpu_mask: writing %#"PRIx32" to %#" PRIxVA, target, itargetsr);
684918bb3a5SEtienne Carriere io_write32(itargetsr, target);
685b012d115SEtienne Carriere DMSG("cpu_mask: %#"PRIx32, io_read32(itargetsr));
686b0104773SPascal Brand }
687b0104773SPascal Brand
gic_it_set_prio(struct gic_data * gd,size_t it,uint8_t prio)6887315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
689b0104773SPascal Brand {
6908ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
6918ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
692b0104773SPascal Brand
69367e55c51SEtienne Carriere assert(gd == &gic_data);
69467e55c51SEtienne Carriere
695b0104773SPascal Brand /* Assigned to group0 */
696918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
697b0104773SPascal Brand
698b0104773SPascal Brand /* Set prio it to selected CPUs */
699b012d115SEtienne Carriere DMSG("prio: writing %#"PRIx8" to %#" PRIxVA,
7007315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
701918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
702b0104773SPascal Brand }
703b0104773SPascal Brand
gic_it_set_type(struct gic_data * gd,size_t it,uint32_t type)704141876e4SEtienne Carriere static void gic_it_set_type(struct gic_data *gd, size_t it, uint32_t type)
705141876e4SEtienne Carriere {
706141876e4SEtienne Carriere size_t index = it / GICD_ICFGR_NUM_INTS_PER_REG;
707141876e4SEtienne Carriere uint32_t shift = (it % GICD_ICFGR_NUM_INTS_PER_REG) *
708141876e4SEtienne Carriere GICD_ICFGR_FIELD_BITS;
709141876e4SEtienne Carriere uint32_t icfg = 0;
710141876e4SEtienne Carriere
711141876e4SEtienne Carriere assert(type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH);
712141876e4SEtienne Carriere
713141876e4SEtienne Carriere if (type == IRQ_TYPE_EDGE_RISING)
714141876e4SEtienne Carriere icfg = GICD_ICFGR_TYPE_EDGE;
715141876e4SEtienne Carriere else
716141876e4SEtienne Carriere icfg = GICD_ICFGR_TYPE_LEVEL;
717141876e4SEtienne Carriere
718141876e4SEtienne Carriere io_mask32(gd->gicd_base + GICD_ICFGR(index),
719141876e4SEtienne Carriere SHIFT_U32(icfg, shift),
720141876e4SEtienne Carriere SHIFT_U32(GICD_ICFGR_FIELD_MASK, shift));
721141876e4SEtienne Carriere }
722141876e4SEtienne Carriere
gic_it_enable(struct gic_data * gd,size_t it)7237315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
724b0104773SPascal Brand {
72553bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG;
72653bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
727918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base;
728b0104773SPascal Brand
72967e55c51SEtienne Carriere assert(gd == &gic_data);
73067e55c51SEtienne Carriere
731b0104773SPascal Brand /* Assigned to group0 */
732918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
733b0104773SPascal Brand
734b0104773SPascal Brand /* Enable the interrupt */
735918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask);
736b0104773SPascal Brand }
737b0104773SPascal Brand
gic_it_disable(struct gic_data * gd,size_t it)7387315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
739b0104773SPascal Brand {
74053bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG;
74153bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
742b0104773SPascal Brand
74367e55c51SEtienne Carriere assert(gd == &gic_data);
74467e55c51SEtienne Carriere
745b0104773SPascal Brand /* Assigned to group0 */
746918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
747b0104773SPascal Brand
748b0104773SPascal Brand /* Disable the interrupt */
749918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
750b0104773SPascal Brand }
751b0104773SPascal Brand
gic_it_set_pending(struct gic_data * gd,size_t it)75226ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
75326ed70ecSGuanchao Liang {
75426ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG;
75526ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
75626ed70ecSGuanchao Liang
75767e55c51SEtienne Carriere assert(gd == &gic_data);
75867e55c51SEtienne Carriere
75926ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */
76026ed70ecSGuanchao Liang assert(it >= NUM_SGI);
76126ed70ecSGuanchao Liang
76226ed70ecSGuanchao Liang /* Raise the interrupt */
763918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
76426ed70ecSGuanchao Liang }
76526ed70ecSGuanchao Liang
assert_cpu_mask_is_valid(uint32_t cpu_mask)766ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
767ec740b9fSJens Wiklander {
768ec740b9fSJens Wiklander bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
769ec740b9fSJens Wiklander bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
770ec740b9fSJens Wiklander bool __maybe_unused to_list = cpu_mask & 0xff;
771ec740b9fSJens Wiklander
772ec740b9fSJens Wiklander /* One and only one of the bit fields shall be non-zero */
773ec740b9fSJens Wiklander assert(to_others + to_current + to_list == 1);
774ec740b9fSJens Wiklander }
775ec740b9fSJens Wiklander
gic_it_raise_sgi(struct gic_data * gd __maybe_unused,size_t it,uint32_t cpu_mask,bool ns)77654739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
77784603456SJens Wiklander uint32_t cpu_mask, bool ns)
77826ed70ecSGuanchao Liang {
77954739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
78054739cb4SMark-PK Tsai uint32_t mask_id = it & 0xf;
781ec740b9fSJens Wiklander uint64_t mask = SHIFT_U64(mask_id, 24);
782ec740b9fSJens Wiklander
783ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask);
784ec740b9fSJens Wiklander
785ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
786ec740b9fSJens Wiklander mask |= BIT64(GICC_SGI_IRM_BIT);
787ec740b9fSJens Wiklander } else {
78854739cb4SMark-PK Tsai uint64_t mpidr = read_mpidr();
789ec740b9fSJens Wiklander uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
790ec740b9fSJens Wiklander MPIDR_AFF1_SHIFT;
791ec740b9fSJens Wiklander uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
792ec740b9fSJens Wiklander MPIDR_AFF2_SHIFT;
793ec740b9fSJens Wiklander uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
794ec740b9fSJens Wiklander MPIDR_AFF3_SHIFT;
795ec740b9fSJens Wiklander
796ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
797ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
798ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
799ec740b9fSJens Wiklander
800ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
801ec740b9fSJens Wiklander mask |= BIT32(mpidr & 0xf);
802ec740b9fSJens Wiklander } else {
803ec740b9fSJens Wiklander /*
804ec740b9fSJens Wiklander * Only support sending SGI to the cores in the
805ec740b9fSJens Wiklander * same cluster now.
806ec740b9fSJens Wiklander */
807ec740b9fSJens Wiklander mask |= cpu_mask & 0xff;
808ec740b9fSJens Wiklander }
809ec740b9fSJens Wiklander }
81054739cb4SMark-PK Tsai
81154739cb4SMark-PK Tsai /* Raise the interrupt */
81284603456SJens Wiklander if (ns)
81354739cb4SMark-PK Tsai write_icc_asgi1r(mask);
81454739cb4SMark-PK Tsai else
81554739cb4SMark-PK Tsai write_icc_sgi1r(mask);
81654739cb4SMark-PK Tsai #else
817ec740b9fSJens Wiklander uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
81884603456SJens Wiklander uint32_t mask_group = ns;
819ec740b9fSJens Wiklander uint32_t mask = mask_id;
820ec740b9fSJens Wiklander
821ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask);
822ec740b9fSJens Wiklander
823ec740b9fSJens Wiklander mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
824ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
825ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
826ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
827ec740b9fSJens Wiklander } else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
828ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
829ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
830ec740b9fSJens Wiklander } else {
831ec740b9fSJens Wiklander mask |= SHIFT_U32(cpu_mask & 0xff,
832ec740b9fSJens Wiklander GICD_SGIR_CPU_TARGET_LIST_SHIFT);
833ec740b9fSJens Wiklander }
83426ed70ecSGuanchao Liang
83526ed70ecSGuanchao Liang /* Raise the interrupt */
836918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask);
83754739cb4SMark-PK Tsai #endif
83826ed70ecSGuanchao Liang }
83926ed70ecSGuanchao Liang
gic_read_iar(struct gic_data * gd __maybe_unused)84018901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
841b0104773SPascal Brand {
84267e55c51SEtienne Carriere assert(gd == &gic_data);
84367e55c51SEtienne Carriere
84418901324SDavid Wang #if defined(CFG_ARM_GICV3)
8451de462e1SSumit Garg return read_icc_iar1();
84618901324SDavid Wang #else
847918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR);
84818901324SDavid Wang #endif
849b0104773SPascal Brand }
850b0104773SPascal Brand
gic_write_eoir(struct gic_data * gd __maybe_unused,uint32_t eoir)85118901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
852b0104773SPascal Brand {
85367e55c51SEtienne Carriere assert(gd == &gic_data);
85467e55c51SEtienne Carriere
85518901324SDavid Wang #if defined(CFG_ARM_GICV3)
8561de462e1SSumit Garg write_icc_eoir1(eoir);
85718901324SDavid Wang #else
858918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir);
85918901324SDavid Wang #endif
860b0104773SPascal Brand }
861b0104773SPascal Brand
gic_it_is_enabled(struct gic_data * gd,size_t it)8627315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
8637315b7b4SJens Wiklander {
86453bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG;
86553bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
86667e55c51SEtienne Carriere
86767e55c51SEtienne Carriere assert(gd == &gic_data);
868918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
86953bd332aSSY Chiu }
87053bd332aSSY Chiu
gic_it_get_group(struct gic_data * gd,size_t it)8717315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
8727315b7b4SJens Wiklander {
87353bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG;
87453bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
87567e55c51SEtienne Carriere
87667e55c51SEtienne Carriere assert(gd == &gic_data);
877918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
87853bd332aSSY Chiu }
87953bd332aSSY Chiu
gic_it_get_target(struct gic_data * gd,size_t it)8807315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
8817315b7b4SJens Wiklander {
88253bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG;
8837315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
8847315b7b4SJens Wiklander ITARGETSR_FIELD_BITS;
88553bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
886918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
8877315b7b4SJens Wiklander
88867e55c51SEtienne Carriere assert(gd == &gic_data);
889918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift;
89053bd332aSSY Chiu }
89153bd332aSSY Chiu
gic_dump_state(void)89267e55c51SEtienne Carriere void gic_dump_state(void)
89353bd332aSSY Chiu {
89467e55c51SEtienne Carriere struct gic_data *gd = &gic_data;
89567e55c51SEtienne Carriere int i = 0;
89653bd332aSSY Chiu
89718901324SDavid Wang #if defined(CFG_ARM_GICV3)
898b012d115SEtienne Carriere DMSG("GICC_CTLR: %#"PRIx32, read_icc_ctlr());
89918901324SDavid Wang #else
900b012d115SEtienne Carriere DMSG("GICC_CTLR: %#"PRIx32, io_read32(gd->gicc_base + GICC_CTLR));
90118901324SDavid Wang #endif
902b012d115SEtienne Carriere DMSG("GICD_CTLR: %#"PRIx32, io_read32(gd->gicd_base + GICD_CTLR));
9037315b7b4SJens Wiklander
9044a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) {
9057315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) {
906b012d115SEtienne Carriere DMSG("irq%d: enabled, group:%d, target:%#"PRIx32, i,
9077315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i));
90853bd332aSSY Chiu }
90953bd332aSSY Chiu }
91053bd332aSSY Chiu }
9117315b7b4SJens Wiklander
gic_spi_release_to_ns(size_t it)91210cc5912SRunyang Chen TEE_Result gic_spi_release_to_ns(size_t it)
91310cc5912SRunyang Chen {
91410cc5912SRunyang Chen struct gic_data *gd = &gic_data;
91510cc5912SRunyang Chen size_t idx = it / NUM_INTS_PER_REG;
91610cc5912SRunyang Chen uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
91710cc5912SRunyang Chen
91810cc5912SRunyang Chen if (it >= gd->max_it || it < GIC_SPI_BASE)
91910cc5912SRunyang Chen return TEE_ERROR_BAD_PARAMETERS;
92010cc5912SRunyang Chen /* Make sure it's already disabled */
92110cc5912SRunyang Chen if (!gic_it_is_enabled(gd, it))
92210cc5912SRunyang Chen return TEE_ERROR_BAD_STATE;
92310cc5912SRunyang Chen /* Assert it's secure to start with */
92410cc5912SRunyang Chen if (!gic_it_get_group(gd, it))
92510cc5912SRunyang Chen return TEE_ERROR_BAD_STATE;
92610cc5912SRunyang Chen
92710cc5912SRunyang Chen mutex_lock(&gic_mutex);
92810cc5912SRunyang Chen gic_it_set_cpu_mask(gd, it, 0);
92910cc5912SRunyang Chen gic_it_set_prio(gd, it, GIC_SPI_PRI_NS_EL1);
93010cc5912SRunyang Chen
93110cc5912SRunyang Chen /* Clear pending status */
93210cc5912SRunyang Chen io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
93310cc5912SRunyang Chen /* Assign it to NS Group1 */
93410cc5912SRunyang Chen io_setbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
93510cc5912SRunyang Chen #if defined(CFG_ARM_GICV3)
93610cc5912SRunyang Chen io_clrbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
93710cc5912SRunyang Chen #endif
93810cc5912SRunyang Chen mutex_unlock(&gic_mutex);
93910cc5912SRunyang Chen return TEE_SUCCESS;
94010cc5912SRunyang Chen }
94110cc5912SRunyang Chen
gic_native_itr_handler(void)94267e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
9437315b7b4SJens Wiklander {
94467e55c51SEtienne Carriere struct gic_data *gd = &gic_data;
94567e55c51SEtienne Carriere uint32_t iar = 0;
94667e55c51SEtienne Carriere uint32_t id = 0;
9477315b7b4SJens Wiklander
9487315b7b4SJens Wiklander iar = gic_read_iar(gd);
9497315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK;
9507315b7b4SJens Wiklander
951*b711ff7eSGatien Chevallier if (id >= 1020 && id <= 1023) {
952*b711ff7eSGatien Chevallier /*
953*b711ff7eSGatien Chevallier * Special INTIDs
954*b711ff7eSGatien Chevallier * 1020: Interrupt expected to be handled at SEL1 or SEL2.
955*b711ff7eSGatien Chevallier * PE (Processing Element) is either executing at EL3
956*b711ff7eSGatien Chevallier * in AArch64 state or in monitor mode in AArch32 state.
957*b711ff7eSGatien Chevallier * Reserved on GIC V1 and GIC V2.
958*b711ff7eSGatien Chevallier * 1021: Interrupt expected to be handled at NSEL1 or NSEL2
959*b711ff7eSGatien Chevallier * PE (Processing Element) is either executing at EL3
960*b711ff7eSGatien Chevallier * in AArch64 state or in monitor mode in AArch32 state.
961*b711ff7eSGatien Chevallier * Reserved on GIC V1 and GIC V2.
962*b711ff7eSGatien Chevallier * 1022: -(GICv3.3): Interrupt is an NMI
963*b711ff7eSGatien Chevallier * -(Legacy): Group 1 interrupt to be signaled to the
964*b711ff7eSGatien Chevallier * PE and acknowledged using alias registers. Reserved if
965*b711ff7eSGatien Chevallier * interrupt grouping is not supported.
966*b711ff7eSGatien Chevallier * 1023: No pending interrupt with sufficient priority
967*b711ff7eSGatien Chevallier * (spurious) or the highest priority pending interrupt is
968*b711ff7eSGatien Chevallier * not appropriate for the current security state or
969*b711ff7eSGatien Chevallier * interrupt group.
970*b711ff7eSGatien Chevallier */
971*b711ff7eSGatien Chevallier DMSG("Special interrupt %"PRIu32, id);
972*b711ff7eSGatien Chevallier
973*b711ff7eSGatien Chevallier return;
974*b711ff7eSGatien Chevallier }
975*b711ff7eSGatien Chevallier
9764a9ea08cSFangsuo Wu if (id <= gd->max_it)
97799e2612cSEtienne Carriere interrupt_call_handlers(&gd->chip, id);
9783b3a4611SMathieu Briand else
979*b711ff7eSGatien Chevallier EMSG("Unhandled interrupt %"PRIu32, id);
9807315b7b4SJens Wiklander
9817315b7b4SJens Wiklander gic_write_eoir(gd, iar);
9827315b7b4SJens Wiklander }
9837315b7b4SJens Wiklander
98467e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
985358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
interrupt_main_handler(void)986358bf47cSEtienne Carriere void interrupt_main_handler(void)
98767e55c51SEtienne Carriere {
98867e55c51SEtienne Carriere gic_native_itr_handler();
98967e55c51SEtienne Carriere }
99067e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
99167e55c51SEtienne Carriere
gic_op_configure(struct itr_chip * chip,size_t it,uint32_t type,uint32_t prio __unused)9922a50ce7dSEtienne Carriere static void gic_op_configure(struct itr_chip *chip, size_t it,
993141876e4SEtienne Carriere uint32_t type, uint32_t prio __unused)
9947315b7b4SJens Wiklander {
9957315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip);
9967315b7b4SJens Wiklander
99767e55c51SEtienne Carriere assert(gd == &gic_data);
99867e55c51SEtienne Carriere
9994a9ea08cSFangsuo Wu if (it > gd->max_it)
1000d13278b8SEtienne Carriere panic();
1001d13278b8SEtienne Carriere
10029e935234SJens Wiklander if (it < GIC_SPI_BASE) {
10039e935234SJens Wiklander if (gic_primary_done)
10049e935234SJens Wiklander panic("Cannot add SGI or PPI after boot");
10059e935234SJens Wiklander
10069e935234SJens Wiklander /* Assign it to Secure Group 1, G1S */
10079e935234SJens Wiklander gd->per_cpu_group_modifier |= BIT32(it);
10089e935234SJens Wiklander gd->per_cpu_group_status &= ~BIT32(it);
10099e935234SJens Wiklander }
10109e935234SJens Wiklander
10119e935234SJens Wiklander if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) {
10129e935234SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd);
10139e935234SJens Wiklander
10149e935234SJens Wiklander if (!gicr_base)
10159e935234SJens Wiklander panic("GICR_BASE missing");
10169e935234SJens Wiklander
10179e935234SJens Wiklander /* Disable interrupt */
10189e935234SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(it));
10199e935234SJens Wiklander
10206c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */
10216c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base);
10226c2d2e8aSJens Wiklander
10239e935234SJens Wiklander /* Make interrupt non-pending */
10249e935234SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(it));
10259e935234SJens Wiklander
10269e935234SJens Wiklander /* Make it to Secure */
10279e935234SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status);
10289e935234SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0,
10299e935234SJens Wiklander gd->per_cpu_group_modifier);
10309e935234SJens Wiklander } else {
10312a50ce7dSEtienne Carriere gic_it_configure(gd, it);
10327315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */
10337315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff);
10347315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1);
1035141876e4SEtienne Carriere if (type != IRQ_TYPE_NONE)
1036141876e4SEtienne Carriere gic_it_set_type(gd, it, type);
10377315b7b4SJens Wiklander }
10389e935234SJens Wiklander }
10397315b7b4SJens Wiklander
gic_op_enable(struct itr_chip * chip,size_t it)10407315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
10417315b7b4SJens Wiklander {
10427315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip);
10437315b7b4SJens Wiklander
104467e55c51SEtienne Carriere assert(gd == &gic_data);
104567e55c51SEtienne Carriere
10464a9ea08cSFangsuo Wu if (it > gd->max_it)
1047d13278b8SEtienne Carriere panic();
1048d13278b8SEtienne Carriere
10499e935234SJens Wiklander if (it < GIC_SPI_BASE)
10509e935234SJens Wiklander gd->per_cpu_enable |= BIT(it);
10519e935234SJens Wiklander
10529e935234SJens Wiklander if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) {
10539e935234SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd);
10549e935234SJens Wiklander
10559e935234SJens Wiklander if (!gicr_base)
10569e935234SJens Wiklander panic("GICR_BASE missing");
10579e935234SJens Wiklander
10589e935234SJens Wiklander /* Assigned to G1S */
10599e935234SJens Wiklander assert(gd->per_cpu_group_modifier & BIT(it) &&
10609e935234SJens Wiklander !(gd->per_cpu_group_status & BIT(it)));
10619e935234SJens Wiklander io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable);
10629e935234SJens Wiklander } else {
10637315b7b4SJens Wiklander gic_it_enable(gd, it);
10647315b7b4SJens Wiklander }
10659e935234SJens Wiklander }
10667315b7b4SJens Wiklander
gic_op_disable(struct itr_chip * chip,size_t it)10677315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
10687315b7b4SJens Wiklander {
10697315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip);
10707315b7b4SJens Wiklander
107167e55c51SEtienne Carriere assert(gd == &gic_data);
107267e55c51SEtienne Carriere
10734a9ea08cSFangsuo Wu if (it > gd->max_it)
1074d13278b8SEtienne Carriere panic();
1075d13278b8SEtienne Carriere
10767315b7b4SJens Wiklander gic_it_disable(gd, it);
10777315b7b4SJens Wiklander }
107826ed70ecSGuanchao Liang
gic_op_raise_pi(struct itr_chip * chip,size_t it)107926ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
108026ed70ecSGuanchao Liang {
108126ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip);
108226ed70ecSGuanchao Liang
108367e55c51SEtienne Carriere assert(gd == &gic_data);
108467e55c51SEtienne Carriere
10854a9ea08cSFangsuo Wu if (it > gd->max_it)
108626ed70ecSGuanchao Liang panic();
108726ed70ecSGuanchao Liang
108826ed70ecSGuanchao Liang gic_it_set_pending(gd, it);
108926ed70ecSGuanchao Liang }
109026ed70ecSGuanchao Liang
gic_op_raise_sgi(struct itr_chip * chip,size_t it,uint32_t cpu_mask)109126ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
1092ec740b9fSJens Wiklander uint32_t cpu_mask)
109326ed70ecSGuanchao Liang {
109426ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip);
109584603456SJens Wiklander bool ns = false;
109626ed70ecSGuanchao Liang
109767e55c51SEtienne Carriere assert(gd == &gic_data);
109867e55c51SEtienne Carriere
109954739cb4SMark-PK Tsai /* Should be Software Generated Interrupt */
110054739cb4SMark-PK Tsai assert(it < NUM_SGI);
110154739cb4SMark-PK Tsai
110284603456SJens Wiklander ns = BIT32(it) & gd->per_cpu_group_status;
110384603456SJens Wiklander gic_it_raise_sgi(gd, it, cpu_mask, ns);
110426ed70ecSGuanchao Liang }
110567e55c51SEtienne Carriere
gic_op_set_affinity(struct itr_chip * chip,size_t it,uint8_t cpu_mask)110626ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
110726ed70ecSGuanchao Liang uint8_t cpu_mask)
110826ed70ecSGuanchao Liang {
110926ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip);
111026ed70ecSGuanchao Liang
111167e55c51SEtienne Carriere assert(gd == &gic_data);
111267e55c51SEtienne Carriere
11134a9ea08cSFangsuo Wu if (it > gd->max_it)
111426ed70ecSGuanchao Liang panic();
111526ed70ecSGuanchao Liang
111626ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask);
111726ed70ecSGuanchao Liang }
111814885eb1SEtienne Carriere
111914885eb1SEtienne Carriere #ifdef CFG_DT
112014885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
dt_get_gic_chip_cb(struct dt_pargs * arg,void * priv_data,struct itr_desc * itr_desc)112114885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
112214885eb1SEtienne Carriere struct itr_desc *itr_desc)
112314885eb1SEtienne Carriere {
112414885eb1SEtienne Carriere int itr_num = DT_INFO_INVALID_INTERRUPT;
112514885eb1SEtienne Carriere struct itr_chip *chip = priv_data;
1126141876e4SEtienne Carriere uint32_t phandle_args[3] = { };
112714885eb1SEtienne Carriere uint32_t type = 0;
112814885eb1SEtienne Carriere uint32_t prio = 0;
112914885eb1SEtienne Carriere
113014885eb1SEtienne Carriere assert(arg && itr_desc);
113114885eb1SEtienne Carriere
113214885eb1SEtienne Carriere /*
113314885eb1SEtienne Carriere * gic_dt_get_irq() expects phandle arguments passed are still in DT
113414885eb1SEtienne Carriere * format (big-endian) whereas struct dt_pargs carries converted
113514885eb1SEtienne Carriere * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
113614885eb1SEtienne Carriere * consumes only the 2 first arguments.
113714885eb1SEtienne Carriere */
113814885eb1SEtienne Carriere if (arg->args_count < 2)
113914885eb1SEtienne Carriere return TEE_ERROR_GENERIC;
1140141876e4SEtienne Carriere
114114885eb1SEtienne Carriere phandle_args[0] = cpu_to_fdt32(arg->args[0]);
114214885eb1SEtienne Carriere phandle_args[1] = cpu_to_fdt32(arg->args[1]);
1143141876e4SEtienne Carriere if (arg->args_count >= 3)
1144141876e4SEtienne Carriere phandle_args[2] = cpu_to_fdt32(arg->args[2]);
114514885eb1SEtienne Carriere
1146141876e4SEtienne Carriere itr_num = gic_dt_get_irq((const void *)phandle_args, arg->args_count,
1147141876e4SEtienne Carriere &type, &prio);
114814885eb1SEtienne Carriere if (itr_num == DT_INFO_INVALID_INTERRUPT)
114914885eb1SEtienne Carriere return TEE_ERROR_GENERIC;
115014885eb1SEtienne Carriere
11512a50ce7dSEtienne Carriere gic_op_configure(chip, itr_num, type, prio);
115214885eb1SEtienne Carriere
115314885eb1SEtienne Carriere itr_desc->chip = chip;
115414885eb1SEtienne Carriere itr_desc->itr_num = itr_num;
115514885eb1SEtienne Carriere
115614885eb1SEtienne Carriere return TEE_SUCCESS;
115714885eb1SEtienne Carriere }
115814885eb1SEtienne Carriere
gic_probe(const void * fdt,int offs,const void * cd __unused)115914885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
116014885eb1SEtienne Carriere {
116114885eb1SEtienne Carriere if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
116214885eb1SEtienne Carriere &gic_data.chip))
116314885eb1SEtienne Carriere panic();
116414885eb1SEtienne Carriere
116514885eb1SEtienne Carriere return TEE_SUCCESS;
116614885eb1SEtienne Carriere }
116714885eb1SEtienne Carriere
116814885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
116914885eb1SEtienne Carriere { .compatible = "arm,cortex-a15-gic" },
117014885eb1SEtienne Carriere { .compatible = "arm,cortex-a7-gic" },
117114885eb1SEtienne Carriere { .compatible = "arm,cortex-a5-gic" },
117214885eb1SEtienne Carriere { .compatible = "arm,cortex-a9-gic" },
117314885eb1SEtienne Carriere { .compatible = "arm,gic-400" },
117414885eb1SEtienne Carriere { }
117514885eb1SEtienne Carriere };
117614885eb1SEtienne Carriere
117714885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
117814885eb1SEtienne Carriere .name = "gic",
117914885eb1SEtienne Carriere .match_table = gic_match_table,
118014885eb1SEtienne Carriere .probe = gic_probe,
118114885eb1SEtienne Carriere };
118214885eb1SEtienne Carriere #endif /*CFG_DT*/
11839e935234SJens Wiklander
gic_set_primary_done(void)11849e935234SJens Wiklander static TEE_Result gic_set_primary_done(void)
11859e935234SJens Wiklander {
11869e935234SJens Wiklander gic_primary_done = true;
11879e935234SJens Wiklander return TEE_SUCCESS;
11889e935234SJens Wiklander }
11899e935234SJens Wiklander
11909e935234SJens Wiklander nex_release_init_resource(gic_set_primary_done);
1191