blob: 92eaad2cd37639695756e68f066f365c55916a14 [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2010 - 2017 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 xdpdma.c
*
* This file contains the implementation of the interface functions of the
* XDpDma driver. Refer to xdpdma.h for detailed information.
*
* @note None.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ---- ----- -------- ----------------------------------------------------
* 1.0 aad 04/12/16 Initial release.
*
*****************************************************************************/
/***************************** Include Files **********************************/
#include "xdpdma.h"
#include "xavbuf.h"
/************************** Constant Definitions ******************************/
#define XDPDMA_CH_OFFSET 0x100
#define XDPDMA_WAIT_TIMEOUT 10000
#define XDPDMA_AUDIO_ALIGNMENT 128
#define XDPDMA_VIDEO_CHANNEL0 0
#define XDPDMA_VIDEO_CHANNEL1 1
#define XDPDMA_VIDEO_CHANNEL2 2
#define XDPDMA_GRAPHICS_CHANNEL 3
#define XDPDMA_AUDIO_CHANNEL0 4
#define XDPDMA_AUDIO_CHANNEL1 5
#define XDPDMA_DESC_PREAMBLE 0xA5
#define XDPDMA_DESC_IGNR_DONE 0x400
#define XDPDMA_DESC_UPDATE 0x200
#define XDPDMA_DESC_COMP_INTR 0x100
#define XDPDMA_DESC_LAST_FRAME 0x200000
#define XDPDMA_DESC_DONE_SHIFT 31
#define XDPDMA_QOS_MIN 4
#define XDPDMA_QOS_MAX 11
/*************************************************************************/
/**
*
* This function returns the number of outstanding transactions on a given
* channel.
*
* @param InstancePtr is a pointer to the driver instance.
* @param ChannelNum is the channel number on which the operation is
* being carried out.
*
* @return Number of pending transactions.
*
* @note None.
*
* **************************************************************************/
static int XDpDma_GetPendingTransaction(XDpDma *InstancePtr, u32 ChannelNum)
{
u32 RegVal;
RegVal = XDpDma_ReadReg(InstancePtr->Config.BaseAddr,
XDPDMA_CH0_STATUS + 0x100 * ChannelNum);
return (RegVal & XDPDMA_CH_STATUS_OTRAN_CNT_MASK);
}
/*************************************************************************/
/**
*
* This function waits until the outstanding transactions are completed.
*
* @param InstancePtr is a pointer to the driver instance.
* @param ChannelNum is the channel number on which the operation is
* being carried out.
*
* @return XST_SUCCESS when all the pending transactions are complete
* before timeout.
* XST_FAILURE if timeout occurs before pending transactions are
* completed.
*
* @note None.
*
* **************************************************************************/
static int XDpDma_WaitPendingTransaction(XDpDma *InstancePtr, u8 ChannelNum)
{
/* Verify arguments. */
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ChannelNum <= XDPDMA_AUDIO_CHANNEL1);
u32 Timeout = 0;
u32 Count;
do {
Count = XDpDma_GetPendingTransaction(InstancePtr, ChannelNum);
Timeout++;
} while((Timeout != XDPDMA_WAIT_TIMEOUT) && Count);
if(Timeout == XDPDMA_WAIT_TIMEOUT) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function controls the hardware channels of the DPDMA.
*
*
* @param InstancePtr is a pointer to the driver instance.
* @param ChannelNum is the physical channel number of the DPDMA.
* @param ChannelState is an enum of type XDpDma_ChannelState.
*
* @return XST_SUCCESS when the mentioned channel is enabled successfully.
* XST_FAILURE when the mentioned channel fails to be enabled.
*
* @note None.
*
* **************************************************************************/
static int XDpDma_ConfigChannelState(XDpDma *InstancePtr, u8 ChannelNum,
XDpDma_ChannelState Enable)
{
u32 Mask = 0;
u32 RegVal = 0;
u32 Status = 0;
/* Verify arguments. */
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ChannelNum <= XDPDMA_AUDIO_CHANNEL1);
Mask = XDPDMA_CH_CNTL_EN_MASK | XDPDMA_CH_CNTL_PAUSE_MASK;
switch(Enable) {
case XDPDMA_ENABLE:
RegVal = XDPDMA_CH_CNTL_EN_MASK;
break;
case XDPDMA_DISABLE:
XDpDma_ConfigChannelState(InstancePtr, ChannelNum,
XDPDMA_PAUSE);
Status = XDpDma_WaitPendingTransaction(InstancePtr,
ChannelNum);
if(Status == XST_FAILURE) {
return XST_FAILURE;
}
RegVal = XDPDMA_DISABLE;
Mask = XDPDMA_CH_CNTL_EN_MASK;
break;
case XDPDMA_IDLE:
Status = XDpDma_ConfigChannelState(InstancePtr,
ChannelNum,
XDPDMA_DISABLE);
if(Status == XST_FAILURE) {
return XST_FAILURE;
}
RegVal = 0;
break;
case XDPDMA_PAUSE:
RegVal = XDPDMA_PAUSE;
break;
}
XDpDma_ReadModifyWrite(InstancePtr->Config.BaseAddr,
XDPDMA_CH0_CNTL + XDPDMA_CH_OFFSET * ChannelNum,
RegVal, Mask);
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function updates the descriptor that is not currently active on a
* Video/Graphics channel.
*
* @param InstancePtr is a pointer to the driver instance.
* @param Channel is a pointer to the channel on which the operation is
* to be carried out.
*
* @return Descriptor for next operation.
*
* @note None.
*
* **************************************************************************/
static XDpDma_Descriptor *XDpDma_UpdateVideoDescriptor(XDpDma_Channel *Channel)
{
if(Channel->Current == NULL) {
Channel->Current = &Channel->Descriptor0;
}
else if(Channel->Current == &Channel->Descriptor0) {
Channel->Current = &Channel->Descriptor1;
}
else if(Channel->Current == &Channel->Descriptor1) {
Channel->Current = &Channel->Descriptor0;
}
return Channel->Current;
}
/*************************************************************************/
/**
* This function programs the address of the descriptor about to be active
*
* @param InstancePtr is a pointer to the DPDMA instance.
* @param Channel is an enum of the channel for which the descriptor
* address is to be set.
*
* @return Descriptor for next operation.
*
* @note None.
*
* **************************************************************************/
static void XDpDma_SetDescriptorAddress(XDpDma *InstancePtr, u8 ChannelNum)
{
u32 AddrOffset;
u32 AddrEOffset;
Xil_AssertVoid(ChannelNum <= XDPDMA_AUDIO_CHANNEL1);
AddrOffset = XDPDMA_CH0_DSCR_STRT_ADDR +
(XDPDMA_CH_OFFSET * ChannelNum);
AddrEOffset = XDPDMA_CH0_DSCR_STRT_ADDRE +
(XDPDMA_CH_OFFSET * ChannelNum);
XDpDma_Descriptor *Descriptor = NULL;
switch(ChannelNum) {
case XDPDMA_VIDEO_CHANNEL0:
Descriptor = InstancePtr->Video.Channel[ChannelNum].Current;
break;
case XDPDMA_VIDEO_CHANNEL1:
Descriptor = InstancePtr->Video.Channel[ChannelNum].Current;
break;
case XDPDMA_VIDEO_CHANNEL2:
Descriptor = InstancePtr->Video.Channel[ChannelNum].Current;
break;
case XDPDMA_GRAPHICS_CHANNEL:
Descriptor = InstancePtr->Gfx.Channel.Current;
break;
case XDPDMA_AUDIO_CHANNEL0:
Descriptor = InstancePtr->Audio[0].Current;
break;
case XDPDMA_AUDIO_CHANNEL1:
Descriptor = InstancePtr->Audio[1].Current;
break;
}
XDpDma_WriteReg(InstancePtr->Config.BaseAddr, AddrEOffset,
(INTPTR) Descriptor >> 32);
XDpDma_WriteReg(InstancePtr->Config.BaseAddr, AddrOffset,
(INTPTR) Descriptor);
}
/*************************************************************************/
/**
*
* This functions sets the Audio Descriptor for Data Transfer.
*
* @param CurrDesc is a pointer to the descriptor to be initialized
* @param DataSize is the payload size of the buffer to be transferred
* @param BuffAddr is the payload address
*
* @return None.
*
* @note None.
*
* **************************************************************************/
static void XDpDma_SetupAudioDescriptor(XDpDma_Descriptor *CurrDesc,
u64 DataSize, u64 BuffAddr,
XDpDma_Descriptor *NextDesc)
{
Xil_AssertVoid(CurrDesc != NULL);
Xil_AssertVoid(DataSize != 0);
Xil_AssertVoid(BuffAddr != 0);
if(NextDesc == NULL) {
CurrDesc->Control = XDPDMA_DESC_PREAMBLE |
XDPDMA_DESC_UPDATE | XDPDMA_DESC_IGNR_DONE |
XDPDMA_DESC_COMP_INTR;
}
else {
CurrDesc->Control = XDPDMA_DESC_PREAMBLE |
XDPDMA_DESC_UPDATE | XDPDMA_DESC_IGNR_DONE;
}
CurrDesc->DSCR_ID = 0;
CurrDesc->XFER_SIZE = DataSize;
CurrDesc->LINE_SIZE_STRIDE = 0;
CurrDesc->LSB_Timestamp = 0;
CurrDesc->MSB_Timestamp = 0;
CurrDesc->ADDR_EXT = ((BuffAddr >> XDPDMA_DESCRIPTOR_SRC_ADDR_WIDTH) <<
XDPDMA_DESCRIPTOR_ADDR_EXT_SRC_ADDR_EXT_SHIFT) |
((INTPTR) NextDesc >>
XDPDMA_DESCRIPTOR_NEXT_DESR_WIDTH);
CurrDesc->NEXT_DESR = (INTPTR) NextDesc;
CurrDesc->SRC_ADDR = BuffAddr;
}
/*************************************************************************/
/**
*
* This functions retrieves the configuration for this DPDMA driver and
* fills in the InstancePtr->Config structure.
*
* @param InstancePtr is a pointer to the driver instance.
* @param ConfigPtr is a pointer to the configuration structure that will
* be used to copy the settings from.
*
* @return None.
*
* @note None.
*
* **************************************************************************/
void XDpDma_CfgInitialize(XDpDma *InstancePtr, XDpDma_Config *CfgPtr)
{
InstancePtr->Config.DeviceId = CfgPtr->DeviceId;
InstancePtr->Config.BaseAddr = CfgPtr->BaseAddr;
InstancePtr->Video.Channel[XDPDMA_VIDEO_CHANNEL0].Current = NULL;
InstancePtr->Video.Channel[XDPDMA_VIDEO_CHANNEL1].Current = NULL;
InstancePtr->Video.Channel[XDPDMA_VIDEO_CHANNEL2].Current = NULL;
InstancePtr->Video.TriggerStatus = XDPDMA_TRIGGER_DONE;
InstancePtr->Video.VideoInfo = NULL;
InstancePtr->Video.FrameBuffer[XDPDMA_VIDEO_CHANNEL0] = NULL;
InstancePtr->Video.FrameBuffer[XDPDMA_VIDEO_CHANNEL1] = NULL;
InstancePtr->Video.FrameBuffer[XDPDMA_VIDEO_CHANNEL2] = NULL;
InstancePtr->Gfx.Channel.Current = NULL;
InstancePtr->Gfx.TriggerStatus = XDPDMA_TRIGGER_DONE;
InstancePtr->Gfx.VideoInfo = NULL;
InstancePtr->Gfx.FrameBuffer = NULL;
}
/*************************************************************************/
/**
*
* This functions controls the states in which a channel should go into.
*
* @param InstancePtr is a pointer to the driver instance.
* @param ChannelType is an enum of XDpDma_ChannelType.
* @param ChannelState is an enum of type XDpDma_ChannelState.
*
* @return XST_SUCCESS when the mentioned channel is enabled successfully.
* XST_FAILURE when the mentioned channel fails to be enabled.
*
* @note None.
*
* **************************************************************************/
int XDpDma_SetChannelState(XDpDma *InstancePtr, XDpDma_ChannelType Channel,
XDpDma_ChannelState ChannelState)
{
u32 Index = 0;
u32 NumPlanes = 0;
u32 Status = 0;
/* Verify arguments. */
Xil_AssertNonvoid(InstancePtr != NULL);
switch(Channel) {
case VideoChan:
if(InstancePtr->Video.VideoInfo == NULL) {
return XST_FAILURE;
}
else {
NumPlanes = InstancePtr->Video.VideoInfo->Mode;
for(Index = 0; Index <= NumPlanes; Index++) {
Status = XDpDma_ConfigChannelState(InstancePtr,
Index,
ChannelState);
if(Status == XST_FAILURE) {
return XST_FAILURE;
}
}
}
break;
case GraphicsChan:
if(InstancePtr->Gfx.VideoInfo == NULL) {
return XST_FAILURE;
}
else {
return XDpDma_ConfigChannelState(InstancePtr,
XDPDMA_GRAPHICS_CHANNEL,
ChannelState);
}
break;
case AudioChan0:
return XDpDma_ConfigChannelState(InstancePtr,
XDPDMA_AUDIO_CHANNEL0,
ChannelState);
break;
case AudioChan1:
return XDpDma_ConfigChannelState(InstancePtr,
XDPDMA_AUDIO_CHANNEL1,
ChannelState);
break;
default:
return XST_FAILURE;
break;
}
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function allocates DPDMA Video Channels depending on the number of
* planes in the video
*
* @param InstancePtr is a pointer to the driver instance.
* @params Format is the video format to be used for the DPDMA transfer
*
* @return XST_SUCCESS, When the format is valid Video Format.
* XST_FAILURE, When the format is not valid Video Format
*
* @note None.
*
* **************************************************************************/
int XDpDma_SetVideoFormat(XDpDma *InstancePtr, XAVBuf_VideoFormat Format)
{
/* Verify arguments. */
Xil_AssertNonvoid(InstancePtr != NULL);
InstancePtr->Video.VideoInfo = XAVBuf_GetNLiveVideoAttribute(Format);
if(InstancePtr->Video.VideoInfo == NULL) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function allocates DPDMA Graphics Channels.
*
* @param InstancePtr is a pointer to the driver instance.
* @params Format is the video format to be used for the DPDMA transfer
*
* @return XST_SUCCESS, When the format is a valid Graphics Format.
* XST_FAILURE, When the format is not valid Graphics Format.
*
* @note None.
*
* **************************************************************************/
int XDpDma_SetGraphicsFormat(XDpDma *InstancePtr, XAVBuf_VideoFormat Format)
{
/* Verify arguments. */
Xil_AssertNonvoid(InstancePtr != NULL);
InstancePtr->Gfx.VideoInfo = XAVBuf_GetNLGraphicsAttribute(Format);
if(InstancePtr->Gfx.VideoInfo == NULL) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function starts the operation on the a given channel
*
* @param InstancePtr is a pointer to the driver instance.
* @param QOS is the Quality of Service value to be selected.
*
* @return None.
*
* @note .
*
* **************************************************************************/
void XDpDma_SetQOS(XDpDma *InstancePtr, u8 QOS)
{
u8 Index;
u32 RegVal = 0;
Xil_AssertVoid(QOS >= XDPDMA_QOS_MIN && QOS <= XDPDMA_QOS_MAX);
RegVal = ((QOS << XDPDMA_CH_CNTL_QOS_DATA_RD_SHIFT) |
(QOS << XDPDMA_CH_CNTL_QOS_DSCR_RD_SHIFT) |
(QOS << XDPDMA_CH_CNTL_QOS_DSCR_WR_SHIFT));
u32 Mask = XDPDMA_CH_CNTL_QOS_DATA_RD_MASK |
XDPDMA_CH_CNTL_QOS_DSCR_RD_MASK |
XDPDMA_CH_CNTL_QOS_DSCR_WR_MASK;
for(Index = 0; Index <= XDPDMA_AUDIO_CHANNEL1; Index++) {
XDpDma_ReadModifyWrite(InstancePtr->Config.BaseAddr,
XDPDMA_CH0_CNTL + (XDPDMA_CH_OFFSET * Index),
RegVal, Mask);
}
}
/*************************************************************************/
/**
*
* This function Triggers DPDMA to start the transaction.
*
* @param InstancePtr is a pointer to the XDpDma instance.
* @param Channel is the XDpDma_ChannelType on which the transaction
* is to be triggered.
*
* @return XST_SUCCESS The channel has successfully been Triggered.
* XST_FAILURE When the triggering Video and Graphics channel
* without setting the Video Formats.
*
* @note None.
*
* **************************************************************************/
int XDpDma_Trigger(XDpDma *InstancePtr, XDpDma_ChannelType Channel)
{
u32 Trigger = 0;
u8 Index = 0;
u8 NumPlanes = 0;
switch(Channel) {
case VideoChan:
if(InstancePtr->Video.VideoInfo == NULL) {
return XST_FAILURE;
}
else {
NumPlanes = InstancePtr->Video.VideoInfo->Mode;
for(Index = 0; Index <= NumPlanes; Index++) {
Trigger |= XDPDMA_GBL_TRG_CH0_MASK << Index;
InstancePtr->Video.TriggerStatus =
XDPDMA_TRIGGER_DONE;
}
}
break;
case GraphicsChan:
if(InstancePtr->Gfx.VideoInfo == NULL) {
return XST_FAILURE;
}
Trigger = XDPDMA_GBL_TRG_CH3_MASK;
InstancePtr->Gfx.TriggerStatus = XDPDMA_TRIGGER_DONE;
break;
case AudioChan0:
Trigger = XDPDMA_GBL_TRG_CH4_MASK;
InstancePtr->Audio[0].TriggerStatus = XDPDMA_TRIGGER_DONE;
break;
case AudioChan1:
Trigger = XDPDMA_GBL_TRG_CH5_MASK;
InstancePtr->Audio[1].TriggerStatus = XDPDMA_TRIGGER_DONE;
break;
}
XDpDma_WriteReg(InstancePtr->Config.BaseAddr, XDPDMA_GBL, Trigger);
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function Retriggers DPDMA to fetch data from new descriptor.
*
* @param InstancePtr is a pointer to the XDpDma instance.
* @param Channel is the XDpDma_ChannelType on which the transaction
* is to be retriggered.
*
* @return XST_SUCCESS The channel has successfully been Triggered.
* XST_FAILURE When the triggering Video and Graphics channel
* without setting the Video Formats.
*
* @note None.
*
* **************************************************************************/
int XDpDma_ReTrigger(XDpDma *InstancePtr, XDpDma_ChannelType Channel)
{
u32 Trigger = 0;
u8 NumPlanes;
u8 Index;
switch(Channel) {
case VideoChan:
if(InstancePtr->Video.VideoInfo == NULL) {
return XST_FAILURE;
}
else {
NumPlanes = InstancePtr->Video.VideoInfo->Mode;
for(Index = 0; Index <= NumPlanes; Index++) {
Trigger |= XDPDMA_GBL_RTRG_CH0_MASK << Index;
InstancePtr->Video.TriggerStatus =
XDPDMA_RETRIGGER_DONE;
}
}
break;
case GraphicsChan:
if(InstancePtr->Gfx.VideoInfo == NULL) {
return XST_FAILURE;
}
Trigger = XDPDMA_GBL_RTRG_CH3_MASK;
InstancePtr->Gfx.TriggerStatus = XDPDMA_RETRIGGER_DONE;
break;
case AudioChan0:
Trigger = XDPDMA_GBL_RTRG_CH4_MASK;
InstancePtr->Audio[0].TriggerStatus = XDPDMA_RETRIGGER_DONE;
break;
case AudioChan1:
Trigger = XDPDMA_GBL_RTRG_CH5_MASK;
InstancePtr->Audio[1].TriggerStatus = XDPDMA_RETRIGGER_DONE;
break;
}
XDpDma_WriteReg(InstancePtr->Config.BaseAddr, XDPDMA_GBL, Trigger);
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function intializes Video Descriptor for Video and Graphics channel
*
* @param Channel is a pointer to the current Descriptor of Video or
* Graphics Channel.
* @param FrameBuffer is a pointer to the Frame Buffer structure
*
* @return None.
*
* @note None.
*
* **************************************************************************/
void XDpDma_InitVideoDescriptor(XDpDma_Descriptor *CurrDesc,
XDpDma_FrameBuffer *FrameBuffer)
{
Xil_AssertVoid(CurrDesc != NULL);
Xil_AssertVoid(FrameBuffer != NULL);
Xil_AssertVoid((FrameBuffer->Stride) % XDPDMA_DESCRIPTOR_ALIGN == 0);
CurrDesc->Control = XDPDMA_DESC_PREAMBLE | XDPDMA_DESC_IGNR_DONE |
XDPDMA_DESC_LAST_FRAME;
CurrDesc->DSCR_ID = 0;
CurrDesc->XFER_SIZE = FrameBuffer->Size;
CurrDesc->LINE_SIZE_STRIDE = ((FrameBuffer->Stride >> 4) <<
XDPDMA_DESCRIPTOR_LINE_SIZE_STRIDE_SHIFT) |
(FrameBuffer->LineSize);
CurrDesc->ADDR_EXT = (((FrameBuffer->Address >>
XDPDMA_DESCRIPTOR_SRC_ADDR_WIDTH) <<
XDPDMA_DESCRIPTOR_ADDR_EXT_SRC_ADDR_EXT_SHIFT) |
((INTPTR) CurrDesc >>
XDPDMA_DESCRIPTOR_NEXT_DESR_WIDTH));
CurrDesc->NEXT_DESR = (INTPTR) CurrDesc;
CurrDesc->SRC_ADDR = FrameBuffer->Address;
}
/*************************************************************************/
/**
*
* This function intializes Descriptors for transactions on Audio Channel
*
* @param Channel is a pointer to the XDpDma_AudioChannel instance
*
* @param AudioBuffer is a pointer to the Audio Buffer structure
*
* @return None.
*
* @note None.
*
* **************************************************************************/
void XDpDma_InitAudioDescriptor(XDpDma_AudioChannel *Channel,
XDpDma_AudioBuffer *AudioBuffer)
{
u32 Size;
u64 Address;
Xil_AssertVoid(Channel != NULL);
Xil_AssertVoid(AudioBuffer != NULL);
Xil_AssertVoid((AudioBuffer->Size) % XDPDMA_AUDIO_ALIGNMENT == 0);
Xil_AssertVoid((AudioBuffer->Address) % XDPDMA_AUDIO_ALIGNMENT == 0);
Size = AudioBuffer->Size / 4;
Address = AudioBuffer->Address;
if(Channel->Current == &Channel->Descriptor4) {
XDpDma_SetupAudioDescriptor(&Channel->Descriptor4, Size,
Address,
&Channel->Descriptor5);
XDpDma_SetupAudioDescriptor(&Channel->Descriptor5, Size,
Address + Size,
&Channel->Descriptor6);
XDpDma_SetupAudioDescriptor(&Channel->Descriptor6, Size,
Address + (Size * 2),
&Channel->Descriptor7);
XDpDma_SetupAudioDescriptor(&Channel->Descriptor7, Size,
Address + (Size * 3), NULL);
}
else if(Channel->Current == &Channel->Descriptor0) {
XDpDma_SetupAudioDescriptor(&Channel->Descriptor0, Size,
Address,
&Channel->Descriptor1);
XDpDma_SetupAudioDescriptor(&Channel->Descriptor1, Size,
Address + Size,
&Channel->Descriptor2);
XDpDma_SetupAudioDescriptor(&Channel->Descriptor2, Size,
Address + (Size * 2),
&Channel->Descriptor3);
XDpDma_SetupAudioDescriptor(&Channel->Descriptor3, Size,
Address + (Size * 3), NULL);
}
}
/*************************************************************************/
/**
*
* This function sets the next Frame Buffers to be displayed on the Video
* Channel.
*
* @param InstancePtr is pointer to the instance of DPDMA.
* @param Plane0 is a pointer to the Frame Buffer structure.
* @param Plane1 is a pointer to the Frame Buffer structure.
* @param Plane2 is a pointer to the Frame Buffer structure.
*
* @return None.
*
* @note For interleaved mode use Plane0.
* For semi-planar mode use Plane0 and Plane1.
* For planar mode use Plane0, Plane1 and Plane2
*
* **************************************************************************/
void XDpDma_DisplayVideoFrameBuffer(XDpDma *InstancePtr,
XDpDma_FrameBuffer *Plane0,
XDpDma_FrameBuffer *Plane1,
XDpDma_FrameBuffer *Plane2)
{
u8 NumPlanes;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->Video.VideoInfo != NULL);
NumPlanes = InstancePtr->Video.VideoInfo->Mode;
switch(NumPlanes) {
case XDPDMA_VIDEO_CHANNEL2:
Xil_AssertVoid(Plane2 != NULL);
InstancePtr->Video.FrameBuffer[XDPDMA_VIDEO_CHANNEL2] =
Plane2;
case XDPDMA_VIDEO_CHANNEL1:
Xil_AssertVoid(Plane1 != NULL);
InstancePtr->Video.FrameBuffer[XDPDMA_VIDEO_CHANNEL1] =
Plane1;
case XDPDMA_VIDEO_CHANNEL0:
Xil_AssertVoid(Plane0 != NULL);
InstancePtr->Video.FrameBuffer[XDPDMA_VIDEO_CHANNEL0] =
Plane0;
break;
}
if(InstancePtr->Video.Channel[XDPDMA_VIDEO_CHANNEL0].Current == NULL) {
InstancePtr->Video.TriggerStatus = XDPDMA_TRIGGER_EN;
}
else {
InstancePtr->Video.TriggerStatus = XDPDMA_RETRIGGER_EN;
}
}
/*************************************************************************/
/**
*
* This function sets the next Frame Buffers to be displayed on the Graphics
* Channel.
*
* @param InstancePtr is pointer to the instance of DPDMA.
* @param Plane is a pointer to the Frame Buffer structure.
*
* @return None.
*
* @note None.
*
**************************************************************************/
void XDpDma_DisplayGfxFrameBuffer(XDpDma *InstancePtr,
XDpDma_FrameBuffer *Plane)
{
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(Plane != NULL);
InstancePtr->Gfx.FrameBuffer = Plane;
if(InstancePtr->Gfx.Channel.Current == NULL) {
InstancePtr->Gfx.TriggerStatus = XDPDMA_TRIGGER_EN;
}
else {
InstancePtr->Gfx.TriggerStatus = XDPDMA_RETRIGGER_EN;
}
}
/*************************************************************************/
/**
*
* This function sets the next Audio Buffer to be played on Audio Channel 0
*
* @param InstancePtr is pointer to the instance of DPDMA.
* @param Buffer is a pointer to the attributes of the Audio information
* to be played.
* @param ChannelNum selects between Audio Channel 0 and Audio Channel 1
*
* @return XST_SUCCESS when the play audio request is successful.
* XST_FAILURE when the play audio request fails, user has to
* retry to play the audio.
*
* @note The user has to schedule new audio buffer before half the audio
* information is consumed by DPDMA to have a seamless playback.
*
**************************************************************************/
int XDpDma_PlayAudio(XDpDma *InstancePtr, XDpDma_AudioBuffer *Buffer,
u8 ChannelNum)
{
XDpDma_AudioChannel *Channel;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(Buffer != NULL);
Xil_AssertNonvoid(Buffer->Size >= 512);
Xil_AssertNonvoid(Buffer->Size % 128 == 0);
Xil_AssertNonvoid(Buffer->Address % 128 == 0);
Channel = &InstancePtr->Audio[ChannelNum];
Channel->Buffer = Buffer;
if(Channel->Current == NULL) {
Channel->TriggerStatus = XDPDMA_TRIGGER_EN;
Channel->Current = &Channel->Descriptor0;
Channel->Used = 0;
}
else if(Channel->Current == &Channel->Descriptor0) {
/* Check if descriptor chain can be updated */
if(Channel->Descriptor1.MSB_Timestamp >>
XDPDMA_DESC_DONE_SHIFT) {
Channel->Current = NULL;
return XST_FAILURE;
}
else if(Channel->Descriptor7.MSB_Timestamp >>
XDPDMA_DESC_DONE_SHIFT || !(Channel->Used)) {
Channel->Descriptor3.Control = XDPDMA_DESC_PREAMBLE |
XDPDMA_DESC_UPDATE | XDPDMA_DESC_IGNR_DONE;
Channel->Descriptor3.NEXT_DESR =
(INTPTR) &Channel->Descriptor4;
Channel->Descriptor3.ADDR_EXT &=
~XDPDMA_DESCRIPTOR_ADDR_EXT_DSC_NXT_MASK;
Channel->Descriptor3.ADDR_EXT |=
(INTPTR) &Channel->Descriptor4 >> 32;
Channel->Current = &Channel->Descriptor4;
Channel->Used = 1;
XDpDma_InitAudioDescriptor(Channel, Buffer);
}
else {
return XST_FAILURE;
}
}
else if(Channel->Current == &Channel->Descriptor4) {
/* Check if descriptor chain can be updated */
if(Channel->Descriptor5.MSB_Timestamp >>
XDPDMA_DESC_DONE_SHIFT) {
Channel->Current = NULL;
return XST_FAILURE;
}
else if(Channel->Descriptor3.MSB_Timestamp >>
XDPDMA_DESC_DONE_SHIFT) {
Channel->Descriptor7.Control = XDPDMA_DESC_PREAMBLE |
XDPDMA_DESC_UPDATE | XDPDMA_DESC_IGNR_DONE;
Channel->Descriptor7.NEXT_DESR =
(INTPTR) &Channel->Descriptor0;
Channel->Descriptor7.ADDR_EXT &=
~XDPDMA_DESCRIPTOR_ADDR_EXT_DSC_NXT_MASK;
Channel->Descriptor7.ADDR_EXT |=
(INTPTR) &Channel->Descriptor0 >> 32;
Channel->Current = &Channel->Descriptor0;
XDpDma_InitAudioDescriptor(Channel, Buffer);
}
else {
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
/*************************************************************************/
/**
*
* This function sets the channel with the latest framebuffer and the
* available descriptor for transfer on the next Vsync.
*
* @param InstancePtr is pointer to the instance of DPDMA.
* @param Channel indicates which channels are being setup for transfer.
*
* @return None.
*
* @note None.
*
**************************************************************************/
void XDpDma_SetupChannel(XDpDma *InstancePtr, XDpDma_ChannelType Channel)
{
XDpDma_Channel *Chan;
XDpDma_AudioChannel *AudChan;
XDpDma_FrameBuffer *FB;
XDpDma_AudioBuffer *AudioBuffer;
u8 Index, NumPlanes;
Xil_AssertVoid(InstancePtr != NULL);
switch(Channel) {
case VideoChan:
Xil_AssertVoid(InstancePtr->Video.VideoInfo != NULL);
Xil_AssertVoid(InstancePtr->Video.FrameBuffer != NULL);
NumPlanes = InstancePtr->Video.VideoInfo->Mode;
for(Index = 0; Index <= NumPlanes; Index++) {
Chan = &InstancePtr->Video.Channel[Index];
FB = InstancePtr->Video.FrameBuffer[Index];
XDpDma_UpdateVideoDescriptor(Chan);
XDpDma_InitVideoDescriptor(Chan->Current, FB);
XDpDma_SetDescriptorAddress(InstancePtr,
Index);
}
break;
case GraphicsChan:
Xil_AssertVoid(InstancePtr->Gfx.VideoInfo != NULL);
Xil_AssertVoid(InstancePtr->Gfx.FrameBuffer != NULL);
Chan = &InstancePtr->Gfx.Channel;
FB = InstancePtr->Gfx.FrameBuffer;
XDpDma_UpdateVideoDescriptor(Chan);
XDpDma_InitVideoDescriptor(Chan->Current, FB);
XDpDma_SetDescriptorAddress(InstancePtr,
XDPDMA_GRAPHICS_CHANNEL);
break;
case AudioChan0:
Xil_AssertVoid(InstancePtr->Audio[0].Buffer != NULL);
AudChan = &InstancePtr->Audio[0];
AudioBuffer = InstancePtr->Audio[0].Buffer;
XDpDma_InitAudioDescriptor(AudChan, AudioBuffer);
XDpDma_SetDescriptorAddress(InstancePtr,
XDPDMA_AUDIO_CHANNEL0);
break;
case AudioChan1:
Xil_AssertVoid(InstancePtr->Audio[1].Buffer != NULL);
AudChan = &InstancePtr->Audio[1];
AudioBuffer = InstancePtr->Audio[1].Buffer;
XDpDma_InitAudioDescriptor(AudChan, AudioBuffer);
XDpDma_SetDescriptorAddress(InstancePtr,
XDPDMA_AUDIO_CHANNEL1);
break;
}
}