empty_project_28377D/device/driverlib/ipc.c

444 lines
13 KiB
C

//###########################################################################
//
// FILE: ipc.c
//
// TITLE: C28x IPC driver.
//
//###########################################################################
// $Copyright:
// Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//###########################################################################
#include "ipc.h"
//
// Macros internal to the IPC driver
//
#define IPC_ADDR_OFFSET_NOCHANGE 2U
#define IPC_ADDR_OFFSET_MUL2 4U
#define IPC_ADDR_OFFSET_DIV2 1U
#define IPC_ADDR_OFFSET_CORR(addr, corr) (((addr) * (corr)) / 2U)
#if IPC_MSGQ_SUPPORT == 1U
//
// Global Circular Buffer Definitions
//
#pragma DATA_SECTION(IPC_CPU1_To_CPU2_PutBuffer, "MSGRAM_CPU1_TO_CPU2")
#pragma DATA_SECTION(IPC_CPU1_To_CPU2_GetBuffer, "MSGRAM_CPU2_TO_CPU1")
//
// IPC_CPU1_To_CPU2_PutBuffer acts as IPC_CPU2_To_CPU1_GetBuffer and
// IPC_CPU1_To_CPU2_GetBuffer acts as IPC_CPU2_To_CPU1_PutBuffer
//
IPC_PutBuffer_t IPC_CPU1_To_CPU2_PutBuffer;
IPC_GetBuffer_t IPC_CPU1_To_CPU2_GetBuffer;
#endif
const IPC_Instance_t IPC_Instance[IPC_TOTAL_NUM] = {
/* IPC_CPU1_L_CPU2_R */
{
.IPC_Flag_Ctr_Reg = (volatile IPC_Flag_Ctr_Reg_t *) IPC_BASE,
.IPC_SendCmd_Reg = (volatile IPC_SendCmd_Reg_t *)
(IPC_BASE + 0x10U),
.IPC_RecvCmd_Reg = (volatile IPC_RecvCmd_Reg_t *)
(IPC_BASE + 0x18U),
.IPC_Boot_Pump_Reg = (volatile IPC_Boot_Pump_Reg_t *)
(IPC_BASE + 0x20U),
.IPC_IntNum = {INT_IPC_0, INT_IPC_1, INT_IPC_2, INT_IPC_3,
0U, 0U, 0U, 0U},
.IPC_MsgRam_LtoR = CPU1_TO_CPU2_MSG_RAM_BASE,
.IPC_MsgRam_RtoL = CPU2_TO_CPU1_MSG_RAM_BASE,
.IPC_Offset_Corr = IPC_ADDR_OFFSET_NOCHANGE
#if IPC_MSGQ_SUPPORT == 1U
,
.IPC_PutBuffer = &IPC_CPU1_To_CPU2_PutBuffer,
.IPC_GetBuffer = &IPC_CPU1_To_CPU2_GetBuffer
#endif
},
/* IPC_CPU2_L_CPU1_R */
{
.IPC_Flag_Ctr_Reg = (volatile IPC_Flag_Ctr_Reg_t *) IPC_BASE,
.IPC_SendCmd_Reg = (volatile IPC_SendCmd_Reg_t *)
(IPC_BASE + 0x18U),
.IPC_RecvCmd_Reg = (volatile IPC_RecvCmd_Reg_t *)
(IPC_BASE + 0x10U),
.IPC_Boot_Pump_Reg = (volatile IPC_Boot_Pump_Reg_t *)
(IPC_BASE + 0x20U),
.IPC_IntNum = {INT_IPC_0, INT_IPC_1, INT_IPC_2, INT_IPC_3,
0U, 0U, 0U, 0U},
.IPC_MsgRam_LtoR = CPU2_TO_CPU1_MSG_RAM_BASE,
.IPC_MsgRam_RtoL = CPU1_TO_CPU2_MSG_RAM_BASE,
.IPC_Offset_Corr = IPC_ADDR_OFFSET_NOCHANGE
#if IPC_MSGQ_SUPPORT == 1U
,
.IPC_PutBuffer = (IPC_PutBuffer_t *)&IPC_CPU1_To_CPU2_GetBuffer,
.IPC_GetBuffer = (IPC_GetBuffer_t *)&IPC_CPU1_To_CPU2_PutBuffer
#endif
}
};
//*****************************************************************************
//
// IPC_sendCommand
//
//*****************************************************************************
bool IPC_sendCommand(IPC_Type_t ipcType, uint32_t flags, bool addrCorrEnable,
uint32_t command, uint32_t addr, uint32_t data)
{
bool ret;
//
// Check whether the flags are not busy
//
if((IPC_Instance[ipcType].IPC_Flag_Ctr_Reg->IPC_FLG & flags) == 0U)
{
ret = true;
if(addrCorrEnable)
{
//
// Update the command registers. ADDR register holds the offset
// from the base address of the MSG RAM
//
IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDCOM = command;
IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDDATA = data;
IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDADDR =
addr - IPC_Instance[ipcType].IPC_MsgRam_LtoR;
}
else
{
//
// Update the command registers. addr param remains as is.
//
IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDCOM = command;
IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDDATA = data;
IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDADDR = addr;
}
//
// Set the flags to indicate the remote core
//
IPC_Instance[ipcType].IPC_Flag_Ctr_Reg->IPC_SET = flags;
}
else
{
ret = false;
}
return(ret);
}
//*****************************************************************************
//
// IPC_readCommand
//
//*****************************************************************************
bool IPC_readCommand(IPC_Type_t ipcType, uint32_t flags, bool addrCorrEnable,
uint32_t *command, uint32_t *addr, uint32_t *data)
{
bool ret;
uint32_t addrReg;
//
// Check whether the flags are not empty
//
if((IPC_Instance[ipcType].IPC_Flag_Ctr_Reg->IPC_STS & flags) != 0U)
{
ret = true;
//
// Read the command registers
//
*command = IPC_Instance[ipcType].IPC_RecvCmd_Reg->IPC_RECVCOM;
addrReg = IPC_Instance[ipcType].IPC_RecvCmd_Reg->IPC_RECVADDR;
*data = IPC_Instance[ipcType].IPC_RecvCmd_Reg->IPC_RECVDATA;
if(addrCorrEnable)
{
//
// Calculate the address form the offset
//
*addr = IPC_Instance[ipcType].IPC_MsgRam_RtoL +
IPC_ADDR_OFFSET_CORR(addrReg,
IPC_Instance[ipcType].IPC_Offset_Corr);
}
else
{
*addr = addrReg;
}
}
else
{
ret = false;
}
return(ret);
}
//*****************************************************************************
//
// IPC_registerInterrupt
//
//*****************************************************************************
void IPC_registerInterrupt(IPC_Type_t ipcType, uint32_t ipcInt,
void (*pfnHandler)(void))
{
//
// Check for arguments
//
ASSERT(ipcInt <= IPC_INT3);
//
// Get the corresponding interrupt number
//
uint32_t intNum = IPC_Instance[ipcType].IPC_IntNum[ipcInt];
//
// Register the interrupt handler
//
Interrupt_register(intNum, pfnHandler);
//
// Enable the interrupt
//
Interrupt_enable(intNum);
}
//*****************************************************************************
//
// IPC_unregisterInterrupt
//
//*****************************************************************************
void IPC_unregisterInterrupt(IPC_Type_t ipcType, uint32_t ipcInt)
{
//
// Check for arguments
//
ASSERT(ipcInt <= IPC_INT3);
//
// Get the corresponding interrupt number
//
uint32_t intNum = IPC_Instance[ipcType].IPC_IntNum[ipcInt];
//
// Disable the interrupt.
//
Interrupt_disable(intNum);
//
// Unregister the interrupt handler.
//
Interrupt_unregister(intNum);
}
#if IPC_MSGQ_SUPPORT == 1U
//*****************************************************************************
//
// IPCinitMessageQueue
//
//*****************************************************************************
void IPC_initMessageQueue(IPC_Type_t ipcType,
volatile IPC_MessageQueue_t *msgQueue,
uint32_t ipcInt_L, uint32_t ipcInt_R)
{
//
// Check for arguments
//
ASSERT(msgQueue != NULL);
ASSERT(ipcInt_L < IPC_NUM_OF_INTERRUPTS);
ASSERT(ipcInt_R < IPC_NUM_OF_INTERRUPTS);
IPC_PutBuffer_t *putBuffer = IPC_Instance[ipcType].IPC_PutBuffer;
IPC_GetBuffer_t *getBuffer = IPC_Instance[ipcType].IPC_GetBuffer;
//
// L->R Put Buffer and Index Initialization
//
msgQueue->PutBuffer = putBuffer->Buffer[ipcInt_R];
msgQueue->PutWriteIndex = &(putBuffer->PutWriteIndex[ipcInt_R]);
msgQueue->GetReadIndex = &(putBuffer->GetReadIndex[ipcInt_L]);
msgQueue->PutFlag = (uint32_t)1U << ipcInt_R;
//
// L->R Get Buffer and Index Initialization
//
msgQueue->GetBuffer = getBuffer->Buffer[ipcInt_L];
msgQueue->GetWriteIndex = &(getBuffer->GetWriteIndex[ipcInt_L]);
msgQueue->PutReadIndex = &(getBuffer->PutReadIndex[ipcInt_R]);
//
// Initialize PutBuffer WriteIndex = 0 and GetBuffer ReadIndex = 0
//
*(msgQueue->PutWriteIndex) = 0U;
*(msgQueue->GetReadIndex) = 0U;
}
//*****************************************************************************
//
// IPC_sendMessageToQueue
//
//*****************************************************************************
bool IPC_sendMessageToQueue(IPC_Type_t ipcType,
volatile IPC_MessageQueue_t *msgQueue,
bool addrCorrEnable, IPC_Message_t *msg, bool block)
{
//
// Check for arguments
//
ASSERT(msgQueue != NULL);
ASSERT(msg != NULL);
uint16_t writeIndex;
uint16_t readIndex;
uint16_t ret = true;
writeIndex = *(msgQueue->PutWriteIndex);
readIndex = *(msgQueue->PutReadIndex);
//
// Wait until Put Buffer slot is free
//
while(((writeIndex + 1U) & IPC_MAX_BUFFER_INDEX) == readIndex)
{
//
// If designated as a "Blocking" function, and Put buffer is full,
// return immediately with fail status.
//
if(!block)
{
ret = false;
break;
}
readIndex = *(msgQueue->PutReadIndex);
}
if(ret != false)
{
//
// When slot is free, Write Message to PutBuffer, update PutWriteIndex,
// and set the CPU IPC INT Flag
//
msgQueue->PutBuffer[writeIndex] = *msg;
if(addrCorrEnable)
{
msgQueue->PutBuffer[writeIndex].address -=
IPC_Instance[ipcType].IPC_MsgRam_LtoR;
}
writeIndex = (writeIndex + 1U) & IPC_MAX_BUFFER_INDEX;
*(msgQueue->PutWriteIndex) = writeIndex;
IPC_setFlagLtoR(ipcType, msgQueue->PutFlag);
}
return(ret);
}
//*****************************************************************************
//
// IPC_readMessageFromQueue
//
//*****************************************************************************
bool IPC_readMessageFromQueue(IPC_Type_t ipcType,
volatile IPC_MessageQueue_t *msgQueue,
bool addrCorrEnable, IPC_Message_t *msg, bool block)
{
//
// Check for arguments
//
ASSERT(msgQueue != NULL);
ASSERT(msg != NULL);
uint16_t writeIndex;
uint16_t readIndex;
uint16_t ret = true;
writeIndex = *(msgQueue->GetWriteIndex);
readIndex = *(msgQueue->GetReadIndex);
//
// Loop while GetBuffer is empty
//
while(writeIndex == readIndex)
{
//
// If designated as a "Blocking" function, and Get buffer is empty,
// return immediately with fail status.
//
if(!block)
{
ret = false;
break;
}
writeIndex = *(msgQueue->GetWriteIndex);
}
if(ret != false)
{
//
// If there is a message in GetBuffer, Read Message and update
// the ReadIndex
//
*msg = msgQueue->GetBuffer[readIndex];
if(addrCorrEnable)
{
msg->address = IPC_Instance[ipcType].IPC_MsgRam_RtoL +
IPC_ADDR_OFFSET_CORR(msg->address,
IPC_Instance[ipcType].IPC_Offset_Corr);
}
readIndex = (readIndex + 1U) & IPC_MAX_BUFFER_INDEX;
*(msgQueue->GetReadIndex) = readIndex;
}
return(ret);
}
#endif