Initial version.

This commit is contained in:
Gatsby Van
2023-12-20 00:11:03 +08:00
commit 416bd53733
1043 changed files with 293547 additions and 0 deletions
+452
View File
@@ -0,0 +1,452 @@
/*****************************************************************************/
/**
* Description: A simple AXI DMA api.
*
* Author: Fan Hao
* Date: 2022-06-18 16:37
* LastEditors: Fan Hao
* LastEditTime: 2022-06-18 17:38
* Revisions: Rev 0.0
* History:
* [2022-06-18]: Initial version.
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/***************************** Include Files *********************************/
#include <stdint.h>
#include <stdbool.h>
#include "xaxidma.h"
// #include "xtime_l.h" //Adjutment for microblaze
#include "xil_cache.h"
#include "axi_dma.h"
#include "../error.h"
#include "../common.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
* @brief Initialize the DMA descriptor instance, allocate space for
* descriptor.
*
* @param instPtr a second rank pointer to DMA descriptor instance
* @param configPtr a pointer to DMA descriptor instance configuration
* set.
*
* @return SUCCESS
* ENOMEM memory allocate failed.
* other error codes
*
******************************************************************************/
int32_t Dma_Init(DMA_DESC** instPtr, const DMA_CONFIG* configPtr){
ASSERT(configPtr != NULL);
int32_t Status = SUCCESS;
*instPtr = (DMA_DESC*) malloc(sizeof(DMA_DESC));
if ((*instPtr) == NULL) {
goto err;
}
(*instPtr)->isTxDone = false;
(*instPtr)->isRxDone = false;
(*instPtr)->isError = false;
(*instPtr)->isListening = false;
memcpy(&((*instPtr)->configs), configPtr, sizeof(DMA_CONFIG));
(*instPtr)->axiDmaPtr = (XAxiDma*) malloc(sizeof(XAxiDma));
if ((*instPtr)->axiDmaPtr == NULL) {
free((*instPtr)->axiDmaPtr);
goto err;
}
XAxiDma_Config* damConfigPtr = NULL;
damConfigPtr = XAxiDma_LookupConfig(configPtr->devId);
if (damConfigPtr == NULL) {
DBG_PRINT("No config found for %d\r\n", configPtr->devId);
goto err;
}
/* Initialize DMA engine */
Status = XAxiDma_CfgInitialize((*instPtr)->axiDmaPtr, damConfigPtr);
if (Status != SUCCESS) {
DBG_ERROR("DMA initialize failed. device id: %d\r\n", configPtr->devId);
goto err;
}
if(XAxiDma_HasSg((*instPtr)->axiDmaPtr)){
DBG_ERROR("DMA Device configured as SG mode \r\n");
goto err;
}
/* Clear all interrupts before setup */
XAxiDma_IntrAckIrq((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrAckIrq((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
/* Disable all interrupts before setup */
XAxiDma_IntrDisable((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable((*instPtr)->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
(*instPtr)->isInitialized = true;
return SUCCESS;
err:
free(*instPtr);
return Status;
}
/*****************************************************************************/
/**
* @brief Enable DMA IRQs.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_IrqEnable(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return EDINVAL;
}
/* Enable all interrupts */
XAxiDma_IntrEnable(instPtr->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(instPtr->axiDmaPtr, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Enable DMA listening feature and start a receive procedure.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_ListenEnable(DMA_DESC* instPtr, uint8_t* dataBuff){
if(instPtr == NULL || instPtr->isInitialized == false || dataBuff == NULL){
return EDINVAL;
}
instPtr->isListening = true;
instPtr->listenBuff = dataBuff;
// if(XAxiDma_Busy(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA) == false){
return XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)instPtr->listenBuff,
instPtr->configs.defaultTransLen, XAXIDMA_DEVICE_TO_DMA);
// }
// else{
// return SUCCESS;
// }
}
/*****************************************************************************/
/**
* @brief Disable DMA listening feature and start a receive procedure.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_ListenDisable(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return EDINVAL;
}
instPtr->isListening = false;
instPtr->listenBuff = NULL;
if(XAxiDma_Busy(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA) == true){
DBG_WARNING("an unfinished transfer is on going.\r\n");
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (DMA->Device), none-blocking
* transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_SendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return FAILURE;
}
// Flush the SrcBuffer before the DMA transfer
// Xil_DCacheFlushRange((uintptr_t)dataBuff, dataLen);
// Set txDone flage to false, before transmission
instPtr->isTxDone = false;
// Assert a send trigger
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr, (uintptr_t)dataBuff,
dataLen, XAXIDMA_DMA_TO_DEVICE);
if (Status != SUCCESS) {
return FAILURE;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (DMA->Device), blocking transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* ETIMEOUT transfer timeout.
* other error codes.
*
******************************************************************************/
int32_t Dma_BlockingSendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return EINVAL;
}
Status = Dma_SendData(instPtr, dataBuff, dataLen);
if(Status == SUCCESS){
DBG_ERROR("Failed to setup a DMA transfer (DMA->Device).\r\n");
return Status;
}
//Adjutment for microblaze
// XTime tCur = 0;
// XTime tTimeOut = 0;
// XTime_GetTime(&tCur);
// tTimeOut = tCur + instPtr->configs.timeoutTh;
while(instPtr->isTxDone == false && instPtr->isError == false){
//Adjutment for microblaze
// XTime_GetTime(&tCur);
// if(tCur >= tTimeOut){
// return ETIMEOUT;
// }
}
if(instPtr->isError == true){
return FAILURE;
}
// Set txDone flage to false, after transmission
instPtr->isTxDone = false;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (Device->DMA), none-blocking
* transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_RecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return FAILURE;
}
// Set txDone flage to false, before transmission
instPtr->isRxDone = false;
// Assert a send trigger
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)dataBuff,
dataLen, XAXIDMA_DEVICE_TO_DMA);
if (Status != SUCCESS) {
return FAILURE;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Transfer a specific length of data (Device->DMA), blocking transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
* @param dataBuff a pointer to data buffer.
* @param dataLen length of data need to be transfer.
*
* @return SUCCESS
* EDINVAL device not initialized.
*
******************************************************************************/
int32_t Dma_BlockingRecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen){
int32_t Status;
if(dataLen > instPtr->configs.transMax){
return FAILURE;
}
Status = Dma_RecvData(instPtr, dataBuff, dataLen);
if(Status == SUCCESS){
DBG_ERROR("Failed to setup a DMA transfer (Device->DMA).\r\n");
return Status;
}
//Adjutment for microblaze
// XTime tCur = 0;
// XTime tTimeOut = 0;
// XTime_GetTime(&tCur);
// tTimeOut = tCur + instPtr->configs.timeoutTh;
while(instPtr->isTxDone == false && instPtr->isError == false){
//Adjutment for microblaze
// XTime_GetTime(&tCur);
// if(tCur >= tTimeOut){
// return ETIMEOUT;
// }
}
if(instPtr->isError == true){
return FAILURE;
}
// Set txDone flage to false, after transmission
instPtr->isTxDone = false;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Handler for DMA->Device transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* error codes
*
******************************************************************************/
int32_t Dma_SendIrqHandler(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return FAILURE;
}
int32_t Status = SUCCESS;
uint32_t IrqStatus = 0;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(instPtr->axiDmaPtr, XAXIDMA_DMA_TO_DEVICE);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(instPtr->axiDmaPtr, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
/* If no interrupt is asserted, we do not do anything */
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return EIGNORE;
}
/* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
instPtr->isError = true;
/* Reset should never fail for transmit channel */
XAxiDma_Reset(instPtr->axiDmaPtr);
while (XAxiDma_ResetIsDone(instPtr->axiDmaPtr) == false) {
// FIXME: Add time out check
}
return EUNEXP;
}
/* If Completion interrupt is asserted, then set the TxDone flag */
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
instPtr->isTxDone = true;
}
return Status;
}
/*****************************************************************************/
/**
* @brief Handler for Device->DMA transfer.
*
* @param instPtr a pointer to DMA descriptor instance.
*
* @return SUCCESS
* error codes
*
******************************************************************************/
int32_t Dma_RecvIrqHandler(DMA_DESC* instPtr){
if(instPtr == NULL || instPtr->isInitialized == false){
return FAILURE;
}
int32_t Status = SUCCESS;
uint32_t IrqStatus = 0;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(instPtr->axiDmaPtr, XAXIDMA_DEVICE_TO_DMA);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(instPtr->axiDmaPtr, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
/* If no interrupt is asserted, we do not do anything */
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return EIGNORE;
}
/* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
instPtr->isError = true;
/* Reset should never fail for transmit channel */
XAxiDma_Reset(instPtr->axiDmaPtr);
while (XAxiDma_ResetIsDone(instPtr->axiDmaPtr)) {
// FIXME: Add time out check
}
return EUNEXP;
}
/* If completion interrupt is asserted, then set RxDone flag */
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
// // Invalid the DestBuffer after the DMA transfer
// int RingIndex = 0;
// uintptr_t dstAddr;
// uint32_t transLen;
// dstAddr = XAxiDma_ReadReg(instPtr->axiDmaPtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_DESTADDR_OFFSET);
// if (instPtr->axiDmaPtr->AddrWidth > 32){
// dstAddr |= ((uintptr_t)(XAxiDma_ReadReg(instPtr->axiDmaPtr->RxBdRing[RingIndex].ChanBase,
// XAXIDMA_DESTADDR_MSB_OFFSET))<<32);
// }
// transLen = XAxiDma_ReadReg(InstancePtr->RxBdRing[RingIndex].ChanBase, XAXIDMA_BUFFLEN_OFFSET)
// Xil_DCacheInvalidateRange(dstAddr, transLen);
instPtr->isRxDone = true;
}
if(instPtr->isListening == true){
// Continuous receiving
Status = XAxiDma_SimpleTransfer(instPtr->axiDmaPtr,(uintptr_t)instPtr->listenBuff,
instPtr->configs.defaultTransLen, XAXIDMA_DEVICE_TO_DMA);
if(Status != SUCCESS){
DBG_ERROR("Failed to start a new SimpleTransfer in XAXIDMA_DEVICE_TO_DMA channel.\r\n");
}
}
return Status;
}
+62
View File
@@ -0,0 +1,62 @@
/*****************************************************************************/
/**
* Description: A simple AXI DMA api.
* prototypes.
*
* Author: Fan Hao
* Date: 2022-06-18 16:37
* LastEditors: Fan Hao
* LastEditTime: 2022-06-18 17:40
* Revisions: Rev 0.0
* History:
* [2022-06-18]: Initial version.
*
* Copyright(c) 2022 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
#ifndef AXI_DMA_H_
#define AXI_DMA_H_
/***************************** Include Files *********************************/
#include <stdint.h>
#include <stdbool.h>
#include "xaxidma.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
typedef struct{
uint32_t devId;
uint32_t transMax;
uint32_t defaultTransLen;
uint32_t timeoutTh;
}DMA_CONFIG;
typedef struct{
bool isTxDone;
bool isRxDone;
bool isError;
bool isListening;
bool isInitialized;
uint8_t* listenBuff;
XAxiDma* axiDmaPtr;
DMA_CONFIG configs;
}DMA_DESC;
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
int32_t Dma_Init(DMA_DESC** instPtr, const DMA_CONFIG* configPtr);
int32_t Dma_IrqEnable(DMA_DESC* instPtr);
int32_t Dma_ListenEnable(DMA_DESC* instPtr, uint8_t* dataBuff);
int32_t Dma_ListenDisable(DMA_DESC* instPtr);
int32_t Dma_SendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_BlockingSendData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_RecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_BlockingRecvData(DMA_DESC* instPtr, uint8_t* dataBuff, int32_t dataLen);
int32_t Dma_SendIrqHandler(DMA_DESC* instPtr);
int32_t Dma_RecvIrqHandler(DMA_DESC* instPtr);
#endif //AXI_DMA_H_