diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 83bf430f4684c4caeeb9c8ff469b92e2e05ab8c8..7282bdc451e1923c83a01e8d552be6bbcf36b70b 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -428,6 +428,74 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, return INTR_GROUP0; } +/***************************************************************************** + * Function to save and disable the GIC ITS register context. The power + * management of GIC ITS is implementation-defined and this function doesn't + * save any memory structures required to support ITS. As the sequence to save + * this state is implementation defined, it should be executed in platform + * specific code. Calling this function alone and then powering down the GIC and + * ITS without implementing the aforementioned platform specific code will + * corrupt the ITS state. + * + * This function must be invoked after the GIC CPU interface is disabled. + *****************************************************************************/ +void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx) +{ + int i; + + assert(gicv3_driver_data); + assert(IS_IN_EL3()); + assert(its_ctx); + assert(gits_base); + + its_ctx->gits_ctlr = gits_read_ctlr(gits_base); + + /* Disable the ITS */ + gits_write_ctlr(gits_base, its_ctx->gits_ctlr & + (~GITS_CTLR_ENABLED_BIT)); + + /* Wait for quiescent state */ + gits_wait_for_quiescent_bit(gits_base); + + its_ctx->gits_cbaser = gits_read_cbaser(gits_base); + its_ctx->gits_cwriter = gits_read_cwriter(gits_base); + + for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++) + its_ctx->gits_baser[i] = gits_read_baser(gits_base, i); +} + +/***************************************************************************** + * Function to restore the GIC ITS register context. The power + * management of GIC ITS is implementation defined and this function doesn't + * restore any memory structures required to support ITS. The assumption is + * that these structures are in memory and are retained during system suspend. + * + * This must be invoked before the GIC CPU interface is enabled. + *****************************************************************************/ +void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx) +{ + int i; + + assert(gicv3_driver_data); + assert(IS_IN_EL3()); + assert(its_ctx); + assert(gits_base); + + /* Assert that the GITS is disabled and quiescent */ + assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0); + assert((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 1); + + gits_write_cbaser(gits_base, its_ctx->gits_cbaser); + gits_write_cwriter(gits_base, its_ctx->gits_cwriter); + + for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++) + gits_write_baser(gits_base, i, its_ctx->gits_baser[i]); + + /* Restore the ITS CTLR but leave the ITS disabled */ + gits_write_ctlr(gits_base, its_ctx->gits_ctlr & + (~GITS_CTLR_ENABLED_BIT)); +} + /***************************************************************************** * Function to save the GIC Redistributor register context. This function * must be invoked after CPU interface disable and prior to Distributor save. diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h index 7224e0675d447c257f70da5b4aab5987b60c7074..59298edf2de1aa9e515b77794b4b6edd0a70950f 100644 --- a/drivers/arm/gic/v3/gicv3_private.h +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -314,4 +314,60 @@ static inline void gicr_write_pendbaser(uintptr_t base, unsigned int val) mmio_write_32(base + GICR_PENDBASER, val); } +/******************************************************************************* + * GIC ITS functions to read and write entire ITS registers. + ******************************************************************************/ +static inline uint32_t gits_read_ctlr(uintptr_t base) +{ + return mmio_read_32(base + GITS_CTLR); +} + +static inline void gits_write_ctlr(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GITS_CTLR, val); +} + +static inline uint64_t gits_read_cbaser(uintptr_t base) +{ + return mmio_read_64(base + GITS_CBASER); +} + +static inline void gits_write_cbaser(uintptr_t base, uint64_t val) +{ + mmio_write_32(base + GITS_CBASER, val); +} + +static inline uint64_t gits_read_cwriter(uintptr_t base) +{ + return mmio_read_64(base + GITS_CWRITER); +} + +static inline void gits_write_cwriter(uintptr_t base, uint64_t val) +{ + mmio_write_32(base + GITS_CWRITER, val); +} + +static inline uint64_t gits_read_baser(uintptr_t base, unsigned int its_table_id) +{ + assert(its_table_id < 8); + return mmio_read_64(base + GITS_BASER + (8 * its_table_id)); +} + +static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, uint64_t val) +{ + assert(its_table_id < 8); + mmio_write_64(base + GITS_BASER + (8 * its_table_id), val); +} + +/* + * Wait for Quiescent bit when GIC ITS is disabled + */ +static inline void gits_wait_for_quiescent_bit(uintptr_t gits_base) +{ + assert(!(gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT)); + while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0) + ; +} + + #endif /* __GICV3_PRIVATE_H__ */ diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index d20421d285b70cc7c15918702c80c8a8865e0883..c52fe4833fa943ca40deac97529df6377ee5879c 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -165,6 +165,23 @@ #define IAR1_EL1_INTID_SHIFT 0 #define IAR1_EL1_INTID_MASK 0xffffff +/***************************************************************************** + * GICv3 ITS registers and constants + *****************************************************************************/ + +#define GITS_CTLR 0x0 +#define GITS_IIDR 0x4 +#define GITS_TYPER 0x8 +#define GITS_CBASER 0x80 +#define GITS_CWRITER 0x88 +#define GITS_CREADR 0x90 +#define GITS_BASER 0x100 + +/* GITS_CTLR bit definitions */ +#define GITS_CTLR_ENABLED_BIT 1 +#define GITS_CTLR_QUIESCENT_SHIFT 31 +#define GITS_CTLR_QUIESCENT_BIT (1U << GITS_CTLR_QUIESCENT_SHIFT) + #ifndef __ASSEMBLY__ #include @@ -293,6 +310,16 @@ typedef struct gicv3_dist_ctx { uint32_t gicd_nsacr[GICD_NUM_REGS(NSACR)]; } gicv3_dist_ctx_t; +typedef struct gicv3_its_ctx { + /* 64 bits registers */ + uint64_t gits_cbaser; + uint64_t gits_cwriter; + uint64_t gits_baser[8]; + + /* 32 bits registers */ + uint32_t gits_ctlr; +} gicv3_its_ctx_t; + /******************************************************************************* * GICv3 EL3 driver API ******************************************************************************/ @@ -319,6 +346,8 @@ void gicv3_distif_post_restore(unsigned int proc_num); void gicv3_distif_pre_save(unsigned int proc_num); void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx); void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx); +void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx); +void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx); #endif /* __ASSEMBLY__ */ #endif /* __GICV3_H__ */