]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A53_64-bit_UltraScale_MPSoC/RTOSDemo_A53_bsp/psu_cortexa53_0/libsrc/scugic_v3_5/src/xscugic.c
xTaskGenericNotify() now sets xYieldPending to pdTRUE even when the 'higher priority...
[freertos] / FreeRTOS / Demo / CORTEX_A53_64-bit_UltraScale_MPSoC / RTOSDemo_A53_bsp / psu_cortexa53_0 / libsrc / scugic_v3_5 / src / xscugic.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2010 - 2016 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_1
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 *
111 *
112 * </pre>
113 *
114 ******************************************************************************/
115
116 /***************************** Include Files *********************************/
117 #include "xil_types.h"
118 #include "xil_assert.h"
119 #include "xscugic.h"
120
121 /************************** Constant Definitions *****************************/
122
123
124 /**************************** Type Definitions *******************************/
125
126
127 /***************** Macros (Inline Functions) Definitions *********************/
128
129 /************************** Variable Definitions *****************************/
130
131 /************************** Function Prototypes ******************************/
132
133 static void StubHandler(void *CallBackRef);
134
135 /*****************************************************************************/
136 /**
137 *
138 * DoDistributorInit initializes the distributor of the GIC. The
139 * initialization entails:
140 *
141 * - Write the trigger mode, priority and target CPU
142 * - All interrupt sources are disabled
143 * - Enable the distributor
144 *
145 * @param        InstancePtr is a pointer to the XScuGic instance.
146 * @param        CpuID is the Cpu ID to be initialized.
147 *
148 * @return       None
149 *
150 * @note         None.
151 *
152 ******************************************************************************/
153 static void DoDistributorInit(XScuGic *InstancePtr, u32 CpuID)
154 {
155         u32 Int_Id;
156         u32 LocalCpuID = CpuID;
157
158         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U);
159
160         /*
161          * Set the security domains in the int_security registers for
162          * non-secure interrupts
163          * All are secure, so leave at the default. Set to 1 for non-secure
164          * interrupts.
165          */
166
167         /*
168          * For the Shared Peripheral Interrupts INT_ID[MAX..32], set:
169          */
170
171         /*
172          * 1. The trigger mode in the int_config register
173          * Only write to the SPI interrupts, so start at 32
174          */
175         for (Int_Id = 32U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+16U) {
176                 /*
177                  * Each INT_ID uses two bits, or 16 INT_ID per register
178                  * Set them all to be level sensitive, active HIGH.
179                  */
180                 XScuGic_DistWriteReg(InstancePtr,
181                                         XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
182                                         0U);
183         }
184
185
186 #define DEFAULT_PRIORITY    0xa0a0a0a0U
187         for (Int_Id = 0U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+4U) {
188                 /*
189                  * 2. The priority using int the priority_level register
190                  * The priority_level and spi_target registers use one byte per
191                  * INT_ID.
192                  * Write a default value that can be changed elsewhere.
193                  */
194                 XScuGic_DistWriteReg(InstancePtr,
195                                         XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
196                                         DEFAULT_PRIORITY);
197         }
198
199         for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
200                 /*
201                  * 3. The CPU interface in the spi_target register
202                  * Only write to the SPI interrupts, so start at 32
203                  */
204                 LocalCpuID |= LocalCpuID << 8U;
205                 LocalCpuID |= LocalCpuID << 16U;
206
207                 XScuGic_DistWriteReg(InstancePtr,
208                                          XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
209                                          LocalCpuID);
210         }
211
212         for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) {
213                 /*
214                  * 4. Enable the SPI using the enable_set register. Leave all
215                  * disabled for now.
216                  */
217                 XScuGic_DistWriteReg(InstancePtr,
218                 XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET, Int_Id),
219                         0xFFFFFFFFU);
220
221         }
222
223         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET,
224                                         XSCUGIC_EN_INT_MASK);
225 }
226
227 /*****************************************************************************/
228 /**
229 *
230 * DistributorInit initializes the distributor of the GIC. It calls
231 * DoDistributorInit to finish the initialization.
232 *
233 * @param        InstancePtr is a pointer to the XScuGic instance.
234 * @param        CpuID is the Cpu ID to be initialized.
235 *
236 * @return       None
237 *
238 * @note         None.
239 *
240 ******************************************************************************/
241 static void DistributorInit(XScuGic *InstancePtr, u32 CpuID)
242 {
243         u32 Int_Id;
244         u32 LocalCpuID = CpuID;
245         u32 RegValue;
246
247 #if USE_AMP==1 && (defined (ARMA9) || defined(__aarch64__))
248 #warning "Building GIC for AMP"
249         /*
250          * GIC initialization is taken care by master CPU in
251          * openamp configuration, so do nothing and return.
252          */
253         return;
254 #endif
255
256         RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET);
257         if (!(RegValue & XSCUGIC_EN_INT_MASK)) {
258                 Xil_AssertVoid(InstancePtr != NULL);
259                 DoDistributorInit(InstancePtr, CpuID);
260                 return;
261         }
262
263         /*
264          * The overall distributor should not be initialized in AMP case where
265          * another CPU is taking care of it.
266          */
267         LocalCpuID |= LocalCpuID << 8U;
268         LocalCpuID |= LocalCpuID << 16U;
269         for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) {
270                 RegValue = XScuGic_DistReadReg(InstancePtr,
271                                                 XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
272                 RegValue |= LocalCpuID;
273                 XScuGic_DistWriteReg(InstancePtr,
274                                      XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
275                                      RegValue);
276         }
277 }
278
279 /*****************************************************************************/
280 /**
281 *
282 * CPUInitialize initializes the CPU Interface of the GIC. The initialization entails:
283 *
284 *       - Set the priority of the CPU
285 *       - Enable the CPU interface
286 *
287 * @param        InstancePtr is a pointer to the XScuGic instance.
288 *
289 * @return       None
290 *
291 * @note         None.
292 *
293 ******************************************************************************/
294 static void CPUInitialize(XScuGic *InstancePtr)
295 {
296         /*
297          * Program the priority mask of the CPU using the Priority mask register
298          */
299         XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CPU_PRIOR_OFFSET, 0xF0U);
300
301
302         /*
303          * If the CPU operates in both security domains, set parameters in the
304          * control_s register.
305          * 1. Set FIQen=1 to use FIQ for secure interrupts,
306          * 2. Program the AckCtl bit
307          * 3. Program the SBPR bit to select the binary pointer behavior
308          * 4. Set EnableS = 1 to enable secure interrupts
309          * 5. Set EnbleNS = 1 to enable non secure interrupts
310          */
311
312         /*
313          * If the CPU operates only in the secure domain, setup the
314          * control_s register.
315          * 1. Set FIQen=1,
316          * 2. Set EnableS=1, to enable the CPU interface to signal secure interrupts.
317          * Only enable the IRQ output unless secure interrupts are needed.
318          */
319         XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_CONTROL_OFFSET, 0x07U);
320
321 }
322
323 /*****************************************************************************/
324 /**
325 *
326 * CfgInitialize a specific interrupt controller instance/driver. The
327 * initialization entails:
328 *
329 * - Initialize fields of the XScuGic structure
330 * - Initial vector table with stub function calls
331 * - All interrupt sources are disabled
332 *
333 * @param        InstancePtr is a pointer to the XScuGic instance.
334 * @param        ConfigPtr is a pointer to a config table for the particular
335 *               device this driver is associated with.
336 * @param        EffectiveAddr is the device base address in the virtual memory
337 *               address space. The caller is responsible for keeping the address
338 *               mapping from EffectiveAddr to the device physical base address
339 *               unchanged once this function is invoked. Unexpected errors may
340 *               occur if the address mapping changes after this function is
341 *               called. If address translation is not used, use
342 *               Config->BaseAddress for this parameters, passing the physical
343 *               address instead.
344 *
345 * @return
346 *               - XST_SUCCESS if initialization was successful
347 *
348 * @note         None.
349 *
350 ******************************************************************************/
351 s32  XScuGic_CfgInitialize(XScuGic *InstancePtr,
352                                 XScuGic_Config *ConfigPtr,
353                                 u32 EffectiveAddr)
354 {
355         u32 Int_Id;
356         u32 Cpu_Id = (u32)XPAR_CPU_ID + (u32)1;
357         (void) EffectiveAddr;
358
359         Xil_AssertNonvoid(InstancePtr != NULL);
360         Xil_AssertNonvoid(ConfigPtr != NULL);
361         /*
362      * Detect Zynq-7000 base silicon configuration,Dual or Single CPU.
363      * If it is single CPU cnfiguration then invoke assert for CPU ID=1
364          */
365 #ifdef ARMA9
366         if ( XPAR_CPU_ID == 0x01 )
367         {
368                 Xil_AssertNonvoid((Xil_In32(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)
369                  & EFUSE_STATUS_CPU_MASK ) == 0);
370         }
371 #endif
372
373         if(InstancePtr->IsReady != XIL_COMPONENT_IS_READY) {
374
375                 InstancePtr->IsReady = 0U;
376                 InstancePtr->Config = ConfigPtr;
377
378
379                 for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id++) {
380                         /*
381                         * Initalize the handler to point to a stub to handle an
382                         * interrupt which has not been connected to a handler. Only
383                         * initialize it if the handler is 0 which means it was not
384                         * initialized statically by the tools/user. Set the callback
385                         * reference to this instance so that unhandled interrupts
386                         * can be tracked.
387                         */
388                         if      ((InstancePtr->Config->HandlerTable[Int_Id].Handler == NULL)) {
389                                 InstancePtr->Config->HandlerTable[Int_Id].Handler =
390                                                                         StubHandler;
391                         }
392                         InstancePtr->Config->HandlerTable[Int_Id].CallBackRef =
393                                                                 InstancePtr;
394                 }
395
396                 DistributorInit(InstancePtr, Cpu_Id);
397                 CPUInitialize(InstancePtr);
398
399                 InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
400         }
401
402         return XST_SUCCESS;
403 }
404
405 /*****************************************************************************/
406 /**
407 *
408 * Makes the connection between the Int_Id of the interrupt source and the
409 * associated handler that is to run when the interrupt is recognized. The
410 * argument provided in this call as the Callbackref is used as the argument
411 * for the handler when it is called.
412 *
413 * @param        InstancePtr is a pointer to the XScuGic instance.
414 * @param        Int_Id contains the ID of the interrupt source and should be
415 *               in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
416 * @param        Handler to the handler for that interrupt.
417 * @param        CallBackRef is the callback reference, usually the instance
418 *               pointer of the connecting driver.
419 *
420 * @return
421 *
422 *               - XST_SUCCESS if the handler was connected correctly.
423 *
424 * @note
425 *
426 * WARNING: The handler provided as an argument will overwrite any handler
427 * that was previously connected.
428 *
429 ****************************************************************************/
430 s32  XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
431                       Xil_InterruptHandler Handler, void *CallBackRef)
432 {
433         /*
434          * Assert the arguments
435          */
436         Xil_AssertNonvoid(InstancePtr != NULL);
437         Xil_AssertNonvoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
438         Xil_AssertNonvoid(Handler != NULL);
439         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
440
441         /*
442          * The Int_Id is used as an index into the table to select the proper
443          * handler
444          */
445         InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler;
446         InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;
447
448         return XST_SUCCESS;
449 }
450
451 /*****************************************************************************/
452 /**
453 *
454 * Updates the interrupt table with the Null Handler and NULL arguments at the
455 * location pointed at by the Int_Id. This effectively disconnects that interrupt
456 * source from any handler. The interrupt is disabled also.
457 *
458 * @param        InstancePtr is a pointer to the XScuGic instance to be worked on.
459 * @param        Int_Id contains the ID of the interrupt source and should
460 *               be in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
461 *
462 * @return       None.
463 *
464 * @note         None.
465 *
466 ****************************************************************************/
467 void XScuGic_Disconnect(XScuGic *InstancePtr, u32 Int_Id)
468 {
469         u32 Mask;
470
471         /*
472          * Assert the arguments
473          */
474         Xil_AssertVoid(InstancePtr != NULL);
475         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
476         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
477
478         /*
479          * The Int_Id is used to create the appropriate mask for the
480          * desired bit position. Int_Id currently limited to 0 - 31
481          */
482         Mask = 0x00000001U << (Int_Id % 32U);
483
484         /*
485          * Disable the interrupt such that it won't occur while disconnecting
486          * the handler, only disable the specified interrupt id without modifying
487          * the other interrupt ids
488          */
489         XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
490                                                 ((Int_Id / 32U) * 4U), Mask);
491
492         /*
493          * Disconnect the handler and connect a stub, the callback reference
494          * must be set to this instance to allow unhandled interrupts to be
495          * tracked
496          */
497         InstancePtr->Config->HandlerTable[Int_Id].Handler = StubHandler;
498         InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = InstancePtr;
499 }
500
501 /*****************************************************************************/
502 /**
503 *
504 * Enables the interrupt source provided as the argument Int_Id. Any pending
505 * interrupt condition for the specified Int_Id will occur after this function is
506 * called.
507 *
508 * @param        InstancePtr is a pointer to the XScuGic instance.
509 * @param        Int_Id contains the ID of the interrupt source and should be
510 *               in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
511 *
512 * @return       None.
513 *
514 * @note         None.
515 *
516 ****************************************************************************/
517 void XScuGic_Enable(XScuGic *InstancePtr, u32 Int_Id)
518 {
519         u32 Mask;
520
521         /*
522          * Assert the arguments
523          */
524         Xil_AssertVoid(InstancePtr != NULL);
525         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
526         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
527
528         /*
529          * The Int_Id is used to create the appropriate mask for the
530          * desired bit position. Int_Id currently limited to 0 - 31
531          */
532         Mask = 0x00000001U << (Int_Id % 32U);
533
534         /*
535          * Enable the selected interrupt source by setting the
536          * corresponding bit in the Enable Set register.
537          */
538         XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_ENABLE_SET_OFFSET +
539                                                 ((Int_Id / 32U) * 4U), Mask);
540 }
541
542 /*****************************************************************************/
543 /**
544 *
545 * Disables the interrupt source provided as the argument Int_Id such that the
546 * interrupt controller will not cause interrupts for the specified Int_Id. The
547 * interrupt controller will continue to hold an interrupt condition for the
548 * Int_Id, but will not cause an interrupt.
549 *
550 * @param        InstancePtr is a pointer to the XScuGic instance.
551 * @param        Int_Id contains the ID of the interrupt source and should be
552 *               in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
553 *
554 * @return       None.
555 *
556 * @note         None.
557 *
558 ****************************************************************************/
559 void XScuGic_Disable(XScuGic *InstancePtr, u32 Int_Id)
560 {
561         u32 Mask;
562
563         /*
564          * Assert the arguments
565          */
566         Xil_AssertVoid(InstancePtr != NULL);
567         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
568         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
569
570         /*
571          * The Int_Id is used to create the appropriate mask for the
572          * desired bit position. Int_Id currently limited to 0 - 31
573          */
574         Mask = 0x00000001U << (Int_Id % 32U);
575
576         /*
577          * Disable the selected interrupt source by setting the
578          * corresponding bit in the IDR.
579          */
580         XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET +
581                                                 ((Int_Id / 32U) * 4U), Mask);
582 }
583
584 /*****************************************************************************/
585 /**
586 *
587 * Allows software to simulate an interrupt in the interrupt controller.  This
588 * function will only be successful when the interrupt controller has been
589 * started in simulation mode.  A simulated interrupt allows the interrupt
590 * controller to be tested without any device to drive an interrupt input
591 * signal into it.
592 *
593 * @param        InstancePtr is a pointer to the XScuGic instance.
594 * @param        Int_Id is the software interrupt ID to simulate an interrupt.
595 * @param        Cpu_Id is the list of CPUs to send the interrupt.
596 *
597 * @return
598 *
599 * XST_SUCCESS if successful, or XST_FAILURE if the interrupt could not be
600 * simulated
601 *
602 * @note         None.
603 *
604 ******************************************************************************/
605 s32  XScuGic_SoftwareIntr(XScuGic *InstancePtr, u32 Int_Id, u32 Cpu_Id)
606 {
607         u32 Mask;
608
609         /*
610          * Assert the arguments
611          */
612         Xil_AssertNonvoid(InstancePtr != NULL);
613         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
614         Xil_AssertNonvoid(Int_Id <= 15U) ;
615         Xil_AssertNonvoid(Cpu_Id <= 255U) ;
616
617
618         /*
619          * The Int_Id is used to create the appropriate mask for the
620          * desired interrupt. Int_Id currently limited to 0 - 15
621          * Use the target list for the Cpu ID.
622          */
623         Mask = ((Cpu_Id << 16U) | Int_Id) &
624                 (XSCUGIC_SFI_TRIG_CPU_MASK | XSCUGIC_SFI_TRIG_INTID_MASK);
625
626         /*
627          * Write to the Software interrupt trigger register. Use the appropriate
628          * CPU Int_Id.
629          */
630         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SFI_TRIG_OFFSET, Mask);
631
632         /* Indicate the interrupt was successfully simulated */
633
634         return XST_SUCCESS;
635 }
636
637 /*****************************************************************************/
638 /**
639 *
640 * A stub for the asynchronous callback. The stub is here in case the upper
641 * layers forget to set the handler.
642 *
643 * @param        CallBackRef is a pointer to the upper layer callback reference
644 *
645 * @return       None.
646 *
647 * @note         None.
648 *
649 ******************************************************************************/
650 static void StubHandler(void *CallBackRef) {
651         /*
652          * verify that the inputs are valid
653          */
654         Xil_AssertVoid(CallBackRef != NULL);
655
656         /*
657          * Indicate another unhandled interrupt for stats
658          */
659         ((XScuGic *)((void *)CallBackRef))->UnhandledInterrupts++;
660 }
661
662 /****************************************************************************/
663 /**
664 * Sets the interrupt priority and trigger type for the specificd IRQ source.
665 *
666 * @param        InstancePtr is a pointer to the instance to be worked on.
667 * @param        Int_Id is the IRQ source number to modify
668 * @param        Priority is the new priority for the IRQ source. 0 is highest
669 *                       priority, 0xF8 (248) is lowest. There are 32 priority levels
670 *                       supported with a step of 8. Hence the supported priorities are
671 *                       0, 8, 16, 32, 40 ..., 248.
672 * @param        Trigger is the new trigger type for the IRQ source.
673 * Each bit pair describes the configuration for an INT_ID.
674 * SFI    Read Only    b10 always
675 * PPI    Read Only    depending on how the PPIs are configured.
676 *                    b01    Active HIGH level sensitive
677 *                    b11 Rising edge sensitive
678 * SPI                LSB is read only.
679 *                    b01    Active HIGH level sensitive
680 *                    b11 Rising edge sensitive/
681 *
682 * @return       None.
683 *
684 * @note         None.
685 *
686 *****************************************************************************/
687 void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
688                                         u8 Priority, u8 Trigger)
689 {
690         u32 RegValue;
691         u8 LocalPriority;
692         LocalPriority = Priority;
693
694         Xil_AssertVoid(InstancePtr != NULL);
695         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
696         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
697         Xil_AssertVoid(Trigger <= (u8)XSCUGIC_INT_CFG_MASK);
698         Xil_AssertVoid(LocalPriority <= (u8)XSCUGIC_MAX_INTR_PRIO_VAL);
699
700         /*
701          * Determine the register to write to using the Int_Id.
702          */
703         RegValue = XScuGic_DistReadReg(InstancePtr,
704                         XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
705
706         /*
707          * The priority bits are Bits 7 to 3 in GIC Priority Register. This
708          * means the number of priority levels supported are 32 and they are
709          * in steps of 8. The priorities can be 0, 8, 16, 32, 48, ... etc.
710          * The lower order 3 bits are masked before putting it in the register.
711          */
712         LocalPriority = LocalPriority & (u8)XSCUGIC_INTR_PRIO_MASK;
713         /*
714          * Shift and Mask the correct bits for the priority and trigger in the
715          * register
716          */
717         RegValue &= ~(XSCUGIC_PRIORITY_MASK << ((Int_Id%4U)*8U));
718         RegValue |= (u32)LocalPriority << ((Int_Id%4U)*8U);
719
720         /*
721          * Write the value back to the register.
722          */
723         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
724                                 RegValue);
725
726         /*
727          * Determine the register to write to using the Int_Id.
728          */
729         RegValue = XScuGic_DistReadReg(InstancePtr,
730                         XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
731
732         /*
733          * Shift and Mask the correct bits for the priority and trigger in the
734          * register
735          */
736         RegValue &= ~(XSCUGIC_INT_CFG_MASK << ((Int_Id%16U)*2U));
737         RegValue |= (u32)Trigger << ((Int_Id%16U)*2U);
738
739         /*
740          * Write the value back to the register.
741          */
742         XScuGic_DistWriteReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
743                                 RegValue);
744
745 }
746
747 /****************************************************************************/
748 /**
749 * Gets the interrupt priority and trigger type for the specificd IRQ source.
750 *
751 * @param        InstancePtr is a pointer to the instance to be worked on.
752 * @param        Int_Id is the IRQ source number to modify
753 * @param        Priority is a pointer to the value of the priority of the IRQ
754 *               source. This is a return value.
755 * @param        Trigger is pointer to the value of the trigger of the IRQ
756 *               source. This is a return value.
757 *
758 * @return       None.
759 *
760 * @note         None
761 *
762 *****************************************************************************/
763 void XScuGic_GetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id,
764                                         u8 *Priority, u8 *Trigger)
765 {
766         u32 RegValue;
767
768         Xil_AssertVoid(InstancePtr != NULL);
769         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
770         Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
771         Xil_AssertVoid(Priority != NULL);
772         Xil_AssertVoid(Trigger != NULL);
773
774         /*
775          * Determine the register to read to using the Int_Id.
776          */
777         RegValue = XScuGic_DistReadReg(InstancePtr,
778             XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
779
780         /*
781          * Shift and Mask the correct bits for the priority and trigger in the
782          * register
783          */
784         RegValue = RegValue >> ((Int_Id%4U)*8U);
785         *Priority = (u8)(RegValue & XSCUGIC_PRIORITY_MASK);
786
787         /*
788          * Determine the register to read to using the Int_Id.
789          */
790         RegValue = XScuGic_DistReadReg(InstancePtr,
791         XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id));
792
793         /*
794          * Shift and Mask the correct bits for the priority and trigger in the
795          * register
796          */
797         RegValue = RegValue >> ((Int_Id%16U)*2U);
798
799         *Trigger = (u8)(RegValue & XSCUGIC_INT_CFG_MASK);
800 }
801 /****************************************************************************/
802 /**
803 * Sets the target CPU for the interrupt of a peripheral
804 *
805 * @param        InstancePtr is a pointer to the instance to be worked on.
806 * @param        Cpu_Id is a CPU number for which the interrupt has to be targeted
807 * @param        Int_Id is the IRQ source number to modify
808 *
809 * @return       None.
810 *
811 * @note         None
812 *
813 *****************************************************************************/
814 void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id)
815 {
816         u32 RegValue, Offset;
817         RegValue = XScuGic_DistReadReg(InstancePtr,
818                         XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
819
820         Offset = (Int_Id & 0x3U);
821         Cpu_Id = (0x1U << Cpu_Id);
822
823         RegValue = (RegValue & (~(0xFFU << (Offset*8U))) );
824         RegValue |= ((Cpu_Id) << (Offset*8U));
825
826         XScuGic_DistWriteReg(InstancePtr,
827                                                  XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
828                                                  RegValue);
829 }
830 /** @} */