--- /dev/null
+/******************************************************************************
+*
+* 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;
+ }
+}