embeddedsw/XilinxProcessorIPLib/drivers/llfifo/src/xstreamer.c
Jagannadha Sutradharudu Teki 2c8f92039d embeddesw: Add initial code support
Added initial support Xilinx Embedded Software.

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
2014-06-24 16:45:01 +05:30

513 lines
18 KiB
C
Executable file

/******************************************************************************
*
* Copyright (C) 2005 - 2014 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 THE
* XILINX CONSORTIUM 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 xstreamer.c
*
* See xtreamer.h for a description on how to use this driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a jvb 10/13/06 First release - based on Robert McGee's streaming packet
* fifo driver.
* 1.02a jz 12/04/09 Hal phase 1 support
* 2.00a hbm 01/20/10 Hal phase 1 support, bump up major release
* 2.02a asa 12/28/11 The function XStrm_Read is changed to reset HeadIndex
* to zero when all the bytes are read.
* </pre>
******************************************************************************/
/***************************** Include Files *********************************/
#include "xstreamer.h"
#include "xil_assert.h"
/*
* Implementation Notes
*
* --- Receive ---
*
* The basic algorithm for receiving bytes through this byte streamer copies a
* fifo key-hole width chunk from the fifo into a holding buffer and then doles
* out the bytes from the holding buffer. In some cases, when the buffer given
* happens to already be aligned in memory, this algorithm will bypass the
* holding buffer.
*
* Here is a picture to depict this process:
*
* Initial state: holding buffer
* +--------------+
* | <empty> |
* +--------------+
* ^
* |
* index
*
* during XStrm_Read():
* first holding buffer fill: holding buffer
* +--------------+
* |////<full>////|
* +--------------+
* ^
* |
* index
*
* first holding buffer read: holding buffer
* read unread
* +--------------+
* | |///////|
* +--------------+
* ^
* |
* index
*
* ...
*
* last holding buffer read: holding buffer
* +--------------+
* | <empty> |
* +--------------+
* ^
* |
* index
*
* repeat this process ^^^
*
*
* --- Transmit ---
*
* The basic algorithm for transmitting bytes through this byte streamer copies
* bytes into a holding buffer and then writes the holding buffer into the fifo
* when it is full. In some cases, when the buffer given happens to already be
* aligned in memory, this algorithm will bypass the holding buffer.
*
* Here is a picture to depict this process:
*
* Initial state: holding buffer
* +--------------+
* | <empty> |
* +--------------+
* ^
* |
* index
*
* during XStrm_Write():
* first holding buffer write: holding buffer
* writen empty
* +--------------+
* |//////| |
* +--------------+
* ^
* |
* index
*
* ...
* last holding buffer write: holding buffer
* +--------------+
* |////<full>////|
* +--------------+
* ^
* |
* index
*
* holding buffer flush: holding buffer
* +--------------+
* | <empty> |
* +--------------+
* ^
* |
* index
*
* repeat this process ^^^
*/
#ifndef min
#define min(x, y) (((x) < (y)) ? (x) : (y))
#endif
xdbg_stmnt(u32 _xstrm_ro_value;)
xdbg_stmnt(u32 _xstrm_buffered;)
/*****************************************************************************/
/*
*
* XStrm_RxInitialize initializes the XStrm_RxFifoStreamer object referenced by
* <i>InstancePtr</i>.
*
* @param InstancePtr references the tx streamer on which to operate.
*
* @param FifoWidth specifies the FIFO keyhole size in bytes.
*
* @param FifoInstance references the FIFO driver instance that this streamer
* object should use to transfer data into the the actual fifo.
*
* @param ReadFn specifies a routine to use to read data from the actual
* FIFO. It is assumed that this read routine will handle only reads
* from an aligned buffer. (Otherwise, why are we using this streamer
* driver?)
*
* @param GetLenFn specifies a routine to use to initiate a receive on the
* actual FIFO.
*
* @param GetOccupancyFn specifies a routine to use to retrieve the occupancy
* in the actual FIFO. The true occupancy value needs to come through
* this streamer driver becuase it holds some of the bytes.
*
* @return N/A
*
******************************************************************************/
void XStrm_RxInitialize(XStrm_RxFifoStreamer *InstancePtr, unsigned FifoWidth,
void *FifoInstance, XStrm_XferFnType ReadFn,
XStrm_GetLenFnType GetLenFn,
XStrm_GetOccupancyFnType GetOccupancyFn)
{
/* Verify arguments */
Xil_AssertVoid(InstancePtr != NULL);
InstancePtr->HeadIndex = FifoWidth;
InstancePtr->FifoWidth = FifoWidth;
InstancePtr->FifoInstance = FifoInstance;
InstancePtr->ReadFn = ReadFn;
InstancePtr->GetLenFn = GetLenFn;
InstancePtr->GetOccupancyFn = GetOccupancyFn;
}
/*****************************************************************************/
/*
*
* XStrm_TxInitialize initializes the XStrm_TxFifoStreamer object referenced by
* <i>InstancePtr</i>.
*
* @param InstancePtr references the tx streamer on which to operate.
*
* @param FifoWidth specifies the FIFO keyhole size in bytes.
*
* @param FifoInstance references the FIFO driver instance that this streamer
* object should use to transfer data into the the actual fifo.
*
* @param WriteFn specifies a routine to use to write data into the actual
* FIFO. It is assumed that this write routine will handle only writes
* from an aligned buffer. (Otherwise, why are we using this streamer
* driver?)
*
* @param SetLenFn specifies a routine to use to initiate a transmit on the
* actual FIFO.
*
* @param GetVacancyFn specifies a routine to use to retrieve the vacancy in
* the actual FIFO. The true vacancy value needs to come through this
* streamer driver becuase it holds some of the bytes.
*
* @return N/A
*
******************************************************************************/
void XStrm_TxInitialize(XStrm_TxFifoStreamer *InstancePtr, unsigned FifoWidth,
void *FifoInstance, XStrm_XferFnType WriteFn,
XStrm_SetLenFnType SetLenFn,
XStrm_GetVacancyFnType GetVacancyFn)
{
/* Verify arguments */
Xil_AssertVoid(InstancePtr != NULL);
InstancePtr->TailIndex = 0;
InstancePtr->FifoWidth = FifoWidth;
InstancePtr->FifoInstance = FifoInstance;
InstancePtr->WriteFn = WriteFn;
InstancePtr->SetLenFn = SetLenFn;
InstancePtr->GetVacancyFn = GetVacancyFn;
}
/*****************************************************************************/
/*
*
* XStrm_RxGetLen notifies the hardware that the program is ready to receive the
* next frame from the receive channel of the FIFO, specified by
* <i>InstancePtr</i>.
*
* Note that the program must first call XStrm_RxGetLen before pulling data
* out of the receive channel of the FIFO with XStrm_Read.
*
* @param InstancePtr references the FIFO on which to operate.
*
* @return XStrm_RxGetLen returns the number of bytes available in the next
* frame.
*
******************************************************************************/
u32 XStrm_RxGetLen(XStrm_RxFifoStreamer *InstancePtr)
{
u32 len;
InstancePtr->HeadIndex = InstancePtr->FifoWidth;
len = (*InstancePtr->GetLenFn)(InstancePtr->FifoInstance);
InstancePtr->FrmByteCnt = len;
return len;
}
/*****************************************************************************/
/*
*
* XStrm_Read reads <i>Bytes</i> bytes from the FIFO specified by
* <i>InstancePtr</i> to the block of memory, referenced by <i>BufPtr</i>.
*
* Care must be taken to ensure that the number of bytes read with one or more
* calls to XStrm_Read() does not exceed the number of bytes available given
* from the last call to XStrm_RxGetLen().
*
* @param InstancePtr references the FIFO on which to operate.
*
* @param BufPtr specifies the memory address to place the data read.
*
* @param Bytes specifies the number of bytes to read.
*
* @return N/A
*
******************************************************************************/
void XStrm_Read(XStrm_RxFifoStreamer *InstancePtr, void *BufPtr,
unsigned Bytes)
{
u8 *DestPtr = (u8 *) BufPtr;
unsigned BytesRemaining = Bytes;
unsigned FifoWordsToXfer;
unsigned PartialBytes;
unsigned i;
while (BytesRemaining) {
xdbg_printf(XDBG_DEBUG_FIFO_RX, "XStrm_Read: BytesRemaining: %d\n", BytesRemaining);
/* Case 1: There are bytes in the holding buffer
*
* 1) Read the bytes from the holding buffer to the target buffer.
* 2) Loop back around and handle the rest of the transfer.
*/
if (InstancePtr->HeadIndex != InstancePtr->FifoWidth) {
xdbg_printf(XDBG_DEBUG_FIFO_RX, "XStrm_Read: Case 1: InstancePtr->HeadIndex [%d] != InstancePtr->FifoWidth [%d]\n",
InstancePtr->HeadIndex, InstancePtr->FifoWidth);
i = InstancePtr->HeadIndex;
PartialBytes = min(BytesRemaining,
InstancePtr->FifoWidth -
InstancePtr->HeadIndex);
InstancePtr->HeadIndex += PartialBytes;
BytesRemaining -= PartialBytes;
InstancePtr->FrmByteCnt -= PartialBytes;
while (PartialBytes--) {
*DestPtr = InstancePtr->AlignedBuffer.bytes[i];
i++;
DestPtr++;
}
}
/* Case 2: There are no more bytes in the holding buffer and
* the target buffer is 32 bit aligned and
* the number of bytes remaining to transfer is greater
* than or equal to the fifo width.
*
* 1) We can go fast by reading a long string of fifo words right out
* of the fifo into the target buffer.
* 2) Loop back around to transfer the last few bytes.
*/
else if ((((unsigned)DestPtr & 3) == 0) &&
(BytesRemaining >= InstancePtr->FifoWidth)) {
xdbg_printf(XDBG_DEBUG_FIFO_RX, "XStrm_Read: Case 2: DestPtr: %p, BytesRemaining: %d, InstancePtr->FifoWidth: %d\n",
DestPtr, BytesRemaining, InstancePtr->FifoWidth);
FifoWordsToXfer =
BytesRemaining / InstancePtr->FifoWidth;
(*(InstancePtr->ReadFn)) (InstancePtr->FifoInstance,
DestPtr, FifoWordsToXfer);
DestPtr += FifoWordsToXfer * InstancePtr->FifoWidth;
BytesRemaining -=
FifoWordsToXfer * InstancePtr->FifoWidth;
InstancePtr->FrmByteCnt -=
FifoWordsToXfer * InstancePtr->FifoWidth;
}
/* Case 3: There are no more bytes in the holding buffer and
* the number of bytes remaining to transfer is less than
* the fifo width or
* things just don't line up.
*
* 1) Fill the holding buffer.
* 2) Loop back around and handle the rest of the transfer.
*/
else {
xdbg_printf(XDBG_DEBUG_FIFO_RX, "XStrm_Read: Case 3\n");
/*
* At the tail end, read one fifo word into the local holding
* buffer and loop back around to take care of the transfer.
*/
(*InstancePtr->ReadFn) (InstancePtr->FifoInstance,
&(InstancePtr->AlignedBuffer.
bytes[0]), 1);
InstancePtr->HeadIndex = 0;
}
}
if ((InstancePtr->FrmByteCnt) == 0) {
InstancePtr->HeadIndex = 0;
}
}
/*****************************************************************************/
/*
*
* XStrm_TxSetLen flushes to the FIFO, specified by <i>InstancePtr</i>, any
* bytes remaining in internal buffers and begins a hardware transfer of data
* out of the transmit channel of the FIFO. <i>Bytes</i> specifies the number
* of bytes in the frame to transmit.
*
* @param InstancePtr references the FIFO Streamer on which to operate.
*
* @param Bytes specifies the frame length in bytes.
*
* @return N/A
*
******************************************************************************/
void XStrm_TxSetLen(XStrm_TxFifoStreamer *InstancePtr, u32 Bytes)
{
/*
* First flush what's in the holding buffer
*/
if (InstancePtr->TailIndex != 0) {
(*InstancePtr->WriteFn) (InstancePtr->FifoInstance,
&(InstancePtr->AlignedBuffer.bytes[0]),
1);
InstancePtr->TailIndex = 0;
}
/*
* Kick off the hw write
*/
(*(InstancePtr)->SetLenFn) (InstancePtr->FifoInstance, Bytes);
}
/*****************************************************************************/
/*
*
* XStrm_Write writes <i>Bytes</i> bytes of the block of memory, referenced by
* <i>BufPtr</i>, to the transmit channel of the FIFO referenced by
* <i>InstancePtr</i>.
*
* Care must be taken to ensure that the number of bytes written with one or
* more calls to XStrm_Write() matches the number of bytes given in the next
* call to XStrm_TxSetLen().
*
* @param InstancePtr references the FIFO on which to operate.
*
* @param BufPtr specifies the memory address of data to write.
*
* @param Bytes specifies the number of bytes to write.
*
* @return N/A
*
******************************************************************************/
void XStrm_Write(XStrm_TxFifoStreamer *InstancePtr, void *BufPtr,
unsigned Bytes)
{
u8 *SrcPtr = (u8 *) BufPtr;
unsigned BytesRemaining = Bytes;
unsigned FifoWordsToXfer;
unsigned PartialBytes;
unsigned i;
while (BytesRemaining) {
xdbg_printf(XDBG_DEBUG_FIFO_TX,
"XStrm_Write: BytesRemaining: %d\n",
BytesRemaining);
/* Case 1: The holding buffer is full
*
* 1) Write it to the fifo.
* 2) Fall through to transfer more bytes in this iteration.
*/
if (InstancePtr->TailIndex == InstancePtr->FifoWidth) {
xdbg_printf(XDBG_DEBUG_FIFO_TX,
"XStrm_Write: (case 1) TailIndex: %d; FifoWidth: %d; WriteFn: %p\n",
InstancePtr->TailIndex, InstancePtr->FifoWidth,
InstancePtr->WriteFn);
(*InstancePtr->WriteFn) (InstancePtr->FifoInstance,
&(InstancePtr->AlignedBuffer.
bytes[0]), 1);
InstancePtr->TailIndex = 0;
}
/* Case 2: There are no bytes in the holding buffer and
* the target buffer is 32 bit aligned and
* the number of bytes remaining to transfer is greater
* than or equal to the fifo width.
*
* 1) We can go fast by writing a long string of fifo words right out
* of the source buffer into the fifo.
* 2) Loop back around to transfer the last few bytes.
*/
if ((InstancePtr->TailIndex == 0) &&
(BytesRemaining >= InstancePtr->FifoWidth) &&
(((unsigned)SrcPtr & 3) == 0)) {
FifoWordsToXfer =
BytesRemaining / InstancePtr->FifoWidth;
xdbg_printf(XDBG_DEBUG_FIFO_TX, "XStrm_Write: (case 2) TailIndex: %d; BytesRemaining: %d; FifoWidth: %d; SrcPtr: %p;\n InstancePtr: %p; WriteFn: %p ,\nFifoWordsToXfer: %d (BytesRemaining: %d)\n",
InstancePtr->TailIndex, BytesRemaining,
InstancePtr->FifoWidth, SrcPtr,
InstancePtr, InstancePtr->WriteFn,
FifoWordsToXfer,
BytesRemaining);
(*InstancePtr->WriteFn) (InstancePtr->FifoInstance,
SrcPtr, FifoWordsToXfer);
SrcPtr += FifoWordsToXfer * InstancePtr->FifoWidth;
BytesRemaining -=
FifoWordsToXfer * InstancePtr->FifoWidth;
xdbg_printf(XDBG_DEBUG_FIFO_TX, "XStrm_Write: (end case 2) TailIndex: %d; BytesRemaining: %d; SrcPtr: %p\n",
InstancePtr->TailIndex, BytesRemaining, SrcPtr);
}
/* Case 3: The alignment of the "galaxies" didn't occur in
* Case 2 above, so we must pump the bytes through the
* holding buffer.
*
* 1) Write bytes from the source buffer to the holding buffer
* 2) Loop back around and handle the rest of the transfer.
*/
else {
i = InstancePtr->TailIndex;
PartialBytes =
min(BytesRemaining,
InstancePtr->FifoWidth -
InstancePtr->TailIndex);
BytesRemaining -= PartialBytes;
InstancePtr->TailIndex += PartialBytes;
while (PartialBytes--) {
xdbg_printf(XDBG_DEBUG_FIFO_TX, "XStrm_Write: (case 3) PartialBytes: %d\n",
PartialBytes);
InstancePtr->AlignedBuffer.bytes[i] = *SrcPtr;
i++;
SrcPtr++;
}
}
}
}