GICv3: ITS architectural save and restore helpers

This patch adds functions to save and restore GICv3 ITS registers during
system suspend. Please note that the power management of GIC ITS is
implementation defined. These functions only implements the
architectural part of the ITS power management and they do not restore
memory structures or register content required to support ITS. Even if
the ITS implementation stores structures in memory, an implementation
defined power down sequence is likely to be required to flush some
internal ITS caches to memory. If such implementation defined sequence
is not followed, the platform must ensure that the ITS is not power
gated during system suspend.

Change-Id: I5f31e5541975aa7dcaab69b0b7f67583c0e27678
Signed-off-by: Soby Mathew <soby.mathew@arm.com>
Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
This commit is contained in:
Soby Mathew 2017-07-18 16:12:45 +01:00
parent ebf1ca10e4
commit b258278eec
3 changed files with 153 additions and 0 deletions

View File

@ -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.

View File

@ -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__ */

View File

@ -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 <gic_common.h>
@ -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__ */