root/tools/testing/selftests/kvm/include/arm64/gic_v5.h
/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef __SELFTESTS_GIC_V5_H
#define __SELFTESTS_GIC_V5_H

#include <asm/barrier.h>
#include <asm/sysreg.h>

#include <linux/bitfield.h>

#include "processor.h"

/*
 * Definitions for GICv5 instructions for the Current Domain
 */
#define GICV5_OP_GIC_CDAFF              sys_insn(1, 0, 12, 1, 3)
#define GICV5_OP_GIC_CDDI               sys_insn(1, 0, 12, 2, 0)
#define GICV5_OP_GIC_CDDIS              sys_insn(1, 0, 12, 1, 0)
#define GICV5_OP_GIC_CDHM               sys_insn(1, 0, 12, 2, 1)
#define GICV5_OP_GIC_CDEN               sys_insn(1, 0, 12, 1, 1)
#define GICV5_OP_GIC_CDEOI              sys_insn(1, 0, 12, 1, 7)
#define GICV5_OP_GIC_CDPEND             sys_insn(1, 0, 12, 1, 4)
#define GICV5_OP_GIC_CDPRI              sys_insn(1, 0, 12, 1, 2)
#define GICV5_OP_GIC_CDRCFG             sys_insn(1, 0, 12, 1, 5)
#define GICV5_OP_GICR_CDIA              sys_insn(1, 0, 12, 3, 0)
#define GICV5_OP_GICR_CDNMIA            sys_insn(1, 0, 12, 3, 1)

/* Definitions for GIC CDAFF */
#define GICV5_GIC_CDAFF_IAFFID_MASK     GENMASK_ULL(47, 32)
#define GICV5_GIC_CDAFF_TYPE_MASK       GENMASK_ULL(31, 29)
#define GICV5_GIC_CDAFF_IRM_MASK        BIT_ULL(28)
#define GICV5_GIC_CDAFF_ID_MASK         GENMASK_ULL(23, 0)

/* Definitions for GIC CDDI */
#define GICV5_GIC_CDDI_TYPE_MASK        GENMASK_ULL(31, 29)
#define GICV5_GIC_CDDI_ID_MASK          GENMASK_ULL(23, 0)

/* Definitions for GIC CDDIS */
#define GICV5_GIC_CDDIS_TYPE_MASK       GENMASK_ULL(31, 29)
#define GICV5_GIC_CDDIS_TYPE(r)         FIELD_GET(GICV5_GIC_CDDIS_TYPE_MASK, r)
#define GICV5_GIC_CDDIS_ID_MASK         GENMASK_ULL(23, 0)
#define GICV5_GIC_CDDIS_ID(r)           FIELD_GET(GICV5_GIC_CDDIS_ID_MASK, r)

/* Definitions for GIC CDEN */
#define GICV5_GIC_CDEN_TYPE_MASK        GENMASK_ULL(31, 29)
#define GICV5_GIC_CDEN_ID_MASK          GENMASK_ULL(23, 0)

/* Definitions for GIC CDHM */
#define GICV5_GIC_CDHM_HM_MASK          BIT_ULL(32)
#define GICV5_GIC_CDHM_TYPE_MASK        GENMASK_ULL(31, 29)
#define GICV5_GIC_CDHM_ID_MASK          GENMASK_ULL(23, 0)

/* Definitions for GIC CDPEND */
#define GICV5_GIC_CDPEND_PENDING_MASK   BIT_ULL(32)
#define GICV5_GIC_CDPEND_TYPE_MASK      GENMASK_ULL(31, 29)
#define GICV5_GIC_CDPEND_ID_MASK        GENMASK_ULL(23, 0)

/* Definitions for GIC CDPRI */
#define GICV5_GIC_CDPRI_PRIORITY_MASK   GENMASK_ULL(39, 35)
#define GICV5_GIC_CDPRI_TYPE_MASK       GENMASK_ULL(31, 29)
#define GICV5_GIC_CDPRI_ID_MASK         GENMASK_ULL(23, 0)

