1 /******************************************************************************
3 * Copyright (C) 2015 - 2016 Xilinx, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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.
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
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.
31 ******************************************************************************/
32 /****************************************************************************/
36 * @addtogroup ipipsu_v2_3
39 * This file contains the implementation of the interface functions for XIpiPsu
40 * driver. Refer to the header file xipipsu.h for more detailed information.
43 * MODIFICATION HISTORY:
45 * Ver Who Date Changes
46 * ----- ------ -------- ----------------------------------------------
47 * 1.00 mjr 03/15/15 First Release
48 * 2.0 mjr 01/22/16 Fixed response buffer address
49 * calculation. CR# 932582.
50 * 2.1 kvn 05/05/16 Modified code for MISRA-C:2012 Compliance
51 * 2.2 kvn 02/17/17 Add support for updating ConfigTable at run time
54 *****************************************************************************/
56 /***************************** Include Files ********************************/
58 #include "xipipsu_hw.h"
60 /************************** Variable Definitions *****************************/
61 extern XIpiPsu_Config XIpiPsu_ConfigTable[XPAR_XIPIPSU_NUM_INSTANCES];
63 /****************************************************************************/
65 * Initialize the Instance pointer based on a given Config Pointer
67 * @param InstancePtr is a pointer to the instance to be worked on
68 * @param CfgPtr is the device configuration structure containing required
70 * @param EffectiveAddress is the base address of the device. If address
71 * translation is not utilized, this parameter can be passed in using
72 * CfgPtr->Config.BaseAddress to specify the physical base address.
73 * @return XST_SUCCESS if initialization was successful
74 * XST_FAILURE in case of failure
78 XStatus XIpiPsu_CfgInitialize(XIpiPsu *InstancePtr, XIpiPsu_Config * CfgPtr,
79 UINTPTR EffectiveAddress)
82 /* Verify arguments */
83 Xil_AssertNonvoid(InstancePtr != NULL);
84 Xil_AssertNonvoid(CfgPtr != NULL);
85 /* Set device base address and ID */
86 InstancePtr->Config.DeviceId = CfgPtr->DeviceId;
87 InstancePtr->Config.BaseAddress = EffectiveAddress;
88 InstancePtr->Config.BitMask = CfgPtr->BitMask;
89 InstancePtr->Config.IntId = CfgPtr->IntId;
91 InstancePtr->Config.TargetCount = CfgPtr->TargetCount;
93 for (Index = 0U; Index < CfgPtr->TargetCount; Index++) {
94 InstancePtr->Config.TargetList[Index].Mask =
95 CfgPtr->TargetList[Index].Mask;
96 InstancePtr->Config.TargetList[Index].BufferIndex =
97 CfgPtr->TargetList[Index].BufferIndex;
100 /* Mark the component as Ready */
101 InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
102 return (XST_SUCCESS);
106 * @brief Reset the given IPI register set.
107 * This function can be called to disable the IPIs from all
108 * the sources and clear any pending IPIs in status register
110 * @param InstancePtr is the pointer to current IPI instance
114 void XIpiPsu_Reset(XIpiPsu *InstancePtr)
117 Xil_AssertVoid(InstancePtr != NULL);
118 Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
120 /**************Disable***************/
122 XIpiPsu_WriteReg(InstancePtr->Config.BaseAddress, XIPIPSU_IDR_OFFSET,
125 /**************Clear***************/
126 XIpiPsu_WriteReg(InstancePtr->Config.BaseAddress, XIPIPSU_ISR_OFFSET,
132 * @brief Trigger an IPI to a Destination CPU
134 * @param InstancePtr is the pointer to current IPI instance
135 * @param DestCpuMask is the Mask of the CPU to which IPI is to be triggered
138 * @return XST_SUCCESS if successful
139 * XST_FAILURE if an error occurred
142 XStatus XIpiPsu_TriggerIpi(XIpiPsu *InstancePtr, u32 DestCpuMask)
145 Xil_AssertNonvoid(InstancePtr != NULL);
146 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
148 /* Trigger an IPI to the Target */
149 XIpiPsu_WriteReg(InstancePtr->Config.BaseAddress, XIPIPSU_TRIG_OFFSET,
156 * @brief Poll for an acknowledgement using Observation Register
158 * @param InstancePtr is the pointer to current IPI instance
159 * @param DestCpuMask is the Mask of the destination CPU from which ACK is expected
160 * @param TimeOutCount is the Count after which the routines returns failure
162 * @return XST_SUCCESS if successful
163 * XST_FAILURE if a timeout occurred
166 XStatus XIpiPsu_PollForAck(XIpiPsu *InstancePtr, u32 DestCpuMask,
172 Xil_AssertNonvoid(InstancePtr != NULL);
173 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
176 /* Poll the OBS register until the corresponding DestCpu bit is cleared */
178 Flag = (XIpiPsu_ReadReg(InstancePtr->Config.BaseAddress,
179 XIPIPSU_OBS_OFFSET)) & (DestCpuMask);
181 /* Check if the IPI was Acknowledged by the Target or we Timed Out*/
182 } while ((0x00000000U != Flag) && (PollCount < TimeOutCount));
184 if (PollCount >= TimeOutCount) {
185 Status = XST_FAILURE;
187 Status = XST_SUCCESS;
194 * @brief Get the Buffer Index for a CPU specified by Mask
196 * @param InstancePtr is the pointer to current IPI instance
197 * @param CpuMask is the Mask of the CPU form which Index is required
199 * @return Buffer Index value if CPU Mask is valid
200 * XIPIPSU_MAX_BUFF_INDEX+1 if not valid
202 * @note Static function used only by XIpiPsu_GetBufferAddress
205 static u32 XIpiPsu_GetBufferIndex(XIpiPsu *InstancePtr, u32 CpuMask)
209 /* Init Index with an invalid value */
210 BufferIndex = XIPIPSU_MAX_BUFF_INDEX + 1U;
212 /*Search for CPU in the List */
213 for (Index = 0U; Index < InstancePtr->Config.TargetCount; Index++) {
214 /*If we find the CPU , then set the Index and break the loop*/
215 if (InstancePtr->Config.TargetList[Index].Mask == CpuMask) {
216 BufferIndex = InstancePtr->Config.TargetList[Index].BufferIndex;
221 /* Return the Index */
226 * @brief Get the Buffer Address for a given pair of CPUs
228 * @param InstancePtr is the pointer to current IPI instance
229 * @param SrcCpuMask is the Mask for Source CPU
230 * @param DestCpuMask is the Mask for Destination CPU
231 * @param BufferType is either XIPIPSU_BUF_TYPE_MSG or XIPIPSU_BUF_TYPE_RESP
233 * @return Valid Buffer Address if no error
234 * NULL if an error occurred in calculating Address
238 static u32* XIpiPsu_GetBufferAddress(XIpiPsu *InstancePtr, u32 SrcCpuMask,
239 u32 DestCpuMask, u32 BufferType)
249 /* Get the buffer indices */
250 SrcIndex = XIpiPsu_GetBufferIndex(InstancePtr, SrcCpuMask);
251 DestIndex = XIpiPsu_GetBufferIndex(InstancePtr, DestCpuMask);
253 /* If we got an invalid buffer index, then return NULL pointer, else valid address */
254 if ((SrcIndex > XIPIPSU_MAX_BUFF_INDEX)
255 || (DestIndex > XIPIPSU_MAX_BUFF_INDEX)) {
259 if (XIPIPSU_BUF_TYPE_MSG == BufferType) {
260 BufferAddr = XIPIPSU_MSG_RAM_BASE
261 + (SrcIndex * XIPIPSU_BUFFER_OFFSET_GROUP)
262 + (DestIndex * XIPIPSU_BUFFER_OFFSET_TARGET);
263 } else if (XIPIPSU_BUF_TYPE_RESP == BufferType) {
264 BufferAddr = XIPIPSU_MSG_RAM_BASE
265 + (DestIndex * XIPIPSU_BUFFER_OFFSET_GROUP)
266 + (SrcIndex * XIPIPSU_BUFFER_OFFSET_TARGET)
267 + (XIPIPSU_BUFFER_OFFSET_RESPONSE);
274 return (u32 *) BufferAddr;
278 * @brief Read an Incoming Message from a Source
280 * @param InstancePtr is the pointer to current IPI instance
281 * @param SrcCpuMask is the Device Mask for the CPU which has sent the message
282 * @param MsgPtr is the pointer to Buffer to which the read message needs to be stored
283 * @param MsgLength is the length of the buffer/message
284 * @param BufferType is the type of buffer (XIPIPSU_BUF_TYPE_MSG or XIPIPSU_BUF_TYPE_RESP)
286 * @return XST_SUCCESS if successful
287 * XST_FAILURE if an error occurred
290 XStatus XIpiPsu_ReadMessage(XIpiPsu *InstancePtr, u32 SrcCpuMask, u32 *MsgPtr,
291 u32 MsgLength, u8 BufferType)
297 Xil_AssertNonvoid(InstancePtr != NULL);
298 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
299 Xil_AssertNonvoid(MsgPtr != NULL);
300 Xil_AssertNonvoid(MsgLength <= XIPIPSU_MAX_MSG_LEN);
302 BufferPtr = XIpiPsu_GetBufferAddress(InstancePtr, SrcCpuMask,
303 InstancePtr->Config.BitMask, BufferType);
304 if (BufferPtr != NULL) {
305 /* Copy the IPI Buffer contents into Users's Buffer*/
306 for (Index = 0U; Index < MsgLength; Index++) {
307 MsgPtr[Index] = BufferPtr[Index];
309 Status = XST_SUCCESS;
311 Status = XST_FAILURE;
319 * @brief Send a Message to Destination
321 * @param InstancePtr is the pointer to current IPI instance
322 * @param DestCpuMask is the Device Mask for the destination CPU
323 * @param MsgPtr is the pointer to Buffer which contains the message to be sent
324 * @param MsgLength is the length of the buffer/message
325 * @param BufferType is the type of buffer (XIPIPSU_BUF_TYPE_MSG or XIPIPSU_BUF_TYPE_RESP)
327 * @return XST_SUCCESS if successful
328 * XST_FAILURE if an error occurred
331 XStatus XIpiPsu_WriteMessage(XIpiPsu *InstancePtr, u32 DestCpuMask, u32 *MsgPtr,
332 u32 MsgLength, u8 BufferType)
338 Xil_AssertNonvoid(InstancePtr != NULL);
339 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
340 Xil_AssertNonvoid(MsgPtr != NULL);
341 Xil_AssertNonvoid(MsgLength <= XIPIPSU_MAX_MSG_LEN);
343 BufferPtr = XIpiPsu_GetBufferAddress(InstancePtr,
344 InstancePtr->Config.BitMask, DestCpuMask, BufferType);
345 if (BufferPtr != NULL) {
346 /* Copy the Message to IPI Buffer */
347 for (Index = 0U; Index < MsgLength; Index++) {
348 BufferPtr[Index] = MsgPtr[Index];
350 Status = XST_SUCCESS;
352 Status = XST_FAILURE;
358 /*****************************************************************************/
361 * Set up the device configuration based on the unique device ID. A table
362 * contains the configuration info for each device in the system.
364 * @param DeviceId contains the ID of the device to set up the
367 * @return A pointer to the device configuration for the specified
368 * device ID. See xipipsu.h for the definition of
371 * @note This is for safety use case where in this function has to
372 * be called before CfgInitialize. So that driver will be
373 * initialized with the provided configuration. For non-safe
374 * use cases, this is not needed.
376 ******************************************************************************/
377 void XIpiPsu_SetConfigTable(u32 DeviceId, XIpiPsu_Config *ConfigTblPtr)
381 Xil_AssertVoid(ConfigTblPtr != NULL);
383 for (Index = 0U; Index < XPAR_XIPIPSU_NUM_INSTANCES; Index++) {
384 if (XIpiPsu_ConfigTable[Index].DeviceId == DeviceId) {
385 XIpiPsu_ConfigTable[Index].BaseAddress = ConfigTblPtr->BaseAddress;
386 XIpiPsu_ConfigTable[Index].BitMask = ConfigTblPtr->BitMask;
387 XIpiPsu_ConfigTable[Index].BufferIndex = ConfigTblPtr->BufferIndex;
388 XIpiPsu_ConfigTable[Index].IntId = ConfigTblPtr->IntId;