1 /******************************************************************************
3 * Copyright (C) 2010 - 2018 Xilinx, Inc. All rights reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
31 ******************************************************************************/
32 /*****************************************************************************/
36 * @addtogroup scugic_v3_8
39 * Contains required functions for the XScuGic driver for the Interrupt
40 * Controller. See xscugic.h for a detailed description of the driver.
43 * MODIFICATION HISTORY:
45 * Ver Who Date Changes
46 * ----- ---- -------- --------------------------------------------------------
47 * 1.00a drg 01/19/10 First release
48 * 1.01a sdm 11/09/11 Changes are made in function XScuGic_CfgInitialize. Since
49 * "Config" entry is now made as pointer in the XScuGic
50 * structure, necessary changes are made.
51 * The HandlerTable can now be populated through the low
52 * level routine XScuGic_RegisterHandler added in this
53 * release. Hence necessary checks are added not to
54 * overwrite the HandlerTable entriesin function
55 * XScuGic_CfgInitialize.
56 * 1.03a srt 02/27/13 Added APIs
57 * - XScuGic_SetPriTrigTypeByDistAddr()
58 * - XScuGic_GetPriTrigTypeByDistAddr()
59 * Removed Offset calculation macros, defined in _hw.h
61 * Added support to direct interrupts to the appropriate CPU. Earlier
62 * interrupts were directed to CPU1 (hard coded). Now depending
63 * upon the CPU selected by the user (xparameters.h), interrupts
64 * will be directed to the relevant CPU. This fixes CR 699688.
66 * 1.04a hk 05/04/13 Assigned EffectiveAddr to CpuBaseAddress in
67 * XScuGic_CfgInitialize. Fix for CR#704400 to remove warnings.
68 * Moved functions XScuGic_SetPriTrigTypeByDistAddr and
69 * XScuGic_GetPriTrigTypeByDistAddr to xscugic_hw.c.
70 * This is fix for CR#705621.
71 * 1.06a asa 16/11/13 Fix for CR#749178. Assignment for EffectiveAddr
72 * in function XScuGic_CfgInitialize is removed as it was
74 * 3.00 kvn 02/13/14 Modified code for MISRA-C:2012 compliance.
75 * 3.01 pkp 06/19/15 Added XScuGic_InterruptMaptoCpu API for an interrupt
77 * 3.02 pkp 11/09/15 Modified DistributorInit function for AMP case to add
78 * the current cpu to interrupt processor targets registers
79 * 3.2 asa 02/29/16 Modified DistributorInit function for Zynq AMP case. The
80 * distributor is left uninitialized for Zynq AMP. It is assumed
81 * that the distributor will be initialized by Linux master. However
82 * for CortexR5 case, the earlier code is left unchanged where the
83 * the interrupt processor target registers in the distributor is
84 * initialized with the corresponding CPU ID on which the application
85 * built over the scugic driver runs.
86 * These changes fix CR#937243.
87 * 3.3 pkp 05/12/16 Modified XScuGic_InterruptMaptoCpu to write proper value
88 * to interrupt target register to fix CR#951848
90 * 3.4 asa 04/07/16 Created a new static function DoDistributorInit to simplify
91 * the flow and avoid code duplication. Changes are made for
92 * USE_AMP use case for R5. In a scenario (in R5 split mode) when
93 * one R5 is operating with A53 in open amp config and other
94 * R5 running baremetal app, the existing code
95 * had the potential to stop the whole AMP solution to work (if
96 * for some reason the R5 running the baremetal app tasked to
97 * initialize the Distributor hangs or crashes before initializing).
98 * Changes are made so that the R5 under AMP first checks if
99 * the distributor is enabled or not and if not, it does the
100 * standard Distributor initialization.
101 * This fixes the CR#952962.
102 * 3.4 mus 09/08/16 Added assert to avoid invalid access of GIC from CPUID 1
103 * for single core zynq-7000s
104 * 3.5 mus 10/05/16 Modified DistributorInit function to avoid re-initialization of
105 * distributor,If it is already initialized by other CPU.
106 * 3.5 pkp 10/17/16 Modified XScuGic_InterruptMaptoCpu to correct the CPU Id value
107 * and properly mask interrupt target processor value to modify
108 * interrupt target processor register for a given interrupt ID
110 * 3.6 pkp 20/01/17 Added new API XScuGic_Stop to Disable distributor and
111 * interrupts in case they are being used only by current cpu.
112 * It also removes current cpu from interrupt target registers
113 * for all interrupts.
114 * kvn 02/17/17 Add support for changing GIC CPU master at run time.
115 * kvn 02/28/17 Make the CpuId as static variable and Added new
116 * XScugiC_GetCpuId to access CpuId.
117 * 3.9 mus 02/21/18 Added new API's XScuGic_UnmapAllInterruptsFromCpu and
118 * XScuGic_InterruptUnmapFromCpu, These API's can be used
119 * by applications to unmap specific/all interrupts from
120 * target CPU. It fixes CR#992490.
124 ******************************************************************************/
126 /***************************** Include Files *********************************/
127 #include "xil_types.h"
128 #include "xil_assert.h"
131 /************************** Constant Definitions *****************************/
134 /**************************** Type Definitions *******************************/
137 /***************** Macros (Inline Functions) Definitions *********************/
139 /************************** Variable Definitions *****************************/
140 static u32 CpuId = XPAR_CPU_ID; /**< CPU Core identifier */
142 /************************** Function Prototypes ******************************/
144 static void StubHandler(void *CallBackRef);
146 /*****************************************************************************/
149 * DoDistributorInit initializes the distributor of the GIC. The
150 * initialization entails:
152 * - Write the trigger mode, priority and target CPU
153 * - All interrupt sources are disabled
154 * - Enable the distributor
156 * @param InstancePtr is a pointer to the XScuGic instance.
157 * @param CpuID is the Cpu ID to be initialized.
163 ******************************************************************************/
164 static void DoDistributorInit(XScuGic *InstancePtr, u32 CpuID)
167 u32 LocalCpuID = CpuID;
169 XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U);
172 * Set the security domains in the int_security registers for
173 * non-secure interrupts
174 * All are secure, so leave at the default. Set to 1 for non-secure
179 * For the Shared Peripheral Interrupts INT_ID[MAX..32], set:
183 * 1. The trigger mode in the int_config register
184 * Only write to the SPI interrupts, so start at 32
186 for (Int_Id = 32U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+16U) {
188 * Each INT_ID uses two bits, or 16 INT_ID per register
189 * Set them all to be level sensitive, active HIGH.
191 XScuGic_DistWriteReg(InstancePtr,
192 XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
197 #define DEFAULT_PRIORITY 0xa0a0a0a0U
198 for (Int_Id = 0U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+4U) {
200 * 2. The priority using int the priority_level register
201 * The priority_level and spi_target registers use one byte per
203 * Write a default value that can be changed elsewhere.
205 XScuGic_DistWriteReg(InstancePtr,
206 XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
210 for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
212 * 3. The CPU interface in the spi_target register
213 * Only write to the SPI interrupts, so start at 32
215 LocalCpuID |= LocalCpuID << 8U;
216 LocalCpuID |= LocalCpuID << 16U;
218 XScuGic_DistWriteReg(InstancePtr,
219 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
223 for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) {
225 * 4. Enable the SPI using the enable_set register. Leave all
228 XScuGic_DistWriteReg(InstancePtr,
229 XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET, Int_Id),
234 XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET,
235 XSCUGIC_EN_INT_MASK);
238 /*****************************************************************************/
241 * DistributorInit initializes the distributor of the GIC. It calls
242 * DoDistributorInit to finish the initialization.
244 * @param InstancePtr is a pointer to the XScuGic instance.
245 * @param CpuID is the Cpu ID to be initialized.
251 ******************************************************************************/
252 static void DistributorInit(XScuGic *InstancePtr, u32 CpuID)
255 u32 LocalCpuID = CpuID;
258 #if USE_AMP==1 && (defined (ARMA9) || defined(__aarch64__))
259 #warning "Building GIC for AMP"
261 * GIC initialization is taken care by master CPU in
262 * openamp configuration, so do nothing and return.
267 RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET);
268 if ((RegValue & XSCUGIC_EN_INT_MASK) == 0U) {
269 Xil_AssertVoid(InstancePtr != NULL);
270 DoDistributorInit(InstancePtr, CpuID);
275 * The overall distributor should not be initialized in AMP case where
276 * another CPU is taking care of it.
278 LocalCpuID |= LocalCpuID << 8U;
279 LocalCpuID |= LocalCpuID << 16U;
280 for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
281 RegValue = XScuGic_DistReadReg(InstancePtr,
282 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
283 RegValue |= LocalCpuID;
284 XScuGic_DistWriteReg(InstancePtr,
285 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
290 /*****************************************************************************/
293 * CPUInitialize initializes the CPU Interface of the GIC. The initialization entails:
295 * - Set the priority of the CPU
296 * - Enable the CPU interface
298 * @param InstancePtr is a pointer to the XScuGic instance.
304 ******************************************************************************/
305 static void CPUInitialize(XScuGic *InstancePtr)
308 * Program the priority mask of the CPU using the Priority mask register
310 XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CPU_PRIOR_OFFSET, 0xF0U);
314 * If the CPU operates in both security domains, set parameters in the
315 * control_s register.
316 * 1. Set FIQen=1 to use FIQ for secure interrupts,
317 * 2. Program the AckCtl bit
318 * 3. Program the SBPR bit to select the binary pointer behavior
319 * 4. Set EnableS = 1 to enable secure interrupts
320 * 5. Set EnbleNS = 1 to enable non secure interrupts
324 * If the CPU operates only in the secure domain, setup the
325 * control_s register.
327 * 2. Set EnableS=1, to enable the CPU interface to signal secure interrupts.
328 * Only enable the IRQ output unless secure interrupts are needed.
330 XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CONTROL_OFFSET, 0x07U);
334 /*****************************************************************************/
337 * CfgInitialize a specific interrupt controller instance/driver. The
338 * initialization entails:
340 * - Initialize fields of the XScuGic structure
341 * - Initial vector table with stub function calls
342 * - All interrupt sources are disabled
344 * @param InstancePtr is a pointer to the XScuGic instance.
345 * @param ConfigPtr is a pointer to a config table for the particular
346 * device this driver is associated with.
347 * @param EffectiveAddr is the device base address in the virtual memory
348 * address space. The caller is responsible for keeping the address
349 * mapping from EffectiveAddr to the device physical base address
350 * unchanged once this function is invoked. Unexpected errors may
351 * occur if the address mapping changes after this function is
352 * called. If address translation is not used, use
353 * Config->BaseAddress for this parameters, passing the physical
357 * - XST_SUCCESS if initialization was successful
361 ******************************************************************************/
362 s32 XScuGic_CfgInitialize(XScuGic *InstancePtr,
363 XScuGic_Config *ConfigPtr,
367 u32 Cpu_Id = CpuId + (u32)1;
368 (void) EffectiveAddr;
370 Xil_AssertNonvoid(InstancePtr != NULL);
371 Xil_AssertNonvoid(ConfigPtr != NULL);
373 * Detect Zynq-7000 base silicon configuration,Dual or Single CPU.
374 * If it is single CPU cnfiguration then invoke assert for CPU ID=1
377 if ( XPAR_CPU_ID == 0x01 )
379 Xil_AssertNonvoid((Xil_In32(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)
380 & EFUSE_STATUS_CPU_MASK ) == 0);
384 if(InstancePtr->IsReady != XIL_COMPONENT_IS_READY) {
386 InstancePtr->IsReady = 0U;
387 InstancePtr->Config = ConfigPtr;
390 for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id++) {
392 * Initalize the handler to point to a stub to handle an
393 * interrupt which has not been connected to a handler. Only
394 * initialize it if the handler is 0 which means it was not
395 * initialized statically by the tools/user. Set the callback
396 * reference to this instance so that unhandled interrupts
399 if ((InstancePtr->Config->HandlerTable[Int_Id].Handler == NULL)) {
400 InstancePtr->Config->HandlerTable[Int_Id].Handler =
403 InstancePtr->Config->HandlerTable[Int_Id].CallBackRef =
406 XScuGic_Stop(InstancePtr);
407 DistributorInit(InstancePtr, Cpu_Id);
408 CPUInitialize(InstancePtr);
410 InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
416 /*****************************************************************************/
419 * Makes the connection between the Int_Id of the interrupt source and the
420 * associated handler that is to run when the interrupt is recognized. The
421 * argument provided in this call as the Callbackref is used as the argument
422 * for the handler when it is called.
424 * @param InstancePtr is a pointer to the XScuGic instance.
425 * @param Int_Id contains the ID of the interrupt source and should be
426 * in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
427 * @param Handler to the handler for that interrupt.
428 * @param CallBackRef is the callback reference, usually the instance
429 * pointer of the connecting driver.
433 * - XST_SUCCESS if the handler was connected correctly.
437 * WARNING: The handler provided as an argument will overwrite any handler
438 * that was previously connected.
440 ****************************************************************************/
441 s32 XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
442 Xil_InterruptHandler Handler, void *CallBackRef)
445 * Assert the arguments
447 Xil_AssertNonvoid(InstancePtr != NULL);
448 Xil_AssertNonvoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
449 Xil_AssertNonvoid(Handler != NULL);
450 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
453 * The Int_Id is used as an index into the table to select the proper
456 InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler;
457 InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;
462 /*****************************************************************************/
465 * Updates the interrupt table with the Null Handler and NULL arguments at the
466 * location pointed at by the Int_Id. This effectively disconnects that interrupt
467 * source from any handler. The interrupt is disabled also.
469 * @param InstancePtr is a pointer to the XScuGic instance to be worked on.
470 * @param Int_Id contains the ID of the interrupt source and should
471 * be in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
477 ****************************************************************************/
478 void XScuGic_Disconnect(XScuGic *InstancePtr, u32 Int_Id)
483 * Assert the arguments
485 Xil_AssertVoid(InstancePtr != NULL);
486 Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
487 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
490 * The Int_Id is used to create the appropriate mask for the
491 * desired bit position. Int_Id currently limited to 0 - 31
493 Mask = 0x00000001U << (Int_Id % 32U);
496 * Disable the interrupt such that it won't occur while disconnecting
497 * the handler, only disable the specified interrupt id without modifying
498 * the other interrupt ids
500 XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
501 ((Int_Id / 32U) * 4U), Mask);
504 * Disconnect the handler and connect a stub, the callback reference
505 * must be set to this instance to allow unhandled interrupts to be
508 InstancePtr->Config->HandlerTable[Int_Id].Handler = StubHandler;
509 InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = InstancePtr;
512 /*****************************************************************************/
515 * Enables the interrupt source provided as the argument Int_Id. Any pending
516 * interrupt condition for the specified Int_Id will occur after this function is
519 * @param InstancePtr is a pointer to the XScuGic instance.
520 * @param Int_Id contains the ID of the interrupt source and should be
521 * in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
527 ****************************************************************************/
528 void XScuGic_Enable(XScuGic *InstancePtr, u32 Int_Id)
533 * Assert the arguments
535 Xil_AssertVoid(InstancePtr != NULL);
536 Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
537 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
540 * The Int_Id is used to create the appropriate mask for the
541 * desired bit position. Int_Id currently limited to 0 - 31
543 Mask = 0x00000001U << (Int_Id % 32U);
546 * Enable the selected interrupt source by setting the
547 * corresponding bit in the Enable Set register.
549 XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_ENABLE_SET_OFFSET +
550 ((Int_Id / 32U) * 4U), Mask);
553 /*****************************************************************************/
556 * Disables the interrupt source provided as the argument Int_Id such that the
557 * interrupt controller will not cause interrupts for the specified Int_Id. The
558 * interrupt controller will continue to hold an interrupt condition for the
559 * Int_Id, but will not cause an interrupt.
561 * @param InstancePtr is a pointer to the XScuGic instance.
562 * @param Int_Id contains the ID of the interrupt source and should be
563 * in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
569 ****************************************************************************/
570 void XScuGic_Disable(XScuGic *InstancePtr, u32 Int_Id)
575 * Assert the arguments
577 Xil_AssertVoid(InstancePtr != NULL);
578 Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
579 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
582 * The Int_Id is used to create the appropriate mask for the
583 * desired bit position. Int_Id currently limited to 0 - 31
585 Mask = 0x00000001U << (Int_Id % 32U);
588 * Disable the selected interrupt source by setting the
589 * corresponding bit in the IDR.
591 XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
592 ((Int_Id / 32U) * 4U), Mask);
595 /*****************************************************************************/
598 * Allows software to simulate an interrupt in the interrupt controller. This
599 * function will only be successful when the interrupt controller has been
600 * started in simulation mode. A simulated interrupt allows the interrupt
601 * controller to be tested without any device to drive an interrupt input
604 * @param InstancePtr is a pointer to the XScuGic instance.
605 * @param Int_Id is the software interrupt ID to simulate an interrupt.
606 * @param Cpu_Id is the list of CPUs to send the interrupt.
610 * XST_SUCCESS if successful, or XST_FAILURE if the interrupt could not be
615 ******************************************************************************/
616 s32 XScuGic_SoftwareIntr(XScuGic *InstancePtr, u32 Int_Id, u32 Cpu_Id)
621 * Assert the arguments
623 Xil_AssertNonvoid(InstancePtr != NULL);
624 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
625 Xil_AssertNonvoid(Int_Id <= 15U) ;
626 Xil_AssertNonvoid(Cpu_Id <= 255U) ;
630 * The Int_Id is used to create the appropriate mask for the
631 * desired interrupt. Int_Id currently limited to 0 - 15
632 * Use the target list for the Cpu ID.
634 Mask = ((Cpu_Id << 16U) | Int_Id) &
635 (XSCUGIC_SFI_TRIG_CPU_MASK | XSCUGIC_SFI_TRIG_INTID_MASK);
638 * Write to the Software interrupt trigger register. Use the appropriate
641 XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SFI_TRIG_OFFSET, Mask);
643 /* Indicate the interrupt was successfully simulated */
648 /*****************************************************************************/
651 * A stub for the asynchronous callback. The stub is here in case the upper
652 * layers forget to set the handler.
654 * @param CallBackRef is a pointer to the upper layer callback reference
660 ******************************************************************************/
661 static void StubHandler(void *CallBackRef) {
663 * verify that the inputs are valid
665 Xil_AssertVoid(CallBackRef != NULL);
668 * Indicate another unhandled interrupt for stats
670 ((XScuGic *)((void *)CallBackRef))->UnhandledInterrupts++;
673 /****************************************************************************/
675 * Sets the interrupt priority and trigger type for the specificd IRQ source.
677 * @param InstancePtr is a pointer to the instance to be worked on.
678 * @param Int_Id is the IRQ source number to modify
679 * @param Priority is the new priority for the IRQ source. 0 is highest
680 * priority, 0xF8 (248) is lowest. There are 32 priority levels
681 * supported with a step of 8. Hence the supported priorities are
682 * 0, 8, 16, 32, 40 ..., 248.
683 * @param Trigger is the new trigger type for the IRQ source.
684 * Each bit pair describes the configuration for an INT_ID.
685 * SFI Read Only b10 always
686 * PPI Read Only depending on how the PPIs are configured.
687 * b01 Active HIGH level sensitive
688 * b11 Rising edge sensitive
689 * SPI LSB is read only.
690 * b01 Active HIGH level sensitive
691 * b11 Rising edge sensitive/
697 *****************************************************************************/
698 void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
699 u8 Priority, u8 Trigger)
703 LocalPriority = Priority;
705 Xil_AssertVoid(InstancePtr != NULL);
706 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
707 Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
708 Xil_AssertVoid(Trigger <= (u8)XSCUGIC_INT_CFG_MASK);
709 Xil_AssertVoid(LocalPriority <= (u8)XSCUGIC_MAX_INTR_PRIO_VAL);
712 * Determine the register to write to using the Int_Id.
714 RegValue = XScuGic_DistReadReg(InstancePtr,
715 XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
718 * The priority bits are Bits 7 to 3 in GIC Priority Register. This
719 * means the number of priority levels supported are 32 and they are
720 * in steps of 8. The priorities can be 0, 8, 16, 32, 48, ... etc.
721 * The lower order 3 bits are masked before putting it in the register.
723 LocalPriority = LocalPriority & (u8)XSCUGIC_INTR_PRIO_MASK;
725 * Shift and Mask the correct bits for the priority and trigger in the
728 RegValue &= ~(XSCUGIC_PRIORITY_MASK << ((Int_Id%4U)*8U));
729 RegValue |= (u32)LocalPriority << ((Int_Id%4U)*8U);
732 * Write the value back to the register.
734 XScuGic_DistWriteReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
738 * Determine the register to write to using the Int_Id.
740 RegValue = XScuGic_DistReadReg(InstancePtr,
741 XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
744 * Shift and Mask the correct bits for the priority and trigger in the
747 RegValue &= ~(XSCUGIC_INT_CFG_MASK << ((Int_Id%16U)*2U));
748 RegValue |= (u32)Trigger << ((Int_Id%16U)*2U);
751 * Write the value back to the register.
753 XScuGic_DistWriteReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
758 /****************************************************************************/
760 * Gets the interrupt priority and trigger type for the specificd IRQ source.
762 * @param InstancePtr is a pointer to the instance to be worked on.
763 * @param Int_Id is the IRQ source number to modify
764 * @param Priority is a pointer to the value of the priority of the IRQ
765 * source. This is a return value.
766 * @param Trigger is pointer to the value of the trigger of the IRQ
767 * source. This is a return value.
773 *****************************************************************************/
774 void XScuGic_GetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
775 u8 *Priority, u8 *Trigger)
779 Xil_AssertVoid(InstancePtr != NULL);
780 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
781 Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
782 Xil_AssertVoid(Priority != NULL);
783 Xil_AssertVoid(Trigger != NULL);
786 * Determine the register to read to using the Int_Id.
788 RegValue = XScuGic_DistReadReg(InstancePtr,
789 XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
792 * Shift and Mask the correct bits for the priority and trigger in the
795 RegValue = RegValue >> ((Int_Id%4U)*8U);
796 *Priority = (u8)(RegValue & XSCUGIC_PRIORITY_MASK);
799 * Determine the register to read to using the Int_Id.
801 RegValue = XScuGic_DistReadReg(InstancePtr,
802 XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
805 * Shift and Mask the correct bits for the priority and trigger in the
808 RegValue = RegValue >> ((Int_Id%16U)*2U);
810 *Trigger = (u8)(RegValue & XSCUGIC_INT_CFG_MASK);
812 /****************************************************************************/
814 * Sets the target CPU for the interrupt of a peripheral
816 * @param InstancePtr is a pointer to the instance to be worked on.
817 * @param Cpu_Id is a CPU number for which the interrupt has to be targeted
818 * @param Int_Id is the IRQ source number to modify
824 *****************************************************************************/
825 void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
827 u32 RegValue, Offset;
828 RegValue = XScuGic_DistReadReg(InstancePtr,
829 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
831 Offset = (Int_Id & 0x3U);
832 Cpu_Id = (0x1U << Cpu_Id);
834 RegValue = (RegValue & (~(0xFFU << (Offset*8U))) );
835 RegValue |= ((Cpu_Id) << (Offset*8U));
837 XScuGic_DistWriteReg(InstancePtr,
838 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
841 /****************************************************************************/
843 * Unmaps specific SPI interrupt from the target CPU
845 * @param InstancePtr is a pointer to the instance to be worked on.
846 * @param Cpu_Id is a CPU number from which the interrupt has to be
848 * @param Int_Id is the IRQ source number to modify
854 *****************************************************************************/
855 void XScuGic_InterruptUnmapFromCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
860 Xil_AssertVoid(InstancePtr != NULL);
862 RegValue = XScuGic_DistReadReg(InstancePtr,
863 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
866 * Identify bit position corresponding to Int_Id and Cpu_Id,
867 * in interrupt target register and clear it
869 BitPos = ((Int_Id % 4U) * 8U) + Cpu_Id;
870 RegValue &= (~ ( 1U << BitPos ));
871 XScuGic_DistWriteReg(InstancePtr,
872 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
875 /****************************************************************************/
877 * Unmaps all SPI interrupts from the target CPU
879 * @param InstancePtr is a pointer to the instance to be worked on.
880 * @param Cpu_Id is a CPU number from which the interrupts has to be
887 *****************************************************************************/
888 void XScuGic_UnmapAllInterruptsFromCpu(XScuGic *InstancePtr, u8 Cpu_Id)
892 u32 LocalCpuID = (1U << Cpu_Id);
894 Xil_AssertVoid(InstancePtr != NULL);
896 LocalCpuID |= LocalCpuID << 8U;
897 LocalCpuID |= LocalCpuID << 16U;
899 for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U)
902 Target_Cpu = XScuGic_DistReadReg(InstancePtr,
903 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
904 /* Remove LocalCpuID from interrupt target register */
905 Target_Cpu &= (~LocalCpuID);
906 XScuGic_DistWriteReg(InstancePtr,
907 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), Target_Cpu);
911 /****************************************************************************/
913 * It checks if the interrupt target register contains all interrupts to be
914 * targeted for current CPU. If they are programmed to be forwarded to current
915 * cpu, this API disable all interrupts and disable GIC distributor.
916 * This API also removes current CPU from interrupt target registers for all
919 * @param InstancePtr is a pointer to the instance to be worked on.
925 *****************************************************************************/
926 void XScuGic_Stop(XScuGic *InstancePtr)
931 u32 DistDisable = 1; /* To track if distributor need to be disabled or not */
932 u32 LocalCpuID = ((u32)0x1 << CpuId);
934 Xil_AssertVoid(InstancePtr != NULL);
936 /* If distributor is already disabled, no need to do anything */
937 RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET);
938 if ((RegValue & XSCUGIC_EN_INT_MASK) == 0U) {
942 LocalCpuID |= LocalCpuID << 8U;
943 LocalCpuID |= LocalCpuID << 16U;
946 * Check if the interrupt are targeted to current cpu only or not.
947 * Also remove current cpu from interrupt target register for all
950 for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
952 Target_Cpu = XScuGic_DistReadReg(InstancePtr,
953 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
954 if ((Target_Cpu != LocalCpuID) && (Target_Cpu!= 0)) {
956 * If any other CPU is also programmed to target register, GIC
957 * distributor can not be disabled.
962 /* Remove current CPU from interrupt target register */
963 Target_Cpu &= (~LocalCpuID);
964 XScuGic_DistWriteReg(InstancePtr,
965 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), Target_Cpu);
970 * If GIC distributor is safe to be disabled, disable all the interrupt
971 * and then disable distributor.
973 if ( DistDisable == 1) {
974 for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) {
976 * Disable all the interrupts
978 XScuGic_DistWriteReg(InstancePtr,
979 XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET,
983 XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U);
987 /****************************************************************************/
989 * This updates the CpuId global variable.
991 * @param CpuCoreId is the CPU core number.
997 *****************************************************************************/
998 void XScuGic_SetCpuID(u32 CpuCoreId)
1000 Xil_AssertVoid(CpuCoreId <= 1U);
1005 /****************************************************************************/
1007 * This function returns the CpuId variable.
1011 * @return The CPU core number.
1015 *****************************************************************************/
1016 u32 XScuGic_GetCpuID(void)