blob: 06d9ced3c5d20d2b366020bf6a275a4ee409a49c [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2015 - 2016 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_v2_3
* @{
*
* This file contains the implementation of the interface functions for XIpiPsu
* driver. Refer to the header file xipipsu.h for more detailed information.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ------ -------- ----------------------------------------------
* 1.00 mjr 03/15/15 First Release
* 2.0 mjr 01/22/16 Fixed response buffer address
* calculation. CR# 932582.
* 2.1 kvn 05/05/16 Modified code for MISRA-C:2012 Compliance
* 2.2 kvn 02/17/17 Add support for updating ConfigTable at run time
* </pre>
*
*****************************************************************************/
/***************************** Include Files ********************************/
#include "xipipsu.h"
#include "xipipsu_hw.h"
/************************** Variable Definitions *****************************/
extern XIpiPsu_Config XIpiPsu_ConfigTable[XPAR_XIPIPSU_NUM_INSTANCES];
/****************************************************************************/
/**
* 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 = 0U; 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 = 0U;
/* 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 + 1U;
/*Search for CPU in the List */
for (Index = 0U; 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
+ (DestIndex * XIPIPSU_BUFFER_OFFSET_GROUP)
+ (SrcIndex * 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 BufferType 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 SrcCpuMask, u32 *MsgPtr,
u32 MsgLength, u8 BufferType)
{
u32 *BufferPtr;
u32 Index;
XStatus 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, SrcCpuMask,
InstancePtr->Config.BitMask, BufferType);
if (BufferPtr != NULL) {
/* Copy the IPI Buffer contents into Users's Buffer*/
for (Index = 0U; 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 BufferType 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 DestCpuMask, u32 *MsgPtr,
u32 MsgLength, u8 BufferType)
{
u32 *BufferPtr;
u32 Index;
XStatus 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, DestCpuMask, BufferType);
if (BufferPtr != NULL) {
/* Copy the Message to IPI Buffer */
for (Index = 0U; Index < MsgLength; Index++) {
BufferPtr[Index] = MsgPtr[Index];
}
Status = XST_SUCCESS;
} else {
Status = XST_FAILURE;
}
return Status;
}
/*****************************************************************************/
/**
*
* Set up the device configuration based on the unique device ID. A table
* contains the configuration info for each device in the system.
*
* @param DeviceId contains the ID of the device to set up the
* configuration for.
*
* @return A pointer to the device configuration for the specified
* device ID. See xipipsu.h for the definition of
* XIpiPsu_Config.
*
* @note This is for safety use case where in this function has to
* be called before CfgInitialize. So that driver will be
* initialized with the provided configuration. For non-safe
* use cases, this is not needed.
*
******************************************************************************/
void XIpiPsu_SetConfigTable(u32 DeviceId, XIpiPsu_Config *ConfigTblPtr)
{
u32 Index;
Xil_AssertVoid(ConfigTblPtr != NULL);
for (Index = 0U; Index < XPAR_XIPIPSU_NUM_INSTANCES; Index++) {
if (XIpiPsu_ConfigTable[Index].DeviceId == DeviceId) {
XIpiPsu_ConfigTable[Index].BaseAddress = ConfigTblPtr->BaseAddress;
XIpiPsu_ConfigTable[Index].BitMask = ConfigTblPtr->BitMask;
XIpiPsu_ConfigTable[Index].BufferIndex = ConfigTblPtr->BufferIndex;
XIpiPsu_ConfigTable[Index].IntId = ConfigTblPtr->IntId;
}
}
}
/** @} */