/****************************************************************************** * * Copyright (C) 2015 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /****************************************************************************/ /** * * @file xipipsu.c * @addtogroup ipipsu_v1_0 * @{ * * This file contains the implementation of the interface functions for XIpiPsu * driver. Refer to the header file xipipsu.h for more detailed information. * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ------ -------- ---------------------------------------------- * 1.00 mjr 03/15/15 First Release ** *****************************************************************************/ /***************************** Include Files ********************************/ #include "xipipsu.h" #include "xipipsu_hw.h" /****************************************************************************/ /** * Initialize the Instance pointer based on a given Config Pointer * * @param InstancePtr is a pointer to the instance to be worked on * @param CfgPtr is the device configuration structure containing required * hardware build data * @param EffectiveAddress is the base address of the device. If address * translation is not utilized, this parameter can be passed in using * CfgPtr->Config.BaseAddress to specify the physical base address. * @return XST_SUCCESS if initialization was successful * XST_FAILURE in case of failure * */ XStatus XIpiPsu_CfgInitialize(XIpiPsu *InstancePtr, XIpiPsu_Config * CfgPtr, UINTPTR EffectiveAddress) { u32 Index; /* Verify arguments */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(CfgPtr != NULL); /* Set device base address and ID */ InstancePtr->Config.DeviceId = CfgPtr->DeviceId; InstancePtr->Config.BaseAddress = EffectiveAddress; InstancePtr->Config.BitMask = CfgPtr->BitMask; InstancePtr->Config.IntId = CfgPtr->IntId; InstancePtr->Config.TargetCount = CfgPtr->TargetCount; for (Index = 0; Index < CfgPtr->TargetCount; Index++) { InstancePtr->Config.TargetList[Index].Mask = CfgPtr->TargetList[Index].Mask; InstancePtr->Config.TargetList[Index].BufferIndex = CfgPtr->TargetList[Index].BufferIndex; } /* Mark the component as Ready */ InstancePtr->IsReady = XIL_COMPONENT_IS_READY; return (XST_SUCCESS); } /** * @brief Reset the given IPI register set. * This function can be called to disable the IPIs from all * the sources and clear any pending IPIs in status register * * @param InstancePtr is the pointer to current IPI instance * */ void XIpiPsu_Reset(XIpiPsu *InstancePtr) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /**************Disable***************/ XIpiPsu_WriteReg(InstancePtr->Config.BaseAddress, XIPIPSU_IDR_OFFSET, XIPIPSU_ALL_MASK); /**************Clear***************/ XIpiPsu_WriteReg(InstancePtr->Config.BaseAddress, XIPIPSU_ISR_OFFSET, XIPIPSU_ALL_MASK); } /** * @brief Trigger an IPI to a Destination CPU * * @param InstancePtr is the pointer to current IPI instance * @param DestCpuMask is the Mask of the CPU to which IPI is to be triggered * * * @return XST_SUCCESS if successful * XST_FAILURE if an error occurred */ XStatus XIpiPsu_TriggerIpi(XIpiPsu *InstancePtr, u32 DestCpuMask) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* Trigger an IPI to the Target */ XIpiPsu_WriteReg(InstancePtr->Config.BaseAddress, XIPIPSU_TRIG_OFFSET, DestCpuMask); return XST_SUCCESS; } /** * @brief Poll for an acknowledgement using Observation Register * * @param InstancePtr is the pointer to current IPI instance * @param DestCpuMask is the Mask of the destination CPU from which ACK is expected * @param TimeOutCount is the Count after which the routines returns failure * * @return XST_SUCCESS if successful * XST_FAILURE if a timeout occurred */ XStatus XIpiPsu_PollForAck(XIpiPsu *InstancePtr, u32 DestCpuMask, u32 TimeOutCount) { u32 Flag, PollCount; XStatus Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); PollCount = 0; /* Poll the OBS register until the corresponding DestCpu bit is cleared */ do { Flag = (XIpiPsu_ReadReg(InstancePtr->Config.BaseAddress, XIPIPSU_OBS_OFFSET)) & (DestCpuMask); PollCount++; /* Check if the IPI was Acknowledged by the Target or we Timed Out*/ } while ((0x00000000U != Flag) && (PollCount < TimeOutCount)); if (PollCount >= TimeOutCount) { Status = XST_FAILURE; } else { Status = XST_SUCCESS; } return Status; } /** * @brief Get the Buffer Index for a CPU specified by Mask * * @param InstancePtr is the pointer to current IPI instance * @param CpuMask is the Mask of the CPU form which Index is required * * @return Buffer Index value if CPU Mask is valid * XIPIPSU_MAX_BUFF_INDEX+1 if not valid * * @note Static function used only by XIpiPsu_GetBufferAddress * */ static u32 XIpiPsu_GetBufferIndex(XIpiPsu *InstancePtr, u32 CpuMask) { u32 BufferIndex; u32 Index; /* Init Index with an invalid value */ BufferIndex = XIPIPSU_MAX_BUFF_INDEX + 1; /*Search for CPU in the List */ for (Index = 0; Index < InstancePtr->Config.TargetCount; Index++) { /*If we find the CPU , then set the Index and break the loop*/ if (InstancePtr->Config.TargetList[Index].Mask == CpuMask) { BufferIndex = InstancePtr->Config.TargetList[Index].BufferIndex; break; } } /* Return the Index */ return BufferIndex; } /** * @brief Get the Buffer Address for a given pair of CPUs * * @param InstancePtr is the pointer to current IPI instance * @param SrcCpuMask is the Mask for Source CPU * @param DestCpuMask is the Mask for Destination CPU * @param BufferType is either XIPIPSU_BUF_TYPE_MSG or XIPIPSU_BUF_TYPE_RESP * * @return Valid Buffer Address if no error * NULL if an error occurred in calculating Address * */ static u32* XIpiPsu_GetBufferAddress(XIpiPsu *InstancePtr, u32 SrcCpuMask, u32 DestCpuMask, u32 BufferType) { #ifdef __aarch64__ u64 BufferAddr; #else u32 BufferAddr; #endif u32 SrcIndex; u32 DestIndex; /* Get the buffer indices */ SrcIndex = XIpiPsu_GetBufferIndex(InstancePtr, SrcCpuMask); DestIndex = XIpiPsu_GetBufferIndex(InstancePtr, DestCpuMask); /* If we got an invalid buffer index, then return NULL pointer, else valid address */ if ((SrcIndex > XIPIPSU_MAX_BUFF_INDEX) || (DestIndex > XIPIPSU_MAX_BUFF_INDEX)) { BufferAddr = 0U; } else { if (XIPIPSU_BUF_TYPE_MSG == BufferType) { BufferAddr = XIPIPSU_MSG_RAM_BASE + (SrcIndex * XIPIPSU_BUFFER_OFFSET_GROUP) + (DestIndex * XIPIPSU_BUFFER_OFFSET_TARGET); } else if (XIPIPSU_BUF_TYPE_RESP == BufferType) { BufferAddr = XIPIPSU_MSG_RAM_BASE + (SrcIndex * XIPIPSU_BUFFER_OFFSET_GROUP) + (DestIndex * XIPIPSU_BUFFER_OFFSET_TARGET) + (XIPIPSU_BUFFER_OFFSET_RESPONSE); } else { BufferAddr = 0U; } } return (u32 *) BufferAddr; } /** * @brief Read an Incoming Message from a Source * * @param InstancePtr is the pointer to current IPI instance * @param SrcCpuMask is the Device Mask for the CPU which has sent the message * @param MsgPtr is the pointer to Buffer to which the read message needs to be stored * @param MsgLength is the length of the buffer/message * @param BufType is the type of buffer (XIPIPSU_BUF_TYPE_MSG or XIPIPSU_BUF_TYPE_RESP) * * @return XST_SUCCESS if successful * XST_FAILURE if an error occurred */ XStatus XIpiPsu_ReadMessage(XIpiPsu *InstancePtr, u32 TargetMask, u32 *MsgPtr, u32 MsgLength, u8 BufferType) { u32 *BufferPtr; u32 Index; u32 Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(MsgLength <= XIPIPSU_MAX_MSG_LEN); BufferPtr = XIpiPsu_GetBufferAddress(InstancePtr, TargetMask, InstancePtr->Config.BitMask, BufferType); if (BufferPtr != NULL) { /* Copy the IPI Buffer contents into Users's Buffer*/ for (Index = 0; Index < MsgLength; Index++) { MsgPtr[Index] = BufferPtr[Index]; } Status = XST_SUCCESS; } else { Status = XST_FAILURE; } return Status; } /** * @brief Send a Message to Destination * * @param InstancePtr is the pointer to current IPI instance * @param DestCpuMask is the Device Mask for the destination CPU * @param MsgPtr is the pointer to Buffer which contains the message to be sent * @param MsgLength is the length of the buffer/message * @param BufType is the type of buffer (XIPIPSU_BUF_TYPE_MSG or XIPIPSU_BUF_TYPE_RESP) * * @return XST_SUCCESS if successful * XST_FAILURE if an error occurred */ XStatus XIpiPsu_WriteMessage(XIpiPsu *InstancePtr, u32 TargetMask, u32 *MsgPtr, u32 MsgLength, u8 BufferType) { u32 *BufferPtr; u32 Index; u32 Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(MsgLength <= XIPIPSU_MAX_MSG_LEN); BufferPtr = XIpiPsu_GetBufferAddress(InstancePtr, InstancePtr->Config.BitMask, TargetMask, BufferType); if (BufferPtr != NULL) { /* Copy the Message to IPI Buffer */ for (Index = 0; Index < MsgLength; Index++) { BufferPtr[Index] = MsgPtr[Index]; } Status = XST_SUCCESS; } else { Status = XST_FAILURE; } return Status; } /** @} */