/**************************************************************************//**
 *
 * Copyright 1998-2012 NetBurner, Inc.  ALL RIGHTS RESERVED
 *   Permission is hereby granted to purchasers of NetBurner Hardware
 *   to use or modify this computer program for any use as long as the
 *   resultant program is only executed on NetBurner provided hardware.
 *
 *   No other rights to use this program or it's derivatives in part or
 *   in whole are granted.
 *
 *   It may be possible to license this or other NetBurner software for
 *   use on non-NetBurner Hardware.
 *   Please contact sales@Netburner.com for more information.
 *
 *   NetBurner makes no representation or warranties
 *   with respect to the performance of this computer program, and
 *   specifically disclaims any responsibility for any damages,
 *   special or consequential, connected with the use of this program.
 *
 *---------------------------------------------------------------------
 * NetBurner, Inc.
 * 5405 Morehouse Drive
 * San Diego, California 92121
 *
 * information available at:  http://www.netburner.com
 * E-Mail info@netburner.com
 *
 * Support is available: E-Mail support@netburner.com
 *
 *****************************************************************************/

#ifndef  _DMA_SPI_H_INC
#define  _DMA_SPI_H_INC
#include <basictypes.h>
#include <sim5441x.h>


#ifndef __cplusplus
#error DSPI driver is a C++ only library
#endif

/*
   DSPI state
*/
#define DSPI_OK      ( 0 )
#define DSPI_BUSY    ( 1 )
#define DSPI_ERROR   ( 2 )


// MCR Register masks
#define MCR_MASTER_INIT     0x80000C01
#define MCR_HALT_BIT        0x00000001
#define MCR_DIS_TXF         0x00002000
#define MCR_DIS_RXF         0x00001000
#define MCR_CLR_FIFOS       0x00000C00


// CTAR Register masks
#define CTAR_CLOCK_POLARITY 0x04000000
#define CTAR_CLOCK_PHASE    0x02000000
#define CTAR_FRAME_16BIT    0x78000000
#define CTAR_FRAME_4BIT     0x18000000

// SR Register masks
#define SR_EOQF_MASK        0x10000000
#define SR_CLR_FLAGS        0x8A0A0000

// RSER (Interrupt/DMA enable) Register masks
#define RSER_EOQF_IRQ_ONLY  ~0x8B0B0000
#define RSER_DMA_IRQ_ONLY   0x03030000

// PUSHR (command) Register masks
#define PUSHR_CONT_BIT      0x80000000
#define PUSHR_EOQ_BIT       0x08000000

////////////////////////////////////////
//
// DMA CHANNEL NUMBERS
#define DMA_CH_DSPI_0_RX    0x0C    // (12)
#define DMA_CH_DSPI_0_TX    0x0D    // (13)
#define DMA_CH_DSPI_1_RX    0x0E    // (14)
#define DMA_CH_DSPI_1_TX    0x0F    // (15)
#define DMA_CH_DSPI_2_RX    0x1C    // (28)
#define DMA_CH_DSPI_2_TX    0x1D    // (29)
#define DMA_CH_DSPI_3_RX    0x2C    // (44)
#define DMA_CH_DSPI_3_TX    0x2D    // (45)


// EDMA CR Register masks
#define CR_CLEAR_NON_GRP_PRIO   ~0x000300FF
#define CR_SET_RR_CH_ARB    0x00000004

////////////////////////////////////////
// EDMA TCD masks
#define TCD_ATTR_8BIT_TRANS 0x0000
#define TCD_ATTR_16BIT_TRANS    0x0101

#define TCD_XOFF_0BYTE      0x0000
#define TCD_XOFF_1BYTE      0x0001
#define TCD_XOFF_2BYTE      0x0002

#define TCD_XITER_CNT_MASK  0x7FFF

#define TCD_CSR_DONE_BIT    0x0080
#define TCD_CSR_DISABLE_REQ 0xC008
#define TCD_CSR_DREQ_INT_MAJOR  0xC00A
// end EDMA TCD masks
////////////////////////////////////////

#define DEFAULT_DSPI_MODULE 1
#define DSPI_MODULE_COUNT   4

enum csReturnType {
    DEASSERT_NEVER          = 0,
    DEASSERT_AFTER_LAST     = 1,
    DEASSERT_EVERY_TRANSFER = 2,
};

/*
 *****************************************************************************-
 *
 *  dspiDMAStruct
 *
 *  bool enabled - whether or not the driver is using DMA for the transfer
 *
 *  uint8_t byteCount - the bytes transfer per dma call
 *
 *  uint32_t savedMCR - the actual MCR value, saved when doing DMA based transfer
 *                      as the CS inactive state is inverted on the active CS
 *
 *****************************************************************************-
 */
