]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/scugic_v3_9/src/xscugic.c
Update Zynq, MPSoc Cortex-A53 and MPSoc Cortex-R5 demo projects to build with the...
[freertos] / FreeRTOS / Demo / CORTEX_A9_Zynq_ZC702 / RTOSDemo_bsp / ps7_cortexa9_0 / libsrc / scugic_v3_9 / src / xscugic.c
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/scugic_v3_9/src/xscugic.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/scugic_v3_9/src/xscugic.c
new file mode 100644 (file)
index 0000000..f6afc0e
--- /dev/null
@@ -0,0 +1,1020 @@
+/******************************************************************************
+*
+* Copyright (C) 2010 - 2018 Xilinx, Inc.  All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* Use of the Software is limited solely to applications:
+* (a) running on a Xilinx device, or
+* (b) that interact with a Xilinx device through a bus or interconnect.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*
+* Except as contained in this notice, the name of the Xilinx shall not be used
+* in advertising or otherwise to promote the sale, use or other dealings in
+* this Software without prior written authorization from Xilinx.
+*
+******************************************************************************/
+/*****************************************************************************/
+/**
+*
+* @file xscugic.c
+* @addtogroup scugic_v3_8
+* @{
+*
+* Contains required functions for the XScuGic driver for the Interrupt
+* Controller. See xscugic.h for a detailed description of the driver.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- --------------------------------------------------------
+* 1.00a drg  01/19/10 First release
+* 1.01a sdm  11/09/11 Changes are made in function XScuGic_CfgInitialize. Since
+*                                "Config" entry is now made as pointer in the XScuGic
+*                                structure, necessary changes are made.
+*                                The HandlerTable can now be populated through the low
+*                                level routine XScuGic_RegisterHandler added in this
+*                                release. Hence necessary checks are added not to
+*                                overwrite the HandlerTable entriesin function
+*                                XScuGic_CfgInitialize.
+* 1.03a srt  02/27/13 Added APIs
+*                                        - XScuGic_SetPriTrigTypeByDistAddr()
+*                                        - XScuGic_GetPriTrigTypeByDistAddr()
+*                                Removed Offset calculation macros, defined in _hw.h
+*                                (CR 702687)
+*                                        Added support to direct interrupts to the appropriate CPU. Earlier
+*                                        interrupts were directed to CPU1 (hard coded). Now depending
+*                                        upon the CPU selected by the user (xparameters.h), interrupts
+*                                        will be directed to the relevant CPU. This fixes CR 699688.
+*
+* 1.04a hk   05/04/13 Assigned EffectiveAddr to CpuBaseAddress in
+*                                        XScuGic_CfgInitialize. Fix for CR#704400 to remove warnings.
+*                                        Moved functions XScuGic_SetPriTrigTypeByDistAddr and
+*                        XScuGic_GetPriTrigTypeByDistAddr to xscugic_hw.c.
+*                                        This is fix for CR#705621.
+* 1.06a asa  16/11/13 Fix for CR#749178. Assignment for EffectiveAddr
+*                                        in function XScuGic_CfgInitialize is removed as it was
+*                                a bug.
+* 3.00  kvn  02/13/14 Modified code for MISRA-C:2012 compliance.
+* 3.01 pkp      06/19/15 Added XScuGic_InterruptMaptoCpu API for an interrupt
+*                                        target CPU mapping
+* 3.02 pkp      11/09/15 Modified DistributorInit function for AMP case to add
+*                                        the current cpu to interrupt processor targets registers
+* 3.2   asa  02/29/16 Modified DistributorInit function for Zynq AMP case. The
+*                                        distributor is left uninitialized for Zynq AMP. It is assumed
+*                        that the distributor will be initialized by Linux master. However
+*                        for CortexR5 case, the earlier code is left unchanged where the
+*                        the interrupt processor target registers in the distributor is
+*                        initialized with the corresponding CPU ID on which the application
+*                        built over the scugic driver runs.
+*                        These changes fix CR#937243.
+* 3.3  pkp  05/12/16 Modified XScuGic_InterruptMaptoCpu to write proper value
+*                                        to interrupt target register to fix CR#951848
+*
+* 3.4   asa  04/07/16 Created a new static function DoDistributorInit to simplify
+*                     the flow and avoid code duplication. Changes are made for
+*                     USE_AMP use case for R5. In a scenario (in R5 split mode) when
+*                     one R5 is operating with A53 in open amp config and other
+*                     R5 running baremetal app, the existing code
+*                     had the potential to stop the whole AMP solution to work (if
+*                     for some reason the R5 running the baremetal app tasked to
+*                     initialize the Distributor hangs or crashes before initializing).
+*                     Changes are made so that the R5 under AMP first checks if
+*                     the distributor is enabled or not and if not, it does the
+*                     standard Distributor initialization.
+*                     This fixes the CR#952962.
+* 3.4   mus  09/08/16 Added assert to avoid invalid access of GIC from CPUID 1
+*                     for single core zynq-7000s
+* 3.5   mus  10/05/16 Modified DistributorInit function to avoid re-initialization of
+*                     distributor,If it is already initialized by other CPU.
+* 3.5  pkp      10/17/16 Modified XScuGic_InterruptMaptoCpu to correct the CPU Id value
+*                                        and properly mask interrupt target processor value to modify
+*                                        interrupt target processor register for a given interrupt ID
+*                                        and cpu ID
+* 3.6  pkp      20/01/17 Added new API XScuGic_Stop to Disable distributor and
+*                                        interrupts in case they are being used only by current cpu.
+*                                        It also removes current cpu from interrupt target registers
+*                                        for all interrupts.
+*       kvn  02/17/17 Add support for changing GIC CPU master at run time.
+*       kvn  02/28/17 Make the CpuId as static variable and Added new
+*                     XScugiC_GetCpuId to access CpuId.
+* 3.9   mus  02/21/18 Added new API's XScuGic_UnmapAllInterruptsFromCpu and
+*                     XScuGic_InterruptUnmapFromCpu, These API's can be used
+*                     by applications to unmap specific/all interrupts from
+*                     target CPU. It fixes CR#992490.
+*
+* </pre>
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+#include "xil_types.h"
+#include "xil_assert.h"
+#include "xscugic.h"
+
+/************************** Constant Definitions *****************************/
+
+
+/**************************** Type Definitions *******************************/
+
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Variable Definitions *****************************/
+static u32 CpuId = XPAR_CPU_ID; /**< CPU Core identifier */
+
+/************************** Function Prototypes ******************************/
+
+static void StubHandler(void *CallBackRef);
+
+/*****************************************************************************/
+/**
+*
+* DoDistributorInit initializes the distributor of the GIC. The
+* initialization entails:
+*
+* - Write the trigger mode, priority and target CPU
+* - All interrupt sources are disabled
+* - Enable the distributor
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+* @param       CpuID is the Cpu ID to be initialized.
+*
+* @return      None
+*
+* @note                None.
+*
+******************************************************************************/
+static void DoDistributorInit(XScuGic *InstancePtr, u32 CpuID)
+{
+       u32 Int_Id;
+       u32 LocalCpuID = CpuID;
+
+       XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U);
+
+       /*
+        * Set the security domains in the int_security registers for
+        * non-secure interrupts
+        * All are secure, so leave at the default. Set to 1 for non-secure
+        * interrupts.
+        */
+
+       /*
+        * For the Shared Peripheral Interrupts INT_ID[MAX..32], set:
+        */
+
+       /*
+        * 1. The trigger mode in the int_config register
+        * Only write to the SPI interrupts, so start at 32
+        */
+       for (Int_Id = 32U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+16U) {
+               /*
+                * Each INT_ID uses two bits, or 16 INT_ID per register
+                * Set them all to be level sensitive, active HIGH.
+                */
+               XScuGic_DistWriteReg(InstancePtr,
+                                       XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
+                                       0U);
+       }
+
+
+#define DEFAULT_PRIORITY    0xa0a0a0a0U
+       for (Int_Id = 0U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+4U) {
+               /*
+                * 2. The priority using int the priority_level register
+                * The priority_level and spi_target registers use one byte per
+                * INT_ID.
+                * Write a default value that can be changed elsewhere.
+                */
+               XScuGic_DistWriteReg(InstancePtr,
+                                       XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
+                                       DEFAULT_PRIORITY);
+       }
+
+       for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
+               /*
+                * 3. The CPU interface in the spi_target register
+                * Only write to the SPI interrupts, so start at 32
+                */
+               LocalCpuID |= LocalCpuID << 8U;
+               LocalCpuID |= LocalCpuID << 16U;
+
+               XScuGic_DistWriteReg(InstancePtr,
+                                        XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
+                                        LocalCpuID);
+       }
+
+       for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) {
+               /*
+                * 4. Enable the SPI using the enable_set register. Leave all
+                * disabled for now.
+                */
+               XScuGic_DistWriteReg(InstancePtr,
+               XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET, Int_Id),
+                       0xFFFFFFFFU);
+
+       }
+
+       XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET,
+                                       XSCUGIC_EN_INT_MASK);
+}
+
+/*****************************************************************************/
+/**
+*
+* DistributorInit initializes the distributor of the GIC. It calls
+* DoDistributorInit to finish the initialization.
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+* @param       CpuID is the Cpu ID to be initialized.
+*
+* @return      None
+*
+* @note                None.
+*
+******************************************************************************/
+static void DistributorInit(XScuGic *InstancePtr, u32 CpuID)
+{
+       u32 Int_Id;
+       u32 LocalCpuID = CpuID;
+       u32 RegValue;
+
+#if USE_AMP==1 && (defined (ARMA9) || defined(__aarch64__))
+#warning "Building GIC for AMP"
+       /*
+        * GIC initialization is taken care by master CPU in
+        * openamp configuration, so do nothing and return.
+        */
+       return;
+#endif
+
+       RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET);
+       if ((RegValue & XSCUGIC_EN_INT_MASK) == 0U) {
+               Xil_AssertVoid(InstancePtr != NULL);
+               DoDistributorInit(InstancePtr, CpuID);
+               return;
+       }
+
+       /*
+        * The overall distributor should not be initialized in AMP case where
+        * another CPU is taking care of it.
+        */
+       LocalCpuID |= LocalCpuID << 8U;
+       LocalCpuID |= LocalCpuID << 16U;
+       for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
+               RegValue = XScuGic_DistReadReg(InstancePtr,
+                                               XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
+               RegValue |= LocalCpuID;
+               XScuGic_DistWriteReg(InstancePtr,
+                                    XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
+                                    RegValue);
+       }
+}
+
+/*****************************************************************************/
+/**
+*
+* CPUInitialize initializes the CPU Interface of the GIC. The initialization entails:
+*
+*      - Set the priority of the CPU
+*      - Enable the CPU interface
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+*
+* @return      None
+*
+* @note                None.
+*
+******************************************************************************/
+static void CPUInitialize(XScuGic *InstancePtr)
+{
+       /*
+        * Program the priority mask of the CPU using the Priority mask register
+        */
+       XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CPU_PRIOR_OFFSET, 0xF0U);
+
+
+       /*
+        * If the CPU operates in both security domains, set parameters in the
+        * control_s register.
+        * 1. Set FIQen=1 to use FIQ for secure interrupts,
+        * 2. Program the AckCtl bit
+        * 3. Program the SBPR bit to select the binary pointer behavior
+        * 4. Set EnableS = 1 to enable secure interrupts
+        * 5. Set EnbleNS = 1 to enable non secure interrupts
+        */
+
+       /*
+        * If the CPU operates only in the secure domain, setup the
+        * control_s register.
+        * 1. Set FIQen=1,
+        * 2. Set EnableS=1, to enable the CPU interface to signal secure interrupts.
+        * Only enable the IRQ output unless secure interrupts are needed.
+        */
+       XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CONTROL_OFFSET, 0x07U);
+
+}
+
+/*****************************************************************************/
+/**
+*
+* CfgInitialize a specific interrupt controller instance/driver. The
+* initialization entails:
+*
+* - Initialize fields of the XScuGic structure
+* - Initial vector table with stub function calls
+* - All interrupt sources are disabled
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+* @param       ConfigPtr is a pointer to a config table for the particular
+*              device this driver is associated with.
+* @param       EffectiveAddr is the device base address in the virtual memory
+*              address space. The caller is responsible for keeping the address
+*              mapping from EffectiveAddr to the device physical base address
+*              unchanged once this function is invoked. Unexpected errors may
+*              occur if the address mapping changes after this function is
+*              called. If address translation is not used, use
+*              Config->BaseAddress for this parameters, passing the physical
+*              address instead.
+*
+* @return
+*              - XST_SUCCESS if initialization was successful
+*
+* @note                None.
+*
+******************************************************************************/
+s32  XScuGic_CfgInitialize(XScuGic *InstancePtr,
+                               XScuGic_Config *ConfigPtr,
+                               u32 EffectiveAddr)
+{
+       u32 Int_Id;
+       u32 Cpu_Id = CpuId + (u32)1;
+       (void) EffectiveAddr;
+
+       Xil_AssertNonvoid(InstancePtr != NULL);
+       Xil_AssertNonvoid(ConfigPtr != NULL);
+       /*
+     * Detect Zynq-7000 base silicon configuration,Dual or Single CPU.
+     * If it is single CPU cnfiguration then invoke assert for CPU ID=1
+        */
+#ifdef ARMA9
+       if ( XPAR_CPU_ID == 0x01 )
+       {
+               Xil_AssertNonvoid((Xil_In32(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)
+                & EFUSE_STATUS_CPU_MASK ) == 0);
+       }
+#endif
+
+       if(InstancePtr->IsReady != XIL_COMPONENT_IS_READY) {
+
+               InstancePtr->IsReady = 0U;
+               InstancePtr->Config = ConfigPtr;
+
+
+               for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id++) {
+                       /*
+                       * Initalize the handler to point to a stub to handle an
+                       * interrupt which has not been connected to a handler. Only
+                       * initialize it if the handler is 0 which means it was not
+                       * initialized statically by the tools/user. Set the callback
+                       * reference to this instance so that unhandled interrupts
+                       * can be tracked.
+                       */
+                       if      ((InstancePtr->Config->HandlerTable[Int_Id].Handler == NULL)) {
+                               InstancePtr->Config->HandlerTable[Int_Id].Handler =
+                                                                       StubHandler;
+                       }
+                       InstancePtr->Config->HandlerTable[Int_Id].CallBackRef =
+                                                               InstancePtr;
+               }
+               XScuGic_Stop(InstancePtr);
+               DistributorInit(InstancePtr, Cpu_Id);
+               CPUInitialize(InstancePtr);
+
+               InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
+       }
+
+       return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* Makes the connection between the Int_Id of the interrupt source and the
+* associated handler that is to run when the interrupt is recognized. The
+* argument provided in this call as the Callbackref is used as the argument
+* for the handler when it is called.
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+* @param       Int_Id contains the ID of the interrupt source and should be
+*              in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
+* @param       Handler to the handler for that interrupt.
+* @param       CallBackRef is the callback reference, usually the instance
+*              pointer of the connecting driver.
+*
+* @return
+*
+*              - XST_SUCCESS if the handler was connected correctly.
+*
+* @note
+*
+* WARNING: The handler provided as an argument will overwrite any handler
+* that was previously connected.
+*
+****************************************************************************/
+s32  XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
+                      Xil_InterruptHandler Handler, void *CallBackRef)
+{
+       /*
+        * Assert the arguments
+        */
+       Xil_AssertNonvoid(InstancePtr != NULL);
+       Xil_AssertNonvoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
+       Xil_AssertNonvoid(Handler != NULL);
+       Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+       /*
+        * The Int_Id is used as an index into the table to select the proper
+        * handler
+        */
+       InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler;
+       InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;
+
+       return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* Updates the interrupt table with the Null Handler and NULL arguments at the
+* location pointed at by the Int_Id. This effectively disconnects that interrupt
+* source from any handler. The interrupt is disabled also.
+*
+* @param       InstancePtr is a pointer to the XScuGic instance to be worked on.
+* @param       Int_Id contains the ID of the interrupt source and should
+*              be in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
+*
+* @return      None.
+*
+* @note                None.
+*
+****************************************************************************/
+void XScuGic_Disconnect(XScuGic *InstancePtr, u32 Int_Id)
+{
+       u32 Mask;
+
+       /*
+        * Assert the arguments
+        */
+       Xil_AssertVoid(InstancePtr != NULL);
+       Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
+       Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+       /*
+        * The Int_Id is used to create the appropriate mask for the
+        * desired bit position. Int_Id currently limited to 0 - 31
+        */
+       Mask = 0x00000001U << (Int_Id % 32U);
+
+       /*
+        * Disable the interrupt such that it won't occur while disconnecting
+        * the handler, only disable the specified interrupt id without modifying
+        * the other interrupt ids
+        */
+       XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
+                                               ((Int_Id / 32U) * 4U), Mask);
+
+       /*
+        * Disconnect the handler and connect a stub, the callback reference
+        * must be set to this instance to allow unhandled interrupts to be
+        * tracked
+        */
+       InstancePtr->Config->HandlerTable[Int_Id].Handler = StubHandler;
+       InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = InstancePtr;
+}
+
+/*****************************************************************************/
+/**
+*
+* Enables the interrupt source provided as the argument Int_Id. Any pending
+* interrupt condition for the specified Int_Id will occur after this function is
+* called.
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+* @param       Int_Id contains the ID of the interrupt source and should be
+*              in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
+*
+* @return      None.
+*
+* @note                None.
+*
+****************************************************************************/
+void XScuGic_Enable(XScuGic *InstancePtr, u32 Int_Id)
+{
+       u32 Mask;
+
+       /*
+        * Assert the arguments
+        */
+       Xil_AssertVoid(InstancePtr != NULL);
+       Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
+       Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+       /*
+        * The Int_Id is used to create the appropriate mask for the
+        * desired bit position. Int_Id currently limited to 0 - 31
+        */
+       Mask = 0x00000001U << (Int_Id % 32U);
+
+       /*
+        * Enable the selected interrupt source by setting the
+        * corresponding bit in the Enable Set register.
+        */
+       XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_ENABLE_SET_OFFSET +
+                                               ((Int_Id / 32U) * 4U), Mask);
+}
+
+/*****************************************************************************/
+/**
+*
+* Disables the interrupt source provided as the argument Int_Id such that the
+* interrupt controller will not cause interrupts for the specified Int_Id. The
+* interrupt controller will continue to hold an interrupt condition for the
+* Int_Id, but will not cause an interrupt.
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+* @param       Int_Id contains the ID of the interrupt source and should be
+*              in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
+*
+* @return      None.
+*
+* @note                None.
+*
+****************************************************************************/
+void XScuGic_Disable(XScuGic *InstancePtr, u32 Int_Id)
+{
+       u32 Mask;
+
+       /*
+        * Assert the arguments
+        */
+       Xil_AssertVoid(InstancePtr != NULL);
+       Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
+       Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+       /*
+        * The Int_Id is used to create the appropriate mask for the
+        * desired bit position. Int_Id currently limited to 0 - 31
+        */
+       Mask = 0x00000001U << (Int_Id % 32U);
+
+       /*
+        * Disable the selected interrupt source by setting the
+        * corresponding bit in the IDR.
+        */
+       XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
+                                               ((Int_Id / 32U) * 4U), Mask);
+}
+
+/*****************************************************************************/
+/**
+*
+* Allows software to simulate an interrupt in the interrupt controller.  This
+* function will only be successful when the interrupt controller has been
+* started in simulation mode.  A simulated interrupt allows the interrupt
+* controller to be tested without any device to drive an interrupt input
+* signal into it.
+*
+* @param       InstancePtr is a pointer to the XScuGic instance.
+* @param       Int_Id is the software interrupt ID to simulate an interrupt.
+* @param       Cpu_Id is the list of CPUs to send the interrupt.
+*
+* @return
+*
+* XST_SUCCESS if successful, or XST_FAILURE if the interrupt could not be
+* simulated
+*
+* @note                None.
+*
+******************************************************************************/
+s32  XScuGic_SoftwareIntr(XScuGic *InstancePtr, u32 Int_Id, u32 Cpu_Id)
+{
+       u32 Mask;
+
+       /*
+        * Assert the arguments
+        */
+       Xil_AssertNonvoid(InstancePtr != NULL);
+       Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+       Xil_AssertNonvoid(Int_Id <= 15U) ;
+       Xil_AssertNonvoid(Cpu_Id <= 255U) ;
+
+
+       /*
+        * The Int_Id is used to create the appropriate mask for the
+        * desired interrupt. Int_Id currently limited to 0 - 15
+        * Use the target list for the Cpu ID.
+        */
+       Mask = ((Cpu_Id << 16U) | Int_Id) &
+               (XSCUGIC_SFI_TRIG_CPU_MASK | XSCUGIC_SFI_TRIG_INTID_MASK);
+
+       /*
+        * Write to the Software interrupt trigger register. Use the appropriate
+        * CPU Int_Id.
+        */
+       XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SFI_TRIG_OFFSET, Mask);
+
+       /* Indicate the interrupt was successfully simulated */
+
+       return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+*
+* A stub for the asynchronous callback. The stub is here in case the upper
+* layers forget to set the handler.
+*
+* @param       CallBackRef is a pointer to the upper layer callback reference
+*
+* @return      None.
+*
+* @note                None.
+*
+******************************************************************************/
+static void StubHandler(void *CallBackRef) {
+       /*
+        * verify that the inputs are valid
+        */
+       Xil_AssertVoid(CallBackRef != NULL);
+
+       /*
+        * Indicate another unhandled interrupt for stats
+        */
+       ((XScuGic *)((void *)CallBackRef))->UnhandledInterrupts++;
+}
+
+/****************************************************************************/
+/**
+* Sets the interrupt priority and trigger type for the specificd IRQ source.
+*
+* @param       InstancePtr is a pointer to the instance to be worked on.
+* @param       Int_Id is the IRQ source number to modify
+* @param       Priority is the new priority for the IRQ source. 0 is highest
+*                      priority, 0xF8 (248) is lowest. There are 32 priority levels
+*                      supported with a step of 8. Hence the supported priorities are
+*                      0, 8, 16, 32, 40 ..., 248.
+* @param       Trigger is the new trigger type for the IRQ source.
+* Each bit pair describes the configuration for an INT_ID.
+* SFI    Read Only    b10 always
+* PPI    Read Only    depending on how the PPIs are configured.
+*                    b01    Active HIGH level sensitive
+*                    b11 Rising edge sensitive
+* SPI                LSB is read only.
+*                    b01    Active HIGH level sensitive
+*                    b11 Rising edge sensitive/
+*
+* @return      None.
+*
+* @note                None.
+*
+*****************************************************************************/
+void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
+                                       u8 Priority, u8 Trigger)
+{
+       u32 RegValue;
+       u8 LocalPriority;
+       LocalPriority = Priority;
+
+       Xil_AssertVoid(InstancePtr != NULL);
+       Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+       Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
+       Xil_AssertVoid(Trigger <= (u8)XSCUGIC_INT_CFG_MASK);
+       Xil_AssertVoid(LocalPriority <= (u8)XSCUGIC_MAX_INTR_PRIO_VAL);
+
+       /*
+        * Determine the register to write to using the Int_Id.
+        */
+       RegValue = XScuGic_DistReadReg(InstancePtr,
+                       XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
+
+       /*
+        * The priority bits are Bits 7 to 3 in GIC Priority Register. This
+        * means the number of priority levels supported are 32 and they are
+        * in steps of 8. The priorities can be 0, 8, 16, 32, 48, ... etc.
+        * The lower order 3 bits are masked before putting it in the register.
+        */
+       LocalPriority = LocalPriority & (u8)XSCUGIC_INTR_PRIO_MASK;
+       /*
+        * Shift and Mask the correct bits for the priority and trigger in the
+        * register
+        */
+       RegValue &= ~(XSCUGIC_PRIORITY_MASK << ((Int_Id%4U)*8U));
+       RegValue |= (u32)LocalPriority << ((Int_Id%4U)*8U);
+
+       /*
+        * Write the value back to the register.
+        */
+       XScuGic_DistWriteReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
+                               RegValue);
+
+       /*
+        * Determine the register to write to using the Int_Id.
+        */
+       RegValue = XScuGic_DistReadReg(InstancePtr,
+                       XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
+
+       /*
+        * Shift and Mask the correct bits for the priority and trigger in the
+        * register
+        */
+       RegValue &= ~(XSCUGIC_INT_CFG_MASK << ((Int_Id%16U)*2U));
+       RegValue |= (u32)Trigger << ((Int_Id%16U)*2U);
+
+       /*
+        * Write the value back to the register.
+        */
+       XScuGic_DistWriteReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
+                               RegValue);
+
+}
+
+/****************************************************************************/
+/**
+* Gets the interrupt priority and trigger type for the specificd IRQ source.
+*
+* @param       InstancePtr is a pointer to the instance to be worked on.
+* @param       Int_Id is the IRQ source number to modify
+* @param       Priority is a pointer to the value of the priority of the IRQ
+*              source. This is a return value.
+* @param       Trigger is pointer to the value of the trigger of the IRQ
+*              source. This is a return value.
+*
+* @return      None.
+*
+* @note                None
+*
+*****************************************************************************/
+void XScuGic_GetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
+                                       u8 *Priority, u8 *Trigger)
+{
+       u32 RegValue;
+
+       Xil_AssertVoid(InstancePtr != NULL);
+       Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+       Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
+       Xil_AssertVoid(Priority != NULL);
+       Xil_AssertVoid(Trigger != NULL);
+
+       /*
+        * Determine the register to read to using the Int_Id.
+        */
+       RegValue = XScuGic_DistReadReg(InstancePtr,
+           XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
+
+       /*
+        * Shift and Mask the correct bits for the priority and trigger in the
+        * register
+        */
+       RegValue = RegValue >> ((Int_Id%4U)*8U);
+       *Priority = (u8)(RegValue & XSCUGIC_PRIORITY_MASK);
+
+       /*
+        * Determine the register to read to using the Int_Id.
+        */
+       RegValue = XScuGic_DistReadReg(InstancePtr,
+       XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
+
+       /*
+        * Shift and Mask the correct bits for the priority and trigger in the
+        * register
+        */
+       RegValue = RegValue >> ((Int_Id%16U)*2U);
+
+       *Trigger = (u8)(RegValue & XSCUGIC_INT_CFG_MASK);
+}
+/****************************************************************************/
+/**
+* Sets the target CPU for the interrupt of a peripheral
+*
+* @param       InstancePtr is a pointer to the instance to be worked on.
+* @param       Cpu_Id is a CPU number for which the interrupt has to be targeted
+* @param       Int_Id is the IRQ source number to modify
+*
+* @return      None.
+*
+* @note                None
+*
+*****************************************************************************/
+void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
+{
+       u32 RegValue, Offset;
+       RegValue = XScuGic_DistReadReg(InstancePtr,
+                       XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
+
+       Offset = (Int_Id & 0x3U);
+       Cpu_Id = (0x1U << Cpu_Id);
+
+       RegValue = (RegValue & (~(0xFFU << (Offset*8U))) );
+       RegValue |= ((Cpu_Id) << (Offset*8U));
+
+       XScuGic_DistWriteReg(InstancePtr,
+                                                XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
+                                                RegValue);
+}
+/****************************************************************************/
+/**
+* Unmaps specific SPI interrupt from the target CPU
+*
+* @param       InstancePtr is a pointer to the instance to be worked on.
+* @param       Cpu_Id is a CPU number from which the interrupt has to be
+*                      unmapped
+* @param       Int_Id is the IRQ source number to modify
+*
+* @return      None.
+*
+* @note                None
+*
+*****************************************************************************/
+void XScuGic_InterruptUnmapFromCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
+{
+       u32 RegValue;
+       u8 BitPos;
+
+       Xil_AssertVoid(InstancePtr != NULL);
+
+       RegValue = XScuGic_DistReadReg(InstancePtr,
+                               XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
+
+       /*
+        * Identify bit position corresponding to  Int_Id and Cpu_Id,
+        * in interrupt target register and clear it
+        */
+       BitPos = ((Int_Id % 4U) * 8U) + Cpu_Id;
+       RegValue &= (~ ( 1U << BitPos ));
+       XScuGic_DistWriteReg(InstancePtr,
+                               XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
+                               RegValue);
+}
+/****************************************************************************/
+/**
+* Unmaps all SPI interrupts from the target CPU
+*
+* @param       InstancePtr is a pointer to the instance to be worked on.
+* @param       Cpu_Id is a CPU number from which the interrupts has to be
+*                      unmapped
+*
+* @return      None.
+*
+* @note                None
+*
+*****************************************************************************/
+void XScuGic_UnmapAllInterruptsFromCpu(XScuGic *InstancePtr, u8 Cpu_Id)
+{
+       u32 Int_Id;
+       u32 Target_Cpu;
+       u32 LocalCpuID = (1U << Cpu_Id);
+
+       Xil_AssertVoid(InstancePtr != NULL);
+
+       LocalCpuID |= LocalCpuID << 8U;
+       LocalCpuID |= LocalCpuID << 16U;
+
+       for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U)
+       {
+
+               Target_Cpu = XScuGic_DistReadReg(InstancePtr,
+                               XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
+               /* Remove LocalCpuID from interrupt target register */
+               Target_Cpu &= (~LocalCpuID);
+               XScuGic_DistWriteReg(InstancePtr,
+                       XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), Target_Cpu);
+
+       }
+}
+/****************************************************************************/
+/**
+* It checks if the interrupt target register contains all interrupts to be
+* targeted for current CPU. If they are programmed to be forwarded to current
+* cpu, this API disable all interrupts and disable GIC distributor.
+* This API also removes current CPU from interrupt target registers for all
+* interrupt.
+*
+* @param       InstancePtr is a pointer to the instance to be worked on.
+*
+* @return      None.
+*
+* @note                None
+*
+*****************************************************************************/
+void XScuGic_Stop(XScuGic *InstancePtr)
+{
+       u32 Int_Id;
+       u32 RegValue;
+       u32 Target_Cpu;
+       u32 DistDisable = 1; /* To track if distributor need to be disabled or not */
+       u32 LocalCpuID = ((u32)0x1 << CpuId);
+
+       Xil_AssertVoid(InstancePtr != NULL);
+
+       /* If distributor is already disabled, no need to do anything */
+       RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET);
+       if ((RegValue & XSCUGIC_EN_INT_MASK) == 0U) {
+               return;
+       }
+
+       LocalCpuID |= LocalCpuID << 8U;
+       LocalCpuID |= LocalCpuID << 16U;
+
+       /*
+        * Check if the interrupt are targeted to current cpu only or not.
+        * Also remove current cpu from interrupt target register for all
+        * interrupts.
+        */
+       for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
+
+               Target_Cpu = XScuGic_DistReadReg(InstancePtr,
+                                                                       XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
+               if ((Target_Cpu != LocalCpuID) && (Target_Cpu!= 0)) {
+                       /*
+                        * If any other CPU is also programmed to target register, GIC
+                        * distributor can not be disabled.
+                        */
+                       DistDisable = 0;
+               }
+
+               /* Remove current CPU from interrupt target register */
+               Target_Cpu &= (~LocalCpuID);
+               XScuGic_DistWriteReg(InstancePtr,
+                                               XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), Target_Cpu);
+
+       }
+
+       /*
+        * If GIC distributor is safe to be disabled, disable all the interrupt
+        * and then disable distributor.
+        */
+       if ( DistDisable == 1) {
+               for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) {
+                       /*
+                        * Disable all the interrupts
+                        */
+                       XScuGic_DistWriteReg(InstancePtr,
+                                                       XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET,
+                                                       Int_Id),
+                       0xFFFFFFFFU);
+               }
+               XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U);
+       }
+}
+
+/****************************************************************************/
+/**
+* This updates the CpuId global variable.
+*
+* @param       CpuCoreId is the CPU core number.
+*
+* @return      None.
+*
+* @note                None
+*
+*****************************************************************************/
+void XScuGic_SetCpuID(u32 CpuCoreId)
+{
+       Xil_AssertVoid(CpuCoreId <= 1U);
+
+       CpuId = CpuCoreId;
+}
+
+/****************************************************************************/
+/**
+* This function returns the CpuId variable.
+*
+* @param       None.
+*
+* @return      The CPU core number.
+*
+* @note        None.
+*
+*****************************************************************************/
+u32 XScuGic_GetCpuID(void)
+{
+       return CpuId;
+}
+/** @} */