]> git.sur5r.net Git - freertos/blob - 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
1 /******************************************************************************
2 *
3 * Copyright (C) 2010 - 2018 Xilinx, Inc.  All rights reserved.
4 *
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:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
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.
18 *
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
25 * SOFTWARE.
26 *
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.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xscugic.c
36 * @addtogroup scugic_v3_8
37 * @{
38 *
39 * Contains required functions for the XScuGic driver for the Interrupt
40 * Controller. See xscugic.h for a detailed description of the driver.
41 *
42 * <pre>
43 * MODIFICATION HISTORY:
44 *
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
60 *                                 (CR 702687)
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.
65 *
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
73 *                                 a bug.
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
76 *                                         target CPU mapping
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
89 *
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
109 *                                         and cpu 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.
121 *
122 * </pre>
123 *
124 ******************************************************************************/
125
126 /***************************** Include Files *********************************/
127 #include "xil_types.h"
128 #include "xil_assert.h"
129 #include "xscugic.h"
130
131 /************************** Constant Definitions *****************************/
132
133
134 /**************************** Type Definitions *******************************/
135
136
137 /***************** Macros (Inline Functions) Definitions *********************/
138
139 /************************** Variable Definitions *****************************/
140 static u32 CpuId = XPAR_CPU_ID; /**< CPU Core identifier */
141
142 /************************** Function Prototypes ******************************/
143
144 static void StubHandler(void *CallBackRef);
145
146 /*****************************************************************************/
147 /**
148 *
149 * DoDistributorInit initializes the distributor of the GIC. The
150 * initialization entails:
151 *
152 * - Write the trigger mode, priority and target CPU
153 * - All interrupt sources are disabled
154 * - Enable the distributor
155 *
156 * @param        InstancePtr is a pointer to the XScuGic instance.
157 * @param        CpuID is the Cpu ID to be initialized.
158 *
159 * @return       None
160 *
161 * @note         None.
162 *
163 ******************************************************************************/
164 static void DoDistributorInit(XScuGic *InstancePtr, u32 CpuID)
165 {
166         u32 Int_Id;
167         u32 LocalCpuID = CpuID;
168
169         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U);
170
171         /*
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
175          * interrupts.
176          */
177
178         /*
179          * For the Shared Peripheral Interrupts INT_ID[MAX..32], set:
180          */
181
182         /*
183          * 1. The trigger mode in the int_config register
184          * Only write to the SPI interrupts, so start at 32
185          */
186         for (Int_Id = 32U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+16U) {
187                 /*
188                  * Each INT_ID uses two bits, or 16 INT_ID per register
189                  * Set them all to be level sensitive, active HIGH.
190                  */
191                 XScuGic_DistWriteReg(InstancePtr,
192                                         XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
193                                         0U);
194         }
195
196
197 #define DEFAULT_PRIORITY    0xa0a0a0a0U
198         for (Int_Id = 0U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+4U) {
199                 /*
200                  * 2. The priority using int the priority_level register
201                  * The priority_level and spi_target registers use one byte per
202                  * INT_ID.
203                  * Write a default value that can be changed elsewhere.
204                  */
205                 XScuGic_DistWriteReg(InstancePtr,
206                                         XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
207                                         DEFAULT_PRIORITY);
208         }
209
210         for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
211                 /*
212                  * 3. The CPU interface in the spi_target register
213                  * Only write to the SPI interrupts, so start at 32
214                  */
215                 LocalCpuID |= LocalCpuID << 8U;
216                 LocalCpuID |= LocalCpuID << 16U;
217
218                 XScuGic_DistWriteReg(InstancePtr,
219                                          XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
220                                          LocalCpuID);
221         }
222
223         for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) {
224                 /*
225                  * 4. Enable the SPI using the enable_set register. Leave all
226                  * disabled for now.
227                  */
228                 XScuGic_DistWriteReg(InstancePtr,
229                 XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET, Int_Id),
230                         0xFFFFFFFFU);
231
232         }
233
234         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET,
235                                         XSCUGIC_EN_INT_MASK);
236 }
237
238 /*****************************************************************************/
239 /**
240 *
241 * DistributorInit initializes the distributor of the GIC. It calls
242 * DoDistributorInit to finish the initialization.
243 *
244 * @param        InstancePtr is a pointer to the XScuGic instance.
245 * @param        CpuID is the Cpu ID to be initialized.
246 *
247 * @return       None
248 *
249 * @note         None.
250 *
251 ******************************************************************************/
252 static void DistributorInit(XScuGic *InstancePtr, u32 CpuID)
253 {
254         u32 Int_Id;
255         u32 LocalCpuID = CpuID;
256         u32 RegValue;
257
258 #if USE_AMP==1 && (defined (ARMA9) || defined(__aarch64__))
259 #warning "Building GIC for AMP"
260         /*
261          * GIC initialization is taken care by master CPU in
262          * openamp configuration, so do nothing and return.
263          */
264         return;
265 #endif
266
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);
271                 return;
272         }
273
274         /*
275          * The overall distributor should not be initialized in AMP case where
276          * another CPU is taking care of it.
277          */
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),
286                                      RegValue);
287         }
288 }
289
290 /*****************************************************************************/
291 /**
292 *
293 * CPUInitialize initializes the CPU Interface of the GIC. The initialization entails:
294 *
295 *       - Set the priority of the CPU
296 *       - Enable the CPU interface
297 *
298 * @param        InstancePtr is a pointer to the XScuGic instance.
299 *
300 * @return       None
301 *
302 * @note         None.
303 *
304 ******************************************************************************/
305 static void CPUInitialize(XScuGic *InstancePtr)
306 {
307         /*
308          * Program the priority mask of the CPU using the Priority mask register
309          */
310         XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CPU_PRIOR_OFFSET, 0xF0U);
311
312
313         /*
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
321          */
322
323         /*
324          * If the CPU operates only in the secure domain, setup the
325          * control_s register.
326          * 1. Set FIQen=1,
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.
329          */
330         XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CONTROL_OFFSET, 0x07U);
331
332 }
333
334 /*****************************************************************************/
335 /**
336 *
337 * CfgInitialize a specific interrupt controller instance/driver. The
338 * initialization entails:
339 *
340 * - Initialize fields of the XScuGic structure
341 * - Initial vector table with stub function calls
342 * - All interrupt sources are disabled
343 *
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
354 *               address instead.
355 *
356 * @return
357 *               - XST_SUCCESS if initialization was successful
358 *
359 * @note         None.
360 *
361 ******************************************************************************/
362 s32  XScuGic_CfgInitialize(XScuGic *InstancePtr,
363                                 XScuGic_Config *ConfigPtr,
364                                 u32 EffectiveAddr)
365 {
366         u32 Int_Id;
367         u32 Cpu_Id = CpuId + (u32)1;
368         (void) EffectiveAddr;
369
370         Xil_AssertNonvoid(InstancePtr != NULL);
371         Xil_AssertNonvoid(ConfigPtr != NULL);
372         /*
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
375          */
376 #ifdef ARMA9
377         if ( XPAR_CPU_ID == 0x01 )
378         {
379                 Xil_AssertNonvoid((Xil_In32(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)
380                  & EFUSE_STATUS_CPU_MASK ) == 0);
381         }
382 #endif
383
384         if(InstancePtr->IsReady != XIL_COMPONENT_IS_READY) {
385
386                 InstancePtr->IsReady = 0U;
387                 InstancePtr->Config = ConfigPtr;
388
389
390                 for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id++) {
391                         /*
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
397                         * can be tracked.
398                         */
399                         if      ((InstancePtr->Config->HandlerTable[Int_Id].Handler == NULL)) {
400                                 InstancePtr->Config->HandlerTable[Int_Id].Handler =
401                                                                         StubHandler;
402                         }
403                         InstancePtr->Config->HandlerTable[Int_Id].CallBackRef =
404                                                                 InstancePtr;
405                 }
406                 XScuGic_Stop(InstancePtr);
407                 DistributorInit(InstancePtr, Cpu_Id);
408                 CPUInitialize(InstancePtr);
409
410                 InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
411         }
412
413         return XST_SUCCESS;
414 }
415
416 /*****************************************************************************/
417 /**
418 *
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.
423 *
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.
430 *
431 * @return
432 *
433 *               - XST_SUCCESS if the handler was connected correctly.
434 *
435 * @note
436 *
437 * WARNING: The handler provided as an argument will overwrite any handler
438 * that was previously connected.
439 *
440 ****************************************************************************/
441 s32  XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
442                       Xil_InterruptHandler Handler, void *CallBackRef)
443 {
444         /*
445          * Assert the arguments
446          */
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);
451
452         /*
453          * The Int_Id is used as an index into the table to select the proper
454          * handler
455          */
456         InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler;
457         InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;
458
459         return XST_SUCCESS;
460 }
461
462 /*****************************************************************************/
463 /**
464 *
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.
468 *
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
472 *
473 * @return       None.
474 *
475 * @note         None.
476 *
477 ****************************************************************************/
478 void XScuGic_Disconnect(XScuGic *InstancePtr, u32 Int_Id)
479 {
480         u32 Mask;
481
482         /*
483          * Assert the arguments
484          */
485         Xil_AssertVoid(InstancePtr != NULL);
486         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
487         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
488
489         /*
490          * The Int_Id is used to create the appropriate mask for the
491          * desired bit position. Int_Id currently limited to 0 - 31
492          */
493         Mask = 0x00000001U << (Int_Id % 32U);
494
495         /*
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
499          */
500         XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
501                                                 ((Int_Id / 32U) * 4U), Mask);
502
503         /*
504          * Disconnect the handler and connect a stub, the callback reference
505          * must be set to this instance to allow unhandled interrupts to be
506          * tracked
507          */
508         InstancePtr->Config->HandlerTable[Int_Id].Handler = StubHandler;
509         InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = InstancePtr;
510 }
511
512 /*****************************************************************************/
513 /**
514 *
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
517 * called.
518 *
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
522 *
523 * @return       None.
524 *
525 * @note         None.
526 *
527 ****************************************************************************/
528 void XScuGic_Enable(XScuGic *InstancePtr, u32 Int_Id)
529 {
530         u32 Mask;
531
532         /*
533          * Assert the arguments
534          */
535         Xil_AssertVoid(InstancePtr != NULL);
536         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
537         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
538
539         /*
540          * The Int_Id is used to create the appropriate mask for the
541          * desired bit position. Int_Id currently limited to 0 - 31
542          */
543         Mask = 0x00000001U << (Int_Id % 32U);
544
545         /*
546          * Enable the selected interrupt source by setting the
547          * corresponding bit in the Enable Set register.
548          */
549         XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_ENABLE_SET_OFFSET +
550                                                 ((Int_Id / 32U) * 4U), Mask);
551 }
552
553 /*****************************************************************************/
554 /**
555 *
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.
560 *
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
564 *
565 * @return       None.
566 *
567 * @note         None.
568 *
569 ****************************************************************************/
570 void XScuGic_Disable(XScuGic *InstancePtr, u32 Int_Id)
571 {
572         u32 Mask;
573
574         /*
575          * Assert the arguments
576          */
577         Xil_AssertVoid(InstancePtr != NULL);
578         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
579         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
580
581         /*
582          * The Int_Id is used to create the appropriate mask for the
583          * desired bit position. Int_Id currently limited to 0 - 31
584          */
585         Mask = 0x00000001U << (Int_Id % 32U);
586
587         /*
588          * Disable the selected interrupt source by setting the
589          * corresponding bit in the IDR.
590          */
591         XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
592                                                 ((Int_Id / 32U) * 4U), Mask);
593 }
594
595 /*****************************************************************************/
596 /**
597 *
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
602 * signal into it.
603 *
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.
607 *
608 * @return
609 *
610 * XST_SUCCESS if successful, or XST_FAILURE if the interrupt could not be
611 * simulated
612 *
613 * @note         None.
614 *
615 ******************************************************************************/
616 s32  XScuGic_SoftwareIntr(XScuGic *InstancePtr, u32 Int_Id, u32 Cpu_Id)
617 {
618         u32 Mask;
619
620         /*
621          * Assert the arguments
622          */
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) ;
627
628
629         /*
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.
633          */
634         Mask = ((Cpu_Id << 16U) | Int_Id) &
635                 (XSCUGIC_SFI_TRIG_CPU_MASK | XSCUGIC_SFI_TRIG_INTID_MASK);
636
637         /*
638          * Write to the Software interrupt trigger register. Use the appropriate
639          * CPU Int_Id.
640          */
641         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SFI_TRIG_OFFSET, Mask);
642
643         /* Indicate the interrupt was successfully simulated */
644
645         return XST_SUCCESS;
646 }
647
648 /*****************************************************************************/
649 /**
650 *
651 * A stub for the asynchronous callback. The stub is here in case the upper
652 * layers forget to set the handler.
653 *
654 * @param        CallBackRef is a pointer to the upper layer callback reference
655 *
656 * @return       None.
657 *
658 * @note         None.
659 *
660 ******************************************************************************/
661 static void StubHandler(void *CallBackRef) {
662         /*
663          * verify that the inputs are valid
664          */
665         Xil_AssertVoid(CallBackRef != NULL);
666
667         /*
668          * Indicate another unhandled interrupt for stats
669          */
670         ((XScuGic *)((void *)CallBackRef))->UnhandledInterrupts++;
671 }
672
673 /****************************************************************************/
674 /**
675 * Sets the interrupt priority and trigger type for the specificd IRQ source.
676 *
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/
692 *
693 * @return       None.
694 *
695 * @note         None.
696 *
697 *****************************************************************************/
698 void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
699                                         u8 Priority, u8 Trigger)
700 {
701         u32 RegValue;
702         u8 LocalPriority;
703         LocalPriority = Priority;
704
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);
710
711         /*
712          * Determine the register to write to using the Int_Id.
713          */
714         RegValue = XScuGic_DistReadReg(InstancePtr,
715                         XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
716
717         /*
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.
722          */
723         LocalPriority = LocalPriority & (u8)XSCUGIC_INTR_PRIO_MASK;
724         /*
725          * Shift and Mask the correct bits for the priority and trigger in the
726          * register
727          */
728         RegValue &= ~(XSCUGIC_PRIORITY_MASK << ((Int_Id%4U)*8U));
729         RegValue |= (u32)LocalPriority << ((Int_Id%4U)*8U);
730
731         /*
732          * Write the value back to the register.
733          */
734         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
735                                 RegValue);
736
737         /*
738          * Determine the register to write to using the Int_Id.
739          */
740         RegValue = XScuGic_DistReadReg(InstancePtr,
741                         XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
742
743         /*
744          * Shift and Mask the correct bits for the priority and trigger in the
745          * register
746          */
747         RegValue &= ~(XSCUGIC_INT_CFG_MASK << ((Int_Id%16U)*2U));
748         RegValue |= (u32)Trigger << ((Int_Id%16U)*2U);
749
750         /*
751          * Write the value back to the register.
752          */
753         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
754                                 RegValue);
755
756 }
757
758 /****************************************************************************/
759 /**
760 * Gets the interrupt priority and trigger type for the specificd IRQ source.
761 *
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.
768 *
769 * @return       None.
770 *
771 * @note         None
772 *
773 *****************************************************************************/
774 void XScuGic_GetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
775                                         u8 *Priority, u8 *Trigger)
776 {
777         u32 RegValue;
778
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);
784
785         /*
786          * Determine the register to read to using the Int_Id.
787          */
788         RegValue = XScuGic_DistReadReg(InstancePtr,
789             XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
790
791         /*
792          * Shift and Mask the correct bits for the priority and trigger in the
793          * register
794          */
795         RegValue = RegValue >> ((Int_Id%4U)*8U);
796         *Priority = (u8)(RegValue & XSCUGIC_PRIORITY_MASK);
797
798         /*
799          * Determine the register to read to using the Int_Id.
800          */
801         RegValue = XScuGic_DistReadReg(InstancePtr,
802         XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
803
804         /*
805          * Shift and Mask the correct bits for the priority and trigger in the
806          * register
807          */
808         RegValue = RegValue >> ((Int_Id%16U)*2U);
809
810         *Trigger = (u8)(RegValue & XSCUGIC_INT_CFG_MASK);
811 }
812 /****************************************************************************/
813 /**
814 * Sets the target CPU for the interrupt of a peripheral
815 *
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
819 *
820 * @return       None.
821 *
822 * @note         None
823 *
824 *****************************************************************************/
825 void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
826 {
827         u32 RegValue, Offset;
828         RegValue = XScuGic_DistReadReg(InstancePtr,
829                         XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
830
831         Offset = (Int_Id & 0x3U);
832         Cpu_Id = (0x1U << Cpu_Id);
833
834         RegValue = (RegValue & (~(0xFFU << (Offset*8U))) );
835         RegValue |= ((Cpu_Id) << (Offset*8U));
836
837         XScuGic_DistWriteReg(InstancePtr,
838                                                  XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
839                                                  RegValue);
840 }
841 /****************************************************************************/
842 /**
843 * Unmaps specific SPI interrupt from the target CPU
844 *
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
847 *                       unmapped
848 * @param        Int_Id is the IRQ source number to modify
849 *
850 * @return       None.
851 *
852 * @note         None
853 *
854 *****************************************************************************/
855 void XScuGic_InterruptUnmapFromCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
856 {
857         u32 RegValue;
858         u8 BitPos;
859
860         Xil_AssertVoid(InstancePtr != NULL);
861
862         RegValue = XScuGic_DistReadReg(InstancePtr,
863                                 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
864
865         /*
866          * Identify bit position corresponding to  Int_Id and Cpu_Id,
867          * in interrupt target register and clear it
868          */
869         BitPos = ((Int_Id % 4U) * 8U) + Cpu_Id;
870         RegValue &= (~ ( 1U << BitPos ));
871         XScuGic_DistWriteReg(InstancePtr,
872                                 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
873                                 RegValue);
874 }
875 /****************************************************************************/
876 /**
877 * Unmaps all SPI interrupts from the target CPU
878 *
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
881 *                       unmapped
882 *
883 * @return       None.
884 *
885 * @note         None
886 *
887 *****************************************************************************/
888 void XScuGic_UnmapAllInterruptsFromCpu(XScuGic *InstancePtr, u8 Cpu_Id)
889 {
890         u32 Int_Id;
891         u32 Target_Cpu;
892         u32 LocalCpuID = (1U << Cpu_Id);
893
894         Xil_AssertVoid(InstancePtr != NULL);
895
896         LocalCpuID |= LocalCpuID << 8U;
897         LocalCpuID |= LocalCpuID << 16U;
898
899         for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U)
900         {
901
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);
908
909         }
910 }
911 /****************************************************************************/
912 /**
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
917 * interrupt.
918 *
919 * @param        InstancePtr is a pointer to the instance to be worked on.
920 *
921 * @return       None.
922 *
923 * @note         None
924 *
925 *****************************************************************************/
926 void XScuGic_Stop(XScuGic *InstancePtr)
927 {
928         u32 Int_Id;
929         u32 RegValue;
930         u32 Target_Cpu;
931         u32 DistDisable = 1; /* To track if distributor need to be disabled or not */
932         u32 LocalCpuID = ((u32)0x1 << CpuId);
933
934         Xil_AssertVoid(InstancePtr != NULL);
935
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) {
939                 return;
940         }
941
942         LocalCpuID |= LocalCpuID << 8U;
943         LocalCpuID |= LocalCpuID << 16U;
944
945         /*
946          * Check if the interrupt are targeted to current cpu only or not.
947          * Also remove current cpu from interrupt target register for all
948          * interrupts.
949          */
950         for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
951
952                 Target_Cpu = XScuGic_DistReadReg(InstancePtr,
953                                                                         XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
954                 if ((Target_Cpu != LocalCpuID) && (Target_Cpu!= 0)) {
955                         /*
956                          * If any other CPU is also programmed to target register, GIC
957                          * distributor can not be disabled.
958                          */
959                         DistDisable = 0;
960                 }
961
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);
966
967         }
968
969         /*
970          * If GIC distributor is safe to be disabled, disable all the interrupt
971          * and then disable distributor.
972          */
973         if ( DistDisable == 1) {
974                 for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) {
975                         /*
976                          * Disable all the interrupts
977                          */
978                         XScuGic_DistWriteReg(InstancePtr,
979                                                         XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET,
980                                                         Int_Id),
981                         0xFFFFFFFFU);
982                 }
983                 XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U);
984         }
985 }
986
987 /****************************************************************************/
988 /**
989 * This updates the CpuId global variable.
990 *
991 * @param        CpuCoreId is the CPU core number.
992 *
993 * @return       None.
994 *
995 * @note         None
996 *
997 *****************************************************************************/
998 void XScuGic_SetCpuID(u32 CpuCoreId)
999 {
1000         Xil_AssertVoid(CpuCoreId <= 1U);
1001
1002         CpuId = CpuCoreId;
1003 }
1004
1005 /****************************************************************************/
1006 /**
1007 * This function returns the CpuId variable.
1008 *
1009 * @param        None.
1010 *
1011 * @return       The CPU core number.
1012 *
1013 * @note        None.
1014 *
1015 *****************************************************************************/
1016 u32 XScuGic_GetCpuID(void)
1017 {
1018         return CpuId;
1019 }
1020 /** @} */