/* Definitions for GIC CDRCFG */
#define GICV5_GIC_CDRCFG_TYPE_MASK      GENMASK_ULL(31, 29)
#define GICV5_GIC_CDRCFG_ID_MASK        GENMASK_ULL(23, 0)

/* Definitions for GICR CDIA */
#define GICV5_GICR_CDIA_VALID_MASK      BIT_ULL(32)
#define GICV5_GICR_CDIA_VALID(r)        FIELD_GET(GICV5_GICR_CDIA_VALID_MASK, r)
#define GICV5_GICR_CDIA_TYPE_MASK       GENMASK_ULL(31, 29)
#define GICV5_GICR_CDIA_ID_MASK         GENMASK_ULL(23, 0)
#define GICV5_GICR_CDIA_INTID           GENMASK_ULL(31, 0)

/* Definitions for GICR CDNMIA */
#define GICV5_GICR_CDNMIA_VALID_MASK    BIT_ULL(32)
#define GICV5_GICR_CDNMIA_VALID(r)      FIELD_GET(GICV5_GICR_CDNMIA_VALID_MASK, r)
#define GICV5_GICR_CDNMIA_TYPE_MASK     GENMASK_ULL(31, 29)
#define GICV5_GICR_CDNMIA_ID_MASK       GENMASK_ULL(23, 0)

#define gicr_insn(insn)                 read_sysreg_s(GICV5_OP_GICR_##insn)
#define gic_insn(v, insn)               write_sysreg_s(v, GICV5_OP_GIC_##insn)

#define __GIC_BARRIER_INSN(op0, op1, CRn, CRm, op2, Rt)                 \
        __emit_inst(0xd5000000                                  |       \
                    sys_insn((op0), (op1), (CRn), (CRm), (op2)) |       \
                    ((Rt) & 0x1f))

#define GSB_SYS_BARRIER_INSN            __GIC_BARRIER_INSN(1, 0, 12, 0, 0, 31)
#define GSB_ACK_BARRIER_INSN            __GIC_BARRIER_INSN(1, 0, 12, 0, 1, 31)

#define gsb_ack()       asm volatile(GSB_ACK_BARRIER_INSN : : : "memory")
#define gsb_sys()       asm volatile(GSB_SYS_BARRIER_INSN : : : "memory")

#define REPEAT_BYTE(x)  ((~0ul / 0xff) * (x))

#define GICV5_IRQ_DEFAULT_PRI 0b10000

#define GICV5_ARCH_PPI_SW_PPI           0x3

void gicv5_ppi_priority_init(void)
{
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR0_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR1_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR2_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR3_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR4_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR5_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR6_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR7_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR8_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR9_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR10_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR11_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR12_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR13_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR14_EL1);
        write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_DEFAULT_PRI), SYS_ICC_PPI_PRIORITYR15_EL1);

        /*
         * Context syncronization required to make sure system register writes
         * effects are synchronised.
         */
        isb();
}

void gicv5_cpu_disable_interrupts(void)
{
        u64 cr0;

        cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 0);
        write_sysreg_s(cr0, SYS_ICC_CR0_EL1);
}

void gicv5_cpu_enable_interrupts(void)
{
        u64 cr0, pcr;

        write_sysreg_s(0, SYS_ICC_PPI_ENABLER0_EL1);
        write_sysreg_s(0, SYS_ICC_PPI_ENABLER1_EL1);

        gicv5_ppi_priority_init();

        pcr = FIELD_PREP(ICC_PCR_EL1_PRIORITY, GICV5_IRQ_DEFAULT_PRI);
        write_sysreg_s(pcr, SYS_ICC_PCR_EL1);

        cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 1);
        write_sysreg_s(cr0, SYS_ICC_CR0_EL1);
}

#endif