typedef struct
{
    bool enabled;
    uint8_t byteCount;
    bool rxPresent;
    bool txPresent;
    dspistruct savedDSPI;
    bool csState;
} dspiDMAStruct;

/*
 *****************************************************************************-
 *
 *   dspiDriverStruct
 *
 *   This struct contains the major variables/configurations used for a DSPI transfer
 *
 *   volatile BYTE* pDSPIRxbuf/pDSPITxbuf -
 *   These pointers are used to track the locations in memory where data will be
 *   read or written to the peripheral
 *
 *   BYTE BitsPerQueue - This is the number if bits per transfer, (value = 8 - 32)
 *
 *   DWORD DSPI_SizeLeft - This is the number if bytes left in the transfer
 *
 *   WORD Command_Mask - This is a partial configuration for the queue's command reg
 *
 *   OS_SEM* DSPI_Sem - This is a pointer to an external semaphore provided by DSPIStart()
 *
 *   BYTE DSPI_INT_STATUS - Status of the spi device
 *
 *   DWORD WordsToWrite - Number of words to write to the command/TX Queues and Read from RX
 *
 *   DWORD LastWordsToWrite - the amount from the previous ISR
 *
 *****************************************************************************-
 */
typedef struct
{
    volatile BYTE* pDSPIRxbuf;
    volatile BYTE* pDSPITxbuf;
    BYTE BitsPerQueue;
    DWORD DSPI_SizeLeft;
    WORD Command_Mask;
    csReturnType csReturnToInactive;
    OS_SEM* DSPI_Sem;
    volatile BYTE DSPI_INT_STATUS;
    DWORD WordsToWrite;
    DWORD LastWordsToWrite;
    volatile BOOL DSPIfinished;
    dspiDMAStruct dma;
} dspiDriverStruct;

BYTE DSPIInit( BYTE SPIModule, DWORD Baudrate, BYTE QueueBitSize, BYTE CS,
                BYTE CSPol, BYTE ClkPolarity, BYTE ClkPhase, BOOL DoutHiz, BYTE QCD, BYTE DTL );

class DSPIModule
{
    uint32_t    m_moduleNum;
    uint32_t    m_mcr;
    uint32_t    m_ctar0;
    uint32_t    m_ctar1;
    bool        m_enableDMA;
    uint16_t    m_CommandMask;
    uint8_t     m_BitsPerQueue;
    OS_SEM      *m_finishedSem;
    uint32_t    m_actualBaudrate;

public:
    bool        m_inProgress;

    static  DSPIModule *lastCxts[DSPI_MODULE_COUNT];
    static  dspiDriverStruct driverCxt[DSPI_MODULE_COUNT];


    DSPIModule( BYTE SPIModule );
    DSPIModule( BYTE SPIModule, DWORD baudRateInBps,
            BYTE transferSizeInBits = 8, BYTE peripheralChipSelects = 0x00,
            BYTE chipSelectPolarity = 0x0F, BYTE clockPolarity = 0,
            BYTE clockPhase = 1, BOOL doutHiz = TRUE,
            BYTE csToClockDelay = 0, BYTE delayAfterTransfer = 0 );

    BYTE Init( DWORD baudRateInBps = 2000000,
            BYTE transferSizeInBits = 8, BYTE peripheralChipSelects = 0x00,
            BYTE chipSelectPolarity = 0x0F, BYTE clockPolarity = 0,
            BYTE clockPhase = 1, BOOL doutHiz = TRUE,
            BYTE csToClockDelay = 0, BYTE delayAfterTransfer = 0 );


    BYTE Start( uint8_t *transmitBufferPtr, volatile uint8_t *receiveBufferPtr,
                uint32_t byteCount, int csReturnToInactive = DEASSERT_AFTER_LAST );

    bool EnableDMA(bool enableDMA = true);
    inline bool DisableDMA() { return EnableDMA(false); }

    bool SetSem( OS_SEM *finishedSem );
    inline bool ClrSem() { return SetSem(NULL); }

    inline bool Done() { return !m_inProgress; }
    static BOOL Done( BYTE SPIModule );

    inline uint32_t GetActualBaudrate() { return m_actualBaudrate; }

    inline bool SetCS( uint8_t CS )
    {
        OSLockObj lock;
        if (m_inProgress) { return false; }
        m_CommandMask = (((m_mcr >> 16) ^ CS) & 0xFF);
        return true;
    }
    friend BYTE DSPIInit( BYTE SPIModule, DWORD Baudrate, BYTE QueueBitSize, BYTE CS,
                BYTE CSPol, BYTE ClkPolarity, BYTE ClkPhase, BOOL DoutHiz, BYTE QCD, BYTE DTL );
};



