blob: d01d24be1359be91e2c269b9a74e4548c1c894ff [file] [log] [blame]
/*
* Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef GICV5_H
#define GICV5_H
#ifndef __ASSEMBLER__
#include <stdbool.h>
#include <stdint.h>
#include <lib/mmio.h>
#endif
#include <lib/utils_def.h>
/* Interrupt Domain definitions */
#define INTDMN_S 0
#define INTDMN_NS 1
#define INTDMN_EL3 2
#define INTDMN_RL 3
/* Trigger modes */
#define TM_EDGE 0
#define TM_LEVEL 1
/* Architected PPI numbers */
#define PPI_TRBIRQ 31
#define PPI_CNTP 30
#define PPI_CNTPS 29
#define PPI_CNTHV 28
#define PPI_CNTV 27
#define PPI_CNTHP 26
#define PPI_GICMNT 25
#define PPI_CTIIRQ 24
#define PPI_PMUIRQ 23
#define PPI_COMMIRQ 22
#define PPI_PMBIRQ 21
#define PPI_CNTHPS 20
#define PPI_CNTHVS 19
#define PPI_DB_NS 2
#define PPI_DB_RL 1
#define PPI_DB_S 0
/* Register fields common to all IRI components.
* They have the same name and offset in every config frame */
#define IRI_AIDR_COMPONENT_SHIFT 8
#define IRI_AIDR_COMPONENT_WIDTH 4
#define IRI_AIDR_COMPONENT_IRS 0
#define IRI_AIDR_COMPONENT_ITS 1
#define IRI_AIDR_COMPONENT_IWB 2
#define IRI_AIDR_ARCH_MAJOR_SHIFT 4
#define IRI_AIDR_ARCH_MAJOR_WIDTH 4
#define IRI_AIDR_ARCH_MAJOR_V5 0
#define IRI_AIDR_ARCH_MINOR_SHIFT 0
#define IRI_AIDR_ARCH_MINOR_WIDTH 4
#define IRI_AIDR_ARCH_MINOR_P0 0
/* IRS register fields */
#define IRS_IDR6_SPI_IRS_RANGE_SHIFT 0
#define IRS_IDR6_SPI_IRS_RANGE_WIDTH 24
#define IRS_IDR7_SPI_BASE_SHIFT 0
#define IRS_IDR7_SPI_BASE_WIDTH 24
#define IRS_SPI_STATUSR_IDLE_BIT BIT(0)
#define IRS_SPI_STATUSR_V_BIT BIT(1)
/* IWB register fields */
#define IWB_IDR0_DOMAINS_SHIFT 11
#define IWB_IDR0_DOMAINS_WIDTH 4
#define IWB_IDR0_IWRANGE_SHIFT 0
#define IWB_IDR0_IWRANGE_WIDTH 10
#define IWB_CR0_IWBEN_BIT BIT(0)
#define IWB_CR0_IDLE_BIT BIT(1)
#define IWB_WENABLE_STATUSR_IDLE_BIT BIT(0)
#define IWB_WDOMAIN_STATUSR_IDLE_BIT BIT(0)
#define IWB_WDOMAINR_DOMAINX_MASK 0x3
#ifndef __ASSEMBLER__
#define _PPI_FIELD_SHIFT(_REG, _ppi_id) \
((_ppi_id % (ICC_PPI_##_REG##_COUNT)) * (64 / ICC_PPI_##_REG##_COUNT))
#define write_icc_ppi_domainr(_var, _ppi_id, _value) \
do { \
_var |= (uint64_t)_value << _PPI_FIELD_SHIFT(DOMAINR, _ppi_id);\
} while (false)
#define DEFINE_GICV5_MMIO_WRITE_FUNC(_name, _offset) \
static inline void write_##_name(uintptr_t base, uint32_t val) \
{ \
mmio_write_32(base + _offset, val); \
}
#define DEFINE_GICV5_MMIO_READ_FUNC(_name, _offset) \
static inline uint32_t read_##_name(uintptr_t base) \
{ \
return mmio_read_32(base + _offset); \
}
#define DEFINE_GICV5_MMIO_WRITE_INDEXED_FUNC(_name, _offset) \
static inline void write_##_name(uintptr_t base, uint16_t index, uint32_t val) \
{ \
mmio_write_32(base + _offset + (index * sizeof(uint32_t)), val); \
}
#define DEFINE_GICV5_MMIO_READ_INDEXED_FUNC(_name, _offset) \
static inline uint32_t read_##_name(uintptr_t base, uint16_t index) \
{ \
return mmio_read_32(base + _offset + (index * sizeof(uint32_t))); \
}
#define DEFINE_GICV5_MMIO_RW_FUNCS(_name, _offset) \
DEFINE_GICV5_MMIO_READ_FUNC(_name, _offset) \
DEFINE_GICV5_MMIO_WRITE_FUNC(_name, _offset)
#define DEFINE_GICV5_MMIO_RW_INDEXED_FUNCS(_name, _offset) \
DEFINE_GICV5_MMIO_READ_INDEXED_FUNC(_name, _offset) \
DEFINE_GICV5_MMIO_WRITE_INDEXED_FUNC(_name, _offset)
DEFINE_GICV5_MMIO_READ_FUNC(iri_aidr, 0x44)
DEFINE_GICV5_MMIO_READ_FUNC(iwb_idr0, 0x00)
DEFINE_GICV5_MMIO_RW_FUNCS( iwb_cr0, 0x80)
DEFINE_GICV5_MMIO_READ_FUNC(iwb_wenable_statusr, 0xc0)
DEFINE_GICV5_MMIO_READ_FUNC(iwb_wdomain_statusr, 0xc4)
DEFINE_GICV5_MMIO_RW_INDEXED_FUNCS(iwb_wenabler, 0x2000)
DEFINE_GICV5_MMIO_RW_INDEXED_FUNCS(iwb_wtmr, 0x4000)
DEFINE_GICV5_MMIO_RW_INDEXED_FUNCS(iwb_wdomainr, 0x6000)
DEFINE_GICV5_MMIO_READ_FUNC(irs_idr6, 0x0018)
DEFINE_GICV5_MMIO_READ_FUNC(irs_idr7, 0x001c)
DEFINE_GICV5_MMIO_RW_FUNCS( irs_spi_selr, 0x0108)
DEFINE_GICV5_MMIO_RW_FUNCS( irs_spi_domainr, 0x010c)
DEFINE_GICV5_MMIO_RW_FUNCS( irs_spi_cfgr, 0x0114)
DEFINE_GICV5_MMIO_READ_FUNC(irs_spi_statusr, 0x0118)
#define WAIT_FOR_IDLE(base, reg, reg_up) \
do { \
while ((read_##reg(base) & reg_up##_IDLE_BIT) == 0U) {} \
} while (0)
/* wait for IDLE but also check the V bit was set */
#define WAIT_FOR_VIDLE(base, reg, reg_up) \
do { \
uint32_t val; \
while (((val = read_##reg(base)) & reg_up##_IDLE_BIT) == 0U) {} \
assert((val & reg##_V_BIT) != 0U); \
} while (0)
#define WAIT_FOR_VIDLE_IRS_SPI_STATUSR(base) \
WAIT_FOR_IDLE(base, irs_spi_statusr, IRS_SPI_STATUSR)
#define WAIT_FOR_IDLE_IWB_WENABLE_STATUSR(base) \
WAIT_FOR_IDLE(base, iwb_wenable_statusr, IWB_WENABLE_STATUSR)
#define WAIT_FOR_IDLE_IWB_WDOMAIN_STATUSR(base) \
WAIT_FOR_IDLE(base, iwb_wdomain_statusr, IWB_WDOMAIN_STATUSR)
#define WAIT_FOR_IDLE_IWB_CR0(base) \
WAIT_FOR_IDLE(base, iwb_cr0, IWB_CR0)
#define WIRE_PROP_DESC(_id, _domain, _tm) \
{ \
.id = (_id), \
.domain = (_domain), \
.tm = (_tm), \
}
struct gicv5_wire_props {
/* continuous wire ID as seen by the attached component */
uint32_t id;
/* use the INTDMN_XYZ macros */
uint8_t domain:2;
/* use the TM_XYZ (eg. TM_EDGE) macros */
uint8_t tm:1;
};
/* to describe every IRS in the system */
struct gicv5_irs {
/* mapped device nGnRnE by the platform*/
uintptr_t el3_config_frame;
struct gicv5_wire_props *spis;
uint32_t num_spis;
};
/*
* to describe every IWB in the system where EL3 is the MPPAS. IWBs that have
* another world as an MPPAS need not be included
*/
struct gicv5_iwb {
/* mapped device nGnRnE by the platform*/
uintptr_t config_frame;
struct gicv5_wire_props *wires;
uint32_t num_wires;
};
struct gicv5_driver_data {
struct gicv5_irs *irss;
struct gicv5_iwb *iwbs;
uint32_t num_irss;
uint32_t num_iwbs;
};
extern const struct gicv5_driver_data plat_gicv5_driver_data;
void gicv5_driver_init();
uint8_t gicv5_get_pending_interrupt_type(void);
bool gicv5_has_interrupt_type(unsigned int type);
void gicv5_enable_ppis();
#endif /* __ASSEMBLER__ */
#endif /* GICV5_H */