418 lines
14 KiB
C
418 lines
14 KiB
C
/*******************************************************************************
|
|
* DISCLAIMER
|
|
* This software is supplied by Renesas Electronics Corporation and is only
|
|
* intended for use with Renesas products. No other uses are authorized. This
|
|
* software is owned by Renesas Electronics Corporation and is protected under
|
|
* all applicable laws, including copyright laws.
|
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
|
|
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
|
|
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
|
|
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
|
|
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
|
|
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
|
|
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
|
|
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
* Renesas reserves the right, without notice, to make changes to this software
|
|
* and to discontinue the availability of this software. By using this software,
|
|
* you agree to the additional terms and conditions found by accessing the
|
|
* following link:
|
|
* http://www.renesas.com/disclaimer
|
|
* Copyright 2018-2023 Renesas Electronics Corporation All rights reserved.
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* DESCRIPTION : GIC Control Function
|
|
******************************************************************************/
|
|
/******************************************************************************
|
|
* @file gic.h
|
|
* - Version : 0.04
|
|
* @brief Controls GIC-600 registers and interrupts.
|
|
* .
|
|
*****************************************************************************/
|
|
/******************************************************************************
|
|
* History : DD.MM.YYYY Version Description
|
|
* : 02.08.2022 0.01 First Release
|
|
* : 20.09.2022 0.02 Set ChildrenAsleep of GICR_WAKER to 1 and end processing
|
|
* : 31.10.2022 0.03 License notation change.
|
|
* : 04.04.2023 0.04 Removed stdio.h.
|
|
*****************************************************************************/
|
|
|
|
#ifndef GIC_H
|
|
#define GIC_H
|
|
|
|
/*******************************************************************************
|
|
** Include Section **
|
|
*******************************************************************************/
|
|
#include <stdint.h>
|
|
|
|
/*******************************************************************************
|
|
** Version Information **
|
|
*******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
** Global Symbols **
|
|
*******************************************************************************/
|
|
/* GIC base */
|
|
#define GICD_BASE (0xF1000000UL)
|
|
#define GICR_BASE (GICD_BASE + 0x60000U)
|
|
|
|
/* Generic Interrupt Controller Distributor (GICD) */
|
|
#define GICD_CTLR *((volatile uint32_t *)(GICD_BASE + 0x000U))
|
|
#define GICD_IGROUPR(n) *((volatile uint32_t *)(GICD_BASE + 0x080U + 4U*(n)))
|
|
#define GICD_ISENABLER(n) *((volatile uint32_t *)(GICD_BASE + 0x100U + 4U*(n)))
|
|
#define GICD_ICENABLER(n) *((volatile uint32_t *)(GICD_BASE + 0x180U + 4U*(n)))
|
|
#define GICD_ISPENDR(n) *((volatile uint32_t *)(GICD_BASE + 0x200U + 4U*(n)))
|
|
#define GICD_ICPENDR(n) *((volatile uint32_t *)(GICD_BASE + 0x280U + 4U*(n)))
|
|
#define GICD_IPRIORITYR(n) *((volatile uint32_t *)(GICD_BASE + 0x400U + 4U*(n)))
|
|
#define GICD_ICFGR(n) *((volatile uint32_t *)(GICD_BASE + 0xC00U + 4U*(n)))
|
|
#define GICD_IGRPMODR(n) *((volatile uint32_t *)(GICD_BASE + 0xD00U + 4U*(n)))
|
|
#define GICD_IROUTER(n) *((volatile uint64_t *)(GICD_BASE + 0x6000U + 8U*(n)))
|
|
|
|
/* Generic Interrupt Controller Redistributor (GICR) */
|
|
#define GICR_CTLR *((volatile uint32_t *)(GICR_BASE + 0x0000U))
|
|
#define GICR_WAKER *((volatile uint32_t *)(GICR_BASE + 0x0014U))
|
|
#define GICR_PWRR *((volatile uint32_t *)(GICR_BASE + 0x0024U))
|
|
|
|
#define CHILDREN_ASLEEP (1U << 2U)
|
|
#define PROCESSOR_SLEEP (1U << 1U)
|
|
#define RDPOWER_DOWN (1U << 0U)
|
|
|
|
/*******************************************************************************
|
|
** Global Data Types **
|
|
*******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
** Function Prototypes **
|
|
*******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
** Macro **
|
|
*******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Definitions for CPU system register interface to GICv3
|
|
******************************************************************************/
|
|
/* ICC_SRE_EL3 */
|
|
#define ICC_SRE_EN_BIT (8U)
|
|
#define ICC_SRE_DIB_BIT (4U)
|
|
#define ICC_SRE_DFB_BIT (2U)
|
|
#define ICC_SRE_SRE_BIT (1U)
|
|
|
|
/* SCR_EL3 */
|
|
#define SCR_NS_BIT (1U)
|
|
|
|
/* Affinity Leve mask value */
|
|
#define AFFINITY0_MASK (0xFFU)
|
|
#define AFFINITY1_MASK (0xFF00U)
|
|
#define AFFINITY2_MASK (0xFF0000U)
|
|
#define AFFINITY3_MASK (0xFF00000000U)
|
|
#define IRM_OFF (0x80000000U)
|
|
|
|
/* Get ICC_IAR0 */
|
|
static inline uint64_t get_ICC_IAR0(void)
|
|
{
|
|
uint64_t value = 0U;
|
|
__asm__ volatile("mrs %0, S3_0_c12_c8_0" : "=r" (value));
|
|
return value;
|
|
}
|
|
|
|
/* Set ICC_PMR */
|
|
static inline void set_ICC_PMR(uint64_t value)
|
|
{
|
|
__asm__ volatile ("msr S3_0_C4_C6_0, %0" :: "r" (value));
|
|
}
|
|
|
|
/* Set ICC_IGRPEN0 */
|
|
static inline void set_ICC_IGRPEN0(uint64_t value)
|
|
{
|
|
__asm__ volatile ("msr S3_0_c12_c12_6, %0" :: "r" (value));
|
|
}
|
|
|
|
/* Set ICC_SRE_EL1 */
|
|
static inline void set_ICC_SRE_EL1(uint64_t value)
|
|
{
|
|
__asm__ volatile ("msr S3_0_C12_C12_5, %0" :: "r" (value));
|
|
}
|
|
|
|
/* Get ICC_SRE_EL3 */
|
|
static inline uint64_t get_ICC_SRE_EL3(void)
|
|
{
|
|
uint64_t value = 0U;
|
|
__asm__ volatile("mrs %0, S3_6_C12_C12_5" : "=r" (value));
|
|
return value;
|
|
}
|
|
|
|
/* Set ICC_SRE_EL3 */
|
|
static inline void set_ICC_SRE_EL3(uint64_t value)
|
|
{
|
|
__asm__ volatile ("msr S3_6_C12_C12_5, %0" :: "r" (value));
|
|
}
|
|
|
|
/* Get MPIDR_EL1 */
|
|
static inline uint64_t get_MPIDR_EL1(void)
|
|
{
|
|
uint64_t value = 0U;
|
|
__asm__ volatile("mrs %0, mpidr_el1" : "=r" (value));
|
|
return value;
|
|
}
|
|
|
|
/* ISB */
|
|
static inline void GIC_isb(void)
|
|
{
|
|
__asm__ volatile ("isb");
|
|
}
|
|
|
|
/* Enable the interrupt distributor using the GIC's CTLR register */
|
|
static inline void GIC_EnableDistributor(void)
|
|
{
|
|
GICD_CTLR |= 0x31U;
|
|
}
|
|
|
|
/* Disable the interrupt distributor using the GIC's CTLR register */
|
|
static inline void GIC_DisableDistributor(void)
|
|
{
|
|
GICD_CTLR &= 0xFFFFFFFEU;
|
|
}
|
|
|
|
/* Set the interrupt enable from the GIC's ISENABLER register */
|
|
static inline void GIC_SetEnable(uint32_t intid, uint32_t value)
|
|
{
|
|
uint32_t reg = GICD_ISENABLER(intid / 32U);
|
|
uint32_t shift = (intid % 32U);
|
|
|
|
reg &= (~(1U << shift));
|
|
reg |= ( (value & 1U) << shift);
|
|
|
|
GICD_ISENABLER(intid / 32U) = reg;
|
|
}
|
|
|
|
/* Set the interrupt disable from the GIC's ICENABLER register */
|
|
static inline void GIC_SetClearEnable(uint32_t intid, uint32_t value)
|
|
{
|
|
uint32_t reg = GICD_ICENABLER(intid / 32U);
|
|
uint32_t shift = (intid % 32U);
|
|
|
|
reg &= (~(1U << shift));
|
|
reg |= ( (value & 1U) << shift);
|
|
|
|
GICD_ICENABLER(intid / 32U) = reg;
|
|
}
|
|
|
|
/* Sets the interrupt configuration using GIC's ICFGR register */
|
|
static inline void GIC_SetConfiguration(uint32_t intid, uint32_t int_config)
|
|
{
|
|
uint32_t icfgr = GICD_ICFGR(intid / 16U);
|
|
uint32_t shift = (intid % 16U) << 1U;
|
|
|
|
icfgr &= (~(3U << shift));
|
|
icfgr |= ( int_config << shift);
|
|
|
|
GICD_ICFGR(intid / 16U) = icfgr;
|
|
}
|
|
|
|
/* Set the priority for the given interrupt in the GIC's IPRIORITYR register */
|
|
static inline void GIC_SetPriority(uint32_t intid, uint32_t priority)
|
|
{
|
|
uint32_t mask = GICD_IPRIORITYR(intid / 4U);
|
|
uint32_t shift = ((intid % 4U) * 8U);
|
|
|
|
mask &= (~(0xFFU << shift));
|
|
mask |= ( (priority & 0xFFU) << shift);
|
|
|
|
GICD_IPRIORITYR(intid / 4U) = mask;
|
|
}
|
|
|
|
/* Set the interrupt group from the GIC's IGROUPR register */
|
|
static inline void GIC_SetGroup(uint32_t intid, uint32_t group)
|
|
{
|
|
uint32_t igroupr = GICD_IGROUPR(intid / 32U);
|
|
uint32_t shift = (intid % 32U);
|
|
|
|
igroupr &= (~(1U << shift));
|
|
igroupr |= ( (group & 1U) << shift);
|
|
|
|
GICD_IGROUPR(intid / 32U) = igroupr;
|
|
}
|
|
|
|
/* Set the interrupt group from the GIC's IGRPMODR register */
|
|
static inline void GIC_SetGrpMode(uint32_t intid, uint32_t mode)
|
|
{
|
|
uint32_t imode = GICD_IGRPMODR(intid / 32U);
|
|
uint32_t shift = (intid % 32U);
|
|
|
|
imode &= (~(1U << shift));
|
|
imode |= ( (mode & 1U) << shift);
|
|
|
|
GICD_IGRPMODR(intid / 32U) = imode;
|
|
}
|
|
|
|
/* Set the interrupt routing from the GIC's IROUTER register */
|
|
static inline void GIC_SetRouter(uint32_t intid)
|
|
{
|
|
uint64_t affinity = 0U;
|
|
|
|
/* Get Affinity level */
|
|
affinity = get_MPIDR_EL1();
|
|
affinity &= (AFFINITY0_MASK | AFFINITY1_MASK | AFFINITY2_MASK | AFFINITY3_MASK);
|
|
/* Interrupt routing mode bit OFF */
|
|
affinity &= (~(IRM_OFF));
|
|
|
|
GICD_IROUTER(intid) = affinity;
|
|
}
|
|
|
|
/* Get power register value from the GIC's GICR_PWRR register */
|
|
static inline uint32_t GIC_Getpwwr(void)
|
|
{
|
|
return (GICR_PWRR);
|
|
}
|
|
|
|
/* Set power register value from the GIC's GICR_PWRR register */
|
|
static inline void GIC_Setpwwr(uint32_t set_value)
|
|
{
|
|
GICR_PWRR = set_value;
|
|
}
|
|
|
|
/* Get power management cotrol register from the GIC's GICR_WAKER register */
|
|
static inline uint32_t GIC_Getwaker(void)
|
|
{
|
|
return (GICR_WAKER);
|
|
}
|
|
|
|
/* Set power management cotrol register from the GIC's GICR_WAKER register */
|
|
static inline void GIC_Setwaker(uint32_t set_value)
|
|
{
|
|
GICR_WAKER = set_value;
|
|
}
|
|
|
|
/* Enables the given interrupt using GIC's ISENABLER register */
|
|
static inline void GIC_EnableFIQ(uint32_t intid)
|
|
{
|
|
|
|
/* Disable interrupt forwarding */
|
|
GIC_DisableDistributor();
|
|
|
|
/* Set level-sensitive */
|
|
GIC_SetConfiguration(intid, 0U);
|
|
|
|
/* Set priority */
|
|
GIC_SetPriority(intid, 0U);
|
|
|
|
/* Set group 0 (secure) */
|
|
GIC_SetGroup(intid, 0U);
|
|
|
|
/* Set group 0 (secure) */
|
|
GIC_SetGrpMode(intid, 0U);
|
|
|
|
/* Enable distributor */
|
|
GIC_EnableDistributor();
|
|
|
|
/* Enable the SPI interrupt */
|
|
GIC_SetEnable(intid, 1U);
|
|
|
|
/* Set the interrupt routing */
|
|
GIC_SetRouter(intid);
|
|
}
|
|
|
|
/* Enable the interrupt redistributor wakeup */
|
|
static inline void GIC_WakeupRedistributor(void)
|
|
{
|
|
uint32_t get_value = 0U;
|
|
uint32_t set_value = 0U;
|
|
|
|
get_value = GIC_Getpwwr();
|
|
set_value = get_value & ~(RDPOWER_DOWN);
|
|
GIC_Setpwwr(set_value);
|
|
|
|
get_value = GIC_Getwaker();
|
|
set_value = get_value & ~(PROCESSOR_SLEEP);
|
|
GIC_Setwaker(set_value);
|
|
|
|
do
|
|
{
|
|
get_value = GIC_Getwaker();
|
|
}while((get_value & CHILDREN_ASLEEP) == CHILDREN_ASLEEP);
|
|
}
|
|
|
|
/* Enable the CPU's interrupt interface */
|
|
static inline void GIC_EnableInterface(void)
|
|
{
|
|
uint64_t reg = 0U;
|
|
uint64_t icc_sre_el3 = 0U;
|
|
|
|
/* Disable the legacy interrupt bypass */
|
|
icc_sre_el3 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT | ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT;
|
|
|
|
reg = get_ICC_SRE_EL3();
|
|
set_ICC_SRE_EL3(reg | icc_sre_el3);
|
|
|
|
set_ICC_SRE_EL1(ICC_SRE_SRE_BIT);
|
|
GIC_isb();
|
|
|
|
set_ICC_IGRPEN0(1U); /* enable interface grp0 */
|
|
GIC_isb();
|
|
}
|
|
|
|
/* Disable the CPU's interrupt interface */
|
|
static inline void GIC_DisableInterface(uint32_t intid)
|
|
{
|
|
uint32_t get_value = 0U;
|
|
uint32_t set_value = 0U;
|
|
|
|
/* Clear Enable the SPI interrupt */
|
|
GIC_SetClearEnable(intid, 1U);
|
|
|
|
/* Set ChildrenAsleep of GICR_WAKER to 1 and end processing */
|
|
get_value = GIC_Getwaker();
|
|
set_value = get_value | PROCESSOR_SLEEP;
|
|
GIC_Setwaker(set_value);
|
|
|
|
do
|
|
{
|
|
get_value = GIC_Getwaker();
|
|
}while((get_value & CHILDREN_ASLEEP) != CHILDREN_ASLEEP);
|
|
|
|
}
|
|
|
|
/* Read the CPU's IAR register */
|
|
static inline uint32_t GIC_AcknowledgePending(void)
|
|
{
|
|
return (uint32_t)(get_ICC_IAR0());
|
|
}
|
|
|
|
/* Set the interrupt priority mask using CPU's PMR register */
|
|
static inline void GIC_SetInterfacePriorityMask(uint64_t priority)
|
|
{
|
|
/* Specify F8. 32 priority levels are bit0-2 invalid */
|
|
set_ICC_PMR(priority << 3U);
|
|
}
|
|
|
|
/* Initialize and enable the GIC */
|
|
static inline void GIC_Enable(void)
|
|
{
|
|
GIC_WakeupRedistributor();
|
|
/* Enable interface */
|
|
GIC_EnableInterface();
|
|
/* Set priority mask */
|
|
GIC_SetInterfacePriorityMask(0xFFUL);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Function **
|
|
*******************************************************************************/
|
|
/* Interrupt configuration */
|
|
#define Interrupt_Config(void) GIC_Enable(void)
|
|
|
|
/* Enable */
|
|
#define Interrupt_Enable(intid) GIC_EnableFIQ((uint32_t)intid)
|
|
|
|
/* Disable */
|
|
#define Interrupt_Disable(intid) GIC_DisableInterface((uint32_t)intid)
|
|
|
|
#endif /* GIC_H */
|
|
/*******************************************************************************
|
|
** End of File **
|
|
*******************************************************************************/
|