/*
 *****************************************************************************-
 *
 *  Initialize DMA Serial Peripheral Interface (DSPI)
 *
 *      Parameters:
 *          baudRateInBps          - Maximum speed requested. (1) (2)
 *          transferSizeInBits     - 8 thru 32 valid (3)
 *          SPIModule              - the dspi module to target on the processor
 *          peripheralChipSelects  - DSPI_CS[7:0] (4)
 *          chipSelectPolarity     - CS[7:0] 0 inactive logic level low, 1 high
 *          clockPolarity          - 0 inactive logic level low, 1 high
 *          clockPhase             - 0 (5) or 1 (6)
 *          doutHiz                - Data output high impedance between transfers
 *          csToClockDelay         - Delay form chip select to valid clock (7)
 *          delayAfterTransfer     - Delay between data transfers (8)
 *
 *      Return:
 *          Current DSPI state     - DSPI_OK success or DSPI_BUSY busy
 *
 *      Notes:
 *          (1) Maximum BAUD rate is CPU_CLOCK / 3
 *          (2) Will select highest BAUD rate available that does not exceed.
 *          (3) Transfers > 8 must be word aligned
 *          (4) Select based on chipSelectPolarity
 *          (5) 0 data captured leading edge of DSPI_CLK, changed following edge.
 *          (6) 1 data changed leading edge of DSPI_CLK, captured following edge.
 *          (7) 0 default is as close to 1/2 DSPI_CLK without going under,
 *              keeping with the interface to QSPI
 *          (8) 0 default is 17/(system clock / 2), in keepin with interface to QSPI
 *
 *****************************************************************************-
 */

BYTE DSPIInit( BYTE SPIModule = DEFAULT_DSPI_MODULE, DWORD baudRateInBps = 2000000,
        BYTE transferSizeInBits = 8, BYTE peripheralChipSelects = 0x00,
        BYTE chipSelectPolarity = 0x0F, BYTE clockPolarity = 0,
        BYTE clockPhase = 1, BOOL doutHiz = TRUE,
        BYTE csToClockDelay = 0, BYTE delayAfterTransfer = 0 );

/*
 *****************************************************************************-
 *
 *  Start DSPI Data Transfer
 *
 *      Parameters:
 *          transmitBufferPtr   - Buffer with data to send, NULL for receiving
 *          receiveBufferPtr    - Buffer to receive data, NULL for sending
 *          byteCount           - Count of bytes to send or receive
 *          SPIModule           - Selects the dspi module to use
 *          finishedSem         - Optional semaphore to set when completed
 *
 *      Return:
 *          Current DSPI state  - DSPI_OK success or DSPI_BUSY busy
 *
 *      Notes:
 *          None
 *
 *****************************************************************************-
 */

BYTE DSPIStart( BYTE SPIModule, PBYTE transmitBufferPtr, volatile BYTE* receiveBufferPtr,
      DWORD byteCount, OS_SEM* finishedSem = NULL, BYTE enableDMA = TRUE,
      int csReturnToInactive = DEASSERT_AFTER_LAST );

/*
 *****************************************************************************-
 *
 * Check current DSPI Data Transfer
 *
 *    Parameters:
 *       None
 *
 *    Return:
 *       Progress of transfer    - TRUE is finished, FALSE is active
 *
 *    Notes:
 *       None
 *
 *****************************************************************************-
 */

BOOL DSPIdone( BYTE SPIModule = DEFAULT_DSPI_MODULE );

// QSPI to DSPITranslation macros
//  Translates QSPI calls to DSPI calls

inline BYTE QSPIInit( DWORD baudRateInBps = 2000000, BYTE transferSizeInBits = 8,
      BYTE peripheralChipSelects = 0x0F, BYTE chipSelectPolarity = 1,
      BYTE clockPolarity = 0, BYTE clockPhase = 1, BOOL doutHiz = TRUE,
      BYTE csToClockDelay = 0, BYTE delayAfterTransfer = 0 )
{
    return DSPIInit( DEFAULT_DSPI_MODULE, baudRateInBps, transferSizeInBits,
                peripheralChipSelects, chipSelectPolarity, clockPolarity, clockPhase,
                doutHiz, csToClockDelay, delayAfterTransfer );
}

inline BYTE QSPIStart( PBYTE transmitBufferPtr, volatile BYTE* receiveBufferPtr,
      DWORD byteCount, OS_SEM* finishedSem = NULL )
{
    return DSPIStart( DEFAULT_DSPI_MODULE, transmitBufferPtr, receiveBufferPtr,
                byteCount, finishedSem );
}

inline BOOL QSPIdone( )
{
    return DSPIdone( );
}

#endif   /* ----- #ifndef _DMA_SPI_H_INC  ----- */
