/** * Sets the interrupt priority and trigger type for the specificd IRQ source. * * @param InstancePtr is a pointer to the instance to be worked on. * @param Int_Id is the IRQ source number to modify * @param Priority is the new priority for the IRQ source. 0 is highest * priority, 0xF8 (248) is lowest. There are 32 priority levels * supported with a step of 8. Hence the supported priorities are * 0, 8, 16, 32, 40 ..., 248. * @param Trigger is the new trigger type for the IRQ source. * Each bit pair describes the configuration for an INT_ID. * SFI Read Only b10 always * PPI Read Only depending on how the PPIs are configured. * b01 Active HIGH level sensitive * b11 Rising edge sensitive * SPI LSB is read only. * b01 Active HIGH level sensitive * b11 Rising edge sensitive/ * * @return None. * * @note None. * *****************************************************************************/ void XScuGic_SetPriorityTriggerType(XScuGic *InstancePtr, u32 Int_Id, u8 Priority, u8 Trigger) { u32 RegValue; u8 LocalPriority; LocalPriority = Priority; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS); Xil_AssertVoid(Trigger <= (u8)XSCUGIC_INT_CFG_MASK); Xil_AssertVoid(LocalPriority <= (u8)XSCUGIC_MAX_INTR_PRIO_VAL); /* * Determine the register to write to using the Int_Id. */ RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id)); /* * The priority bits are Bits 7 to 3 in GIC Priority Register. This * means the number of priority levels supported are 32 and they are * in steps of 8. The priorities can be 0, 8, 16, 32, 48, ... etc. * The lower order 3 bits are masked before putting it in the register. */ LocalPriority = LocalPriority & (u8)XSCUGIC_INTR_PRIO_MASK; /* * Shift and Mask the correct bits for the priority and trigger in the * register */ RegValue &= ~(XSCUGIC_PRIORITY_MASK << ((Int_Id%4U)*8U)); RegValue |= (u32)LocalPriority << ((Int_Id%4U)*8U); /* * Write the value back to the register. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id), RegValue); /* * Determine the register to write to using the Int_Id. */ RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC (Int_Id)); /* * Shift and Mask the correct bits for the priority and trigger in the * register */ RegValue &= ~(XSCUGIC_INT_CFG_MASK << ((Int_Id%16U)*2U)); RegValue |= (u32)Trigger << ((Int_Id%16U)*2U); /* * Write the value back to the register. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id), RegValue); }
/** * * Allows software to simulate an interrupt in the interrupt controller. This * function will only be successful when the interrupt controller has been * started in simulation mode. A simulated interrupt allows the interrupt * controller to be tested without any device to drive an interrupt input * signal into it. * * @param InstancePtr is a pointer to the XScuGic instance. * @param Int_Id is the software interrupt ID to simulate an interrupt. * @param Cpu_Id is the list of CPUs to send the interrupt. * * @return * * XST_SUCCESS if successful, or XST_FAILURE if the interrupt could not be * simulated * * @note None. * ******************************************************************************/ s32 XScuGic_SoftwareIntr(XScuGic *InstancePtr, u32 Int_Id, u32 Cpu_Id) { u32 Mask; /* * Assert the arguments */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(Int_Id <= 15U) ; Xil_AssertNonvoid(Cpu_Id <= 255U) ; /* * The Int_Id is used to create the appropriate mask for the * desired interrupt. Int_Id currently limited to 0 - 15 * Use the target list for the Cpu ID. */ Mask = ((Cpu_Id << 16U) | Int_Id) & (XSCUGIC_SFI_TRIG_CPU_MASK | XSCUGIC_SFI_TRIG_INTID_MASK); /* * Write to the Software interrupt trigger register. Use the appropriate * CPU Int_Id. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SFI_TRIG_OFFSET, Mask); /* Indicate the interrupt was successfully simulated */ return XST_SUCCESS; }
/** * * Updates the interrupt table with the Null Handler and NULL arguments at the * location pointed at by the Int_Id. This effectively disconnects that interrupt * source from any handler. The interrupt is disabled also. * * @param InstancePtr is a pointer to the XScuGic instance to be worked on. * @param Int_Id contains the ID of the interrupt source and should * be in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1 * * @return None. * * @note None. * ****************************************************************************/ void XScuGic_Disconnect(XScuGic *InstancePtr, u32 Int_Id) { u32 Mask; /* * Assert the arguments */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * The Int_Id is used to create the appropriate mask for the * desired bit position. Int_Id currently limited to 0 - 31 */ Mask = 0x00000001U << (Int_Id % 32U); /* * Disable the interrupt such that it won't occur while disconnecting * the handler, only disable the specified interrupt id without modifying * the other interrupt ids */ XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET + ((Int_Id / 32U) * 4U), Mask); /* * Disconnect the handler and connect a stub, the callback reference * must be set to this instance to allow unhandled interrupts to be * tracked */ InstancePtr->Config->HandlerTable[Int_Id].Handler = StubHandler; InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = InstancePtr; }
/** * Sets the target CPU for the interrupt of a peripheral * * @param InstancePtr is a pointer to the instance to be worked on. * @param Cpu_Id is a CPU number for which the interrupt has to be targeted * @param Int_Id is the IRQ source number to modify * * @return None. * * @note None * *****************************************************************************/ void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Id, u32 Int_Id) { u32 RegValue, Offset; RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id)); Offset = (Int_Id & 0x3); RegValue = (RegValue | (~(0xFF << (Offset*8))) ); RegValue |= ((Cpu_Id) << (Offset*8)); XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), RegValue); }
/** * * Disables the interrupt source provided as the argument Int_Id such that the * interrupt controller will not cause interrupts for the specified Int_Id. The * interrupt controller will continue to hold an interrupt condition for the * Int_Id, but will not cause an interrupt. * * @param InstancePtr is a pointer to the XScuGic instance. * @param Int_Id contains the ID of the interrupt source and should be * in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1 * * @return None. * * @note None. * ****************************************************************************/ void XScuGic_Disable(XScuGic *InstancePtr, u32 Int_Id) { u32 Mask; /* * Assert the arguments */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * The Int_Id is used to create the appropriate mask for the * desired bit position. Int_Id currently limited to 0 - 31 */ Mask = 0x00000001U << (Int_Id % 32U); /* * Disable the selected interrupt source by setting the * corresponding bit in the IDR. */ XScuGic_DistWriteReg(InstancePtr, (u32)XSCUGIC_DISABLE_OFFSET + ((Int_Id / 32U) * 4U), Mask); }
/** * * DistributorInit initializes the distributor of the GIC. The * initialization entails: * * - Write the trigger mode, priority and target CPU * - All interrupt sources are disabled * - Enable the distributor * * @param InstancePtr is a pointer to the XScuGic instance. * @param CpuID is the Cpu ID to be initialized. * * @return None * * @note None. * ******************************************************************************/ static void DistributorInit(XScuGic *InstancePtr, u32 CpuID) { u32 Int_Id; u32 LocalCpuID = CpuID; #if USE_AMP==1 #warning "Building GIC for AMP" #ifdef ARMR5 u32 RegValue; /* * The overall distributor should not be initialized in AMP case where * another CPU is taking care of it. */ LocalCpuID |= LocalCpuID << 8U; LocalCpuID |= LocalCpuID << 16U; for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) { RegValue = XScuGic_DistReadReg(InstancePtr, XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id)); RegValue |= LocalCpuID; XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), RegValue); } #endif return; #endif Xil_AssertVoid(InstancePtr != NULL); XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0U); /* * Set the security domains in the int_security registers for * non-secure interrupts * All are secure, so leave at the default. Set to 1 for non-secure * interrupts. */ /* * For the Shared Peripheral Interrupts INT_ID[MAX..32], set: */ /* * 1. The trigger mode in the int_config register * Only write to the SPI interrupts, so start at 32 */ for (Int_Id = 32U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+16U) { /* * Each INT_ID uses two bits, or 16 INT_ID per register * Set them all to be level sensitive, active HIGH. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id), 0U); } #define DEFAULT_PRIORITY 0xa0a0a0a0U for (Int_Id = 0U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id=Int_Id+4U) { /* * 2. The priority using int the priority_level register * The priority_level and spi_target registers use one byte per * INT_ID. * Write a default value that can be changed elsewhere. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id), DEFAULT_PRIORITY); } for (Int_Id = 32U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+4U) { /* * 3. The CPU interface in the spi_target register * Only write to the SPI interrupts, so start at 32 */ LocalCpuID |= LocalCpuID << 8U; LocalCpuID |= LocalCpuID << 16U; XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), LocalCpuID); } for (Int_Id = 0U; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id=Int_Id+32U) { /* * 4. Enable the SPI using the enable_set register. Leave all * disabled for now. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_EN_DIS_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET, Int_Id), 0xFFFFFFFFU); } XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, XSCUGIC_EN_INT_MASK); }
/** * * DistInit initializes the distributor of the GIC. The * initialization entails: * * - Write the trigger mode, priority and target CPU * - All interrupt sources are disabled * - Enable the distributor * * @param InstancePtr is a pointer to the XScuGic instance. * @param CpuID is the Cpu ID to be initialized. * * @return None * * @note None. * ******************************************************************************/ static void DistInit(XScuGic *InstancePtr, u32 CpuID) { u32 Int_Id; #if USE_AMP==1 #warning "Building GIC for AMP" /* * The distrubutor should not be initialized by FreeRTOS in the case of * AMP -- it is assumed that Linux is the master of this device in that * case. */ return; #endif XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, 0UL); /* * Set the security domains in the int_security registers for * non-secure interrupts * All are secure, so leave at the default. Set to 1 for non-secure * interrupts. */ /* * For the Shared Peripheral Interrupts INT_ID[MAX..32], set: */ /* * 1. The trigger mode in the int_config register * Only write to the SPI interrupts, so start at 32 */ for (Int_Id = 32; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id+=16) { /* * Each INT_ID uses two bits, or 16 INT_ID per register * Set them all to be level sensitive, active HIGH. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id), 0UL); } #define DEFAULT_PRIORITY 0xa0a0a0a0UL for (Int_Id = 0; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS; Int_Id+=4) { /* * 2. The priority using int the priority_level register * The priority_level and spi_target registers use one byte per * INT_ID. * Write a default value that can be changed elsewhere. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id), DEFAULT_PRIORITY); } for (Int_Id = 32; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id+=4) { /* * 3. The CPU interface in the spi_target register * Only write to the SPI interrupts, so start at 32 */ CpuID |= CpuID << 8; CpuID |= CpuID << 16; XScuGic_DistWriteReg(InstancePtr, XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id), CpuID); } for (Int_Id = 0; Int_Id<XSCUGIC_MAX_NUM_INTR_INPUTS;Int_Id+=32) { /* * 4. Enable the SPI using the enable_set register. Leave all * disabled for now. */ XScuGic_DistWriteReg(InstancePtr, XSCUGIC_ENABLE_DISABLE_OFFSET_CALC(XSCUGIC_DISABLE_OFFSET, Int_Id), 0xFFFFFFFFUL); } XScuGic_DistWriteReg(InstancePtr, XSCUGIC_DIST_EN_OFFSET, XSCUGIC_EN_INT_MASK); }