Files
lk/dev/interrupt/arm_gic/arm_gic_common.h
Travis Geiselbrecht 6a7c4e25d6 [arm][gicv3] pull in new version from trusty
This is a pretty major implementation change of the GIC driver, but it
now handles v3. Unfortunately this is a bit of a revert of some of the
code cleanups and whatnot that have happened on mainline, but will try
to reapply these momentarily.

TODO:
-fix arm32 and computation of SGI targets for v3
-Consider removing all of the secure mode stuff which is really
complicating things and basically untestable in mainline.
-Properly split V2 and V3 into separate files, and have the main gic.c
act as a redirector of calls.
-Allow both v2 and v3 to compile at the same time.
-Make configuration runtime configurable, stop using #define GICBASE and
others.
2025-10-14 01:41:40 -07:00

346 lines
13 KiB
C

/*
* Copyright (c) 2012-2019 LK Trusty Authors. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <platform/gic.h>
#include <lk/reg.h>
#if ARCH_ARM
#include <arch/arm.h>
#endif
#if ARCH_ARM64
#include <arch/arm64.h>
#endif
#ifdef ARCH_ARM
/*
* AArch32 does not have 64 bit mmio support, but the gic spec allows 32 bit
* upper and lower access to _most_ 64 bit gic registers (not GICR_VSGIPENDR,
* GICR_VSGIR or GITS_SGIR).
*/
/* TODO: add mmio_read32 when needed */
static inline void mmio_write64(volatile uint64_t *ptr64, uint64_t val) {
volatile uint32_t *ptr = (volatile uint32_t *)ptr64;
mmio_write32(ptr, (uint32_t)val);
mmio_write32(ptr + 1, val >> 32);
}
#endif
struct arm_gic {
vaddr_t gicc_vaddr;
size_t gicc_size;
vaddr_t gicd_vaddr;
size_t gicd_size;
vaddr_t gicr_vaddr;
size_t gicr_size;
};
#define NUM_ARM_GICS 1
extern struct arm_gic arm_gics[NUM_ARM_GICS];
#if GIC_VERSION > 2
#if WITH_LIB_SM
#define ARM_GIC_USE_DOORBELL_NS_IRQ 1
#define ARM_GIC_DOORBELL_IRQ 13
#endif
/* GICv3/v4 */
#define GICV3_IRQ_GROUP_GRP0S 0
#define GICV3_IRQ_GROUP_GRP1NS 1
#define GICV3_IRQ_GROUP_GRP1S 2
#ifndef ARM_GIC_SELECTED_IRQ_GROUP
#define ARM_GIC_SELECTED_IRQ_GROUP GRP1NS
#endif
#define COMBINE2(a, b) a ## b
#define XCOMBINE2(a, b) COMBINE2(a,b)
#define GICV3_IRQ_GROUP XCOMBINE2(GICV3_IRQ_GROUP_, ARM_GIC_SELECTED_IRQ_GROUP)
/*
* In ARMv8 for GICv3/v4, ARM suggest to use system register
* to access GICC instead of memory map.
*/
#ifdef ARCH_ARM64
#define GICCREG_READ(gic, reg) ARM64_READ_SYSREG(reg)
#define GICCREG_WRITE(gic, reg, val) ARM64_WRITE_SYSREG(reg, (uint64_t)val)
#else /* ARCH_ARM64 */
/* For 32bit mode, use different way to access registers */
#define GICCREG_READ(gic, reg) COMBINE2(arm_read_,reg)()
#define GICCREG_WRITE(gic, reg, val) COMBINE2(arm_write_,reg)(val)
GEN_CP15_REG_FUNCS(icc_ctlr_el1, 0, c12, c12, 4);
GEN_CP15_REG_FUNCS(icc_pmr_el1, 0, c4, c6, 0);
GEN_CP15_REG_FUNCS(icc_bpr0_el1, 0, c12, c8, 3);
GEN_CP15_REG_FUNCS(icc_iar0_el1, 0, c12, c8, 0);
GEN_CP15_REG_FUNCS(icc_eoir0_el1, 0, c12, c8, 1);
GEN_CP15_REG_FUNCS(icc_rpr_el1, 0, c12, c11, 3);
GEN_CP15_REG_FUNCS(icc_hppir0_el1, 0, c12, c8, 2);
GEN_CP15_REG_FUNCS(icc_bpr1_el1, 0, c12, c12, 3);
GEN_CP15_REG_FUNCS(icc_iar1_el1, 0, c12, c12, 0);
GEN_CP15_REG_FUNCS(icc_eoir1_el1, 0, c12, c12, 1);
GEN_CP15_REG_FUNCS(icc_hppir1_el1, 0, c12, c12, 2);
GEN_CP15_REG_FUNCS(icc_dir_el1, 0, c12, c11, 1);
GEN_CP15_REG_FUNCS(icc_sre_el1, 0, c12, c12, 5);
GEN_CP15_REG_FUNCS(icc_igrpen0_el1, 0, c12, c12, 6);
GEN_CP15_REG_FUNCS(icc_igrpen1_el1, 0, c12, c12, 7);
GEN_CP15_REG_FUNCS(icc_ap0r0_el1, 0, c12, c8, 4);
GEN_CP15_REG_FUNCS(icc_ap0r1_el1, 0, c12, c8, 5);
GEN_CP15_REG_FUNCS(icc_ap0r2_el1, 0, c12, c8, 6);
GEN_CP15_REG_FUNCS(icc_ap0r3_el1, 0, c12, c8, 7);
GEN_CP15_REG_FUNCS(icc_ap1r0_el1, 0, c12, c9, 0);
GEN_CP15_REG_FUNCS(icc_ap1r1_el1, 0, c12, c9, 1);
GEN_CP15_REG_FUNCS(icc_ap1r2_el1, 0, c12, c9, 2);
GEN_CP15_REG_FUNCS(icc_ap1r3_el1, 0, c12, c9, 3);
GEN_CP15_REG64_FUNCS(icc_sgi1r_el1, 0, c12);
GEN_CP15_REG64_FUNCS(icc_asgi1r_el1, 1, c12);
GEN_CP15_REG64_FUNCS(icc_sgi0r_el1, 2, c12);
#endif /* ARCH_ARM64 */
#if GICV3_IRQ_GROUP == GICV3_IRQ_GROUP_GRP0S
#define GICC_PRIMARY_HPPIR icc_hppir0_el1
#define GICC_PRIMARY_IAR icc_iar0_el1
#define GICC_PRIMARY_EOIR icc_eoir0_el1
#define GICC_PRIMARY_SGIR icc_sgi0r_el1
#else
#define GICC_PRIMARY_HPPIR icc_hppir1_el1
#define GICC_PRIMARY_IAR icc_iar1_el1
#define GICC_PRIMARY_EOIR icc_eoir1_el1
#define GICC_PRIMARY_SGIR icc_sgi1r_el1
#endif
#define GICC_LIMIT (0x0000)
#else /* GIC_VERSION > 2 */
#ifndef GICC_OFFSET
#define GICC_OFFSET (0x0000)
#endif
#define GICCREG_READ(gic, reg) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(reg >= GICC_OFFSET); \
ASSERT(reg < GICC_LIMIT); \
mmio_read32((volatile uint32_t *)(arm_gics[(gic)].gicc_vaddr + ((reg) - GICC_OFFSET))); \
})
#define GICCREG_WRITE(gic, reg, val) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(reg >= GICC_OFFSET); \
ASSERT(reg < GICC_LIMIT); \
mmio_write32((volatile uint32_t *)(arm_gics[(gic)].gicc_vaddr + ((reg) - GICC_OFFSET)), (val)); \
})
/* main cpu regs */
#define GICC_CTLR (GICC_OFFSET + 0x0000)
#define GICC_PMR (GICC_OFFSET + 0x0004)
#define GICC_BPR (GICC_OFFSET + 0x0008)
#define GICC_IAR (GICC_OFFSET + 0x000c)
#define GICC_EOIR (GICC_OFFSET + 0x0010)
#define GICC_RPR (GICC_OFFSET + 0x0014)
#define GICC_HPPIR (GICC_OFFSET + 0x0018)
#define GICC_ABPR (GICC_OFFSET + 0x001c)
#define GICC_AIAR (GICC_OFFSET + 0x0020)
#define GICC_AEOIR (GICC_OFFSET + 0x0024)
#define GICC_AHPPIR (GICC_OFFSET + 0x0028)
#define GICC_APR(n) (GICC_OFFSET + 0x00d0 + (n) * 4)
#define GICC_NSAPR(n) (GICC_OFFSET + 0x00e0 + (n) * 4)
#define GICC_IIDR (GICC_OFFSET + 0x00fc)
#if 0 /* GICC_DIR is not currently used by anything */
#define GICC_DIR (GICC_OFFSET + 0x1000)
#endif
#define GICC_LIMIT (GICC_OFFSET + 0x1000)
#define GICC_MIN_SIZE (GICC_LIMIT - GICC_OFFSET)
#if WITH_LIB_SM
#define GICC_PRIMARY_HPPIR GICC_AHPPIR
#define GICC_PRIMARY_IAR GICC_AIAR
#define GICC_PRIMARY_EOIR GICC_AEOIR
#else
#define GICC_PRIMARY_HPPIR GICC_HPPIR
#define GICC_PRIMARY_IAR GICC_IAR
#define GICC_PRIMARY_EOIR GICC_EOIR
#endif
#endif /* GIC_VERSION > 2 */
#ifndef GICD_OFFSET
#define GICD_OFFSET (GICC_LIMIT)
#endif
#define GICDREG_READ(gic, reg) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(reg >= GICD_OFFSET); \
ASSERT(reg < GICD_LIMIT); \
mmio_read32((volatile uint32_t *)(arm_gics[(gic)].gicd_vaddr + ((reg) - GICD_OFFSET))); \
})
#define GICDREG_WRITE(gic, reg, val) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(reg >= GICD_OFFSET); \
ASSERT(reg < GICD_LIMIT); \
LTRACEF_LEVEL(3, "GICDREG_WRITE base vaddr %#lx gic %d reg 0x%x val 0x%x\n", arm_gics[gic].gicd_vaddr, gic, reg, val); \
LTRACEF_LEVEL(3, "final address = %#lx\n", arm_gics[gic].gicd_vaddr + ((reg) - GICD_OFFSET)); \
mmio_write32((volatile uint32_t *)(arm_gics[(gic)].gicd_vaddr + ((reg) - GICD_OFFSET)), (val)); \
})
/* distribution regs */
#define GICD_CTLR (GICD_OFFSET + 0x000)
#define GICD_TYPER (GICD_OFFSET + 0x004)
#define GICD_IIDR (GICD_OFFSET + 0x008)
#define GICD_IGROUPR(n) (GICD_OFFSET + 0x080 + (n) * 4)
#define GICD_ISENABLER(n) (GICD_OFFSET + 0x100 + (n) * 4)
#define GICD_ICENABLER(n) (GICD_OFFSET + 0x180 + (n) * 4)
#define GICD_ISPENDR(n) (GICD_OFFSET + 0x200 + (n) * 4)
#define GICD_ICPENDR(n) (GICD_OFFSET + 0x280 + (n) * 4)
#define GICD_ISACTIVER(n) (GICD_OFFSET + 0x300 + (n) * 4)
#define GICD_ICACTIVER(n) (GICD_OFFSET + 0x380 + (n) * 4)
#define GICD_IPRIORITYR(n) (GICD_OFFSET + 0x400 + (n) * 4)
#define GICD_ITARGETSR(n) (GICD_OFFSET + 0x800 + (n) * 4)
#define GICD_ICFGR(n) (GICD_OFFSET + 0xc00 + (n) * 4)
#define GICD_NSACR(n) (GICD_OFFSET + 0xe00 + (n) * 4)
#define GICD_SGIR (GICD_OFFSET + 0xf00)
#define GICD_CPENDSGIR(n) (GICD_OFFSET + 0xf10 + (n) * 4)
#define GICD_SPENDSGIR(n) (GICD_OFFSET + 0xf20 + (n) * 4)
#if GIC_VERSION <= 2
/* for v3 and higher, these are defined later */
#define GICD_LIMIT (GICD_OFFSET + 0x1000)
#define GICD_MIN_SIZE (GICD_LIMIT - GICD_OFFSET)
#endif /* GIC_VERSION <= 2 */
/* GICD_CTRL Register
* Non-Secure Only_a_Single two_Security
* (1U << 8) RES0 nASSGIreq RES0
* (1U << 7) RES0 E1NWF E1NWF
* (1U << 5) RES0 RES0 ARE_NS
* (1U << 4) ARE_NS ARE ARE_S
* (1U << 2) RES0 RES0 ENABLE_G1S
* (1U << 1) ENABLE_G1A ENABLE_G1 ENABLE_G1NS
* (1U << 0) ENABLE_G1 ENABLE_G0 ENABLE_G0
*/
#define GICD_CTLR_RWP (1U << 31)
#define GICD_CTLR_nASSGIreq (1U << 8)
#define GICD_CTRL_E1NWF (1U << 7)
#define GICD_CTLR_DS (1U << 6)
#define GICD_CTLR_ARE_NS (1U << 5)
#define GICD_CTLR_ARE_S (1U << 4)
#define GICD_CTLR_ENABLE_G1S (1U << 2)
#define GICD_CTLR_ENABLE_G1NS (1U << 1)
#define GICD_CTLR_ENABLE_G0 (1U << 0)
#if GIC_VERSION > 2
/* some registers of GICD are 64 bit */
#define GICDREG_READ64(gic, reg) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(reg >= GICD_OFFSET); \
ASSERT(reg < GICD_LIMIT); \
mmio_read64((volatile uint64_t *)(arm_gics[(gic)].gicd_vaddr + ((reg) - GICD_OFFSET))); \
})
#define GICDREG_WRITE64(gic, reg, val) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(reg >= GICD_OFFSET); \
ASSERT(reg < GICD_LIMIT); \
mmio_write64((volatile uint64_t *)(arm_gics[(gic)].gicd_vaddr + ((reg) - GICD_OFFSET)), (val)); \
})
/* GICv3/v4 Distributor interface */
#define GICD_STATUSR (GICD_OFFSET + 0x0010)
#define GICD_SETSPI_NSR (GICD_OFFSET + 0x0040)
#define GICD_CLRSPI_NSR (GICD_OFFSET + 0x0048)
#define GICD_SETSPI_SR (GICD_OFFSET + 0x0050)
#define GICD_CLRSPI_SR (GICD_OFFSET + 0x0058)
#define GICD_IGRPMODR(n) (GICD_OFFSET + 0x0D00 + (n) * 4)
#define GICD_IROUTER(n) (GICD_OFFSET + 0x6000 + (n) * 8)
#define GICD_CIDR0 (GICD_OFFSET + 0xfff0)
#define GICD_CIDR1 (GICD_OFFSET + 0xfff4)
#define GICD_CIDR2 (GICD_OFFSET + 0xfff8)
#define GICD_CIDR3 (GICD_OFFSET + 0xfffc)
#define GICD_PIDR0 (GICD_OFFSET + 0xffe0)
#define GICD_PIDR1 (GICD_OFFSET + 0xffe4)
#define GICD_PIDR2 (GICD_OFFSET + 0xffe8)
#define GICD_PIDR3 (GICD_OFFSET + 0xffec)
#define GICD_LIMIT (GICD_OFFSET + 0x10000)
#define GICD_MIN_SIZE (GICD_LIMIT - GICD_OFFSET)
/* GICv3/v4 Redistrubutor interface */
#if GIC_VERSION == 3
#define GICR_CPU_OFFSET(cpu) ((cpu) * 0x20000)
#endif
#if GIC_VERSION == 4
#define GICR_CPU_OFFSET(cpu) ((cpu) * 0x40000)
#endif
#ifndef GICR_OFFSET
#define GICR_OFFSET (GICD_LIMIT)
#endif
#define GICRREG_READ(gic, cpu, reg) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(cpu < SMP_MAX_CPUS); \
ASSERT(reg >= GICR_OFFSET); \
ASSERT(reg < GICR_LIMIT); \
mmio_read32((volatile uint32_t *)(arm_gics[(gic)].gicr_vaddr + GICR_CPU_OFFSET(cpu) + ((reg) - GICR_OFFSET))); \
})
#define GICRREG_WRITE(gic, cpu, reg, val) ({ \
ASSERT(gic < NUM_ARM_GICS); \
ASSERT(cpu < SMP_MAX_CPUS); \
ASSERT(reg >= GICR_OFFSET); \
ASSERT(reg < GICR_LIMIT); \
LTRACEF_LEVEL(3, "GICRREG_WRITE base vaddr %#lx gic %d cpu %d reg 0x%x val 0x%x\n", arm_gics[gic].gicr_vaddr, gic, cpu, reg, val); \
LTRACEF_LEVEL(3, "final address = %#lx\n", arm_gics[gic].gicr_vaddr + GICR_CPU_OFFSET(cpu) + ((reg) - GICR_OFFSET)); \
mmio_write32((volatile uint32_t *)(arm_gics[(gic)].gicr_vaddr + GICR_CPU_OFFSET(cpu) + ((reg) - GICR_OFFSET)), (val)); \
})
#define GICR_CTRL (GICR_OFFSET + 0x0000)
#define GICR_IIDR (GICR_OFFSET + 0x0004)
#define GICR_TYPER (GICR_OFFSET + 0x0008)
#define GICR_STATUSR (GICR_OFFSET + 0x0010)
#define GICR_WAKER (GICR_OFFSET + 0x0014)
/* The following GICR registers are on separate 64KB page */
#define GICR_SGI_OFFSET (GICR_OFFSET + 0x10000)
#define GICR_IGROUPR0 (GICR_SGI_OFFSET + 0x0080)
#define GICR_ISENABLER0 (GICR_SGI_OFFSET + 0x0100)
#define GICR_ICENABLER0 (GICR_SGI_OFFSET + 0x0180)
#define GICR_ISPENDR0 (GICR_SGI_OFFSET + 0x0200)
#define GICR_ICPENDR0 (GICR_SGI_OFFSET + 0x0280)
#define GICR_ISACTIVER0 (GICR_SGI_OFFSET + 0x0300)
#define GICR_ICACTIVER0 (GICR_SGI_OFFSET + 0x0380)
#define GICR_IPRIORITYR(n) (GICR_SGI_OFFSET + 0x0400 + (n) * 4)
#define GICR_ICFGR(n) (GICR_SGI_OFFSET + 0x0C00 + (n) * 4)
#define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00)
#define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00)
#define GICR_LIMIT (GICR_SGI_OFFSET + 0x1000)
#define GICR_MIN_SIZE (0x10000)
#endif /* GIC_VERSION > 2 */
// XXX: from trusty macros.h
#define ROUND_UP(n, d) (((n) + (size_t)(d) - 1) & ~((size_t)(d) - 1))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))