/**********************************************************************************************************************
 *  COPYRIGHT
 *  -------------------------------------------------------------------------------------------------------------------
 *  \verbatim
 *                 TEXAS INSTRUMENTS INCORPORATED PROPRIETARY INFORMATION
 *
 *                 Property of Texas Instruments, Unauthorized reproduction and/or distribution
 *                 is strictly prohibited.  This product  is  protected  under  copyright  law
 *                 and  trade  secret law as an  unpublished work.
 *                 (C) Copyright Texas Instruments - 2012.  All rights reserved.
 *
 *  \endverbatim
 *  -------------------------------------------------------------------------------------------------------------------
 *  FILE DESCRIPTION
 *  -------------------------------------------------------------------------------------------------------------------
 *         File:  Spi.c
 *      Project:  Tms570_AutoSarSpiDriver
 *       Module:  SpiDriver module Spi_DlcDma.c
 *    Generator:  -
 *
 *  Description:  This file implements the Spi Dma support, handling of channels and transmission settings.
 *---------------------------------------------------------------------------------------------------------------------
 * Author:  Prathap Srinivasan
 *---------------------------------------------------------------------------------------------------------------------
 * Revision History
 *---------------------------------------------------------------------------------------------------------------------
 * Version        Date         Author               Change ID        Description
 *---------------------------------------------------------------------------------------------------------------------
 * 02.10.00       24Jan2013    Prathap Srinivasan  0000000000000    Initial Version adapted for TMS570LS1227
 * 02.20.00       08Aug2013    Enrique Lizarraga   SDOCM00103201    Updated version info
 * 02.21.00       30Sep2014    Enrique Lizarraga   SDOCM00112317    - Updated version info
 *                                                                  - MISRA exceptions
 * 02.21.01       29Feb2016    Enrique Lizarraga   SDOCM00121246    - Update version info
 * 02.22.00       18Jul2016    Prathap Srinivasan  SDOCM00122408    -Update version info
 * 																	-Added Sync Polling Mode Support
 * 02.22.01       10Aug2016    Prathap Srinivasan  SDOCM00122593    -Bug Fix: Spi_IrqTxRxERR function checks for
 *                                                                   wrong error status bit
 * 02.22.02       23Aug2016    Vishwanath Reddy    SDOCM00121246    -Update version info
 * 02.22.03       26Sep2016    Prathap Srinivasan  SDOCM00122695    -Update version info
 * 02.30.00       01Dec2016    Sudhakar Singh         None          -Update version info
 * 05.30.00       15Mar2017    Sudhakar Singh      SDOCM00122834    Version supports TMS570LSxx Family of Devices.
 *
 *********************************************************************************************************************/

#define SPI_DLCDMA_SOURCE 1

/**********************************************************************************************************************
 *  INCLUDES
 *********************************************************************************************************************/
#include "Std_Types.h"
#include "Spi_DlcDma.h"
#include "Spi_Dlc.h"

/**********************************************************************************************************************
 *  VERSION CHECK
 *********************************************************************************************************************/
#define SPI_DLCDMA_SW_C_MAJOR_VERSION               (5U)
#define SPI_DLCDMA_SW_C_MINOR_VERSION               (30U)
#define SPI_DLCDMA_SW_C_PATCH_VERSION               (0U)

 /* vendor specific version information is BCD coded */
#if (  (SPI_DLCDMA_SW_MAJOR_VERSION != SPI_DLCDMA_SW_C_MAJOR_VERSION) \
    || (SPI_DLCDMA_SW_MINOR_VERSION != SPI_DLCDMA_SW_C_MINOR_VERSION) \
    || (SPI_DLCDMA_SW_PATCH_VERSION != SPI_DLCDMA_SW_C_PATCH_VERSION) )
  #error "Vendor specific version numbers of Spi_DlcDma.c and Spi_DlcDma.h are inconsistent"
#endif

/**********************************************************************************************************************
 *  LOCAL CONSTANT MACROS
 **********************************************************************************************************************/

/* the Spi uses max five Channel_u16s for Tx/Rx with 10 requests */

#define DMA_HW_Channel_u16_NUMBER    (16U)

/**********************************************************************************************************************
 *  LOCAL FUNCTION MACROS
 **********************************************************************************************************************/

/**********************************************************************************************************************
 *  LOCAL DATA TYPES AND STRUCTURES
 **********************************************************************************************************************/

/**********************************************************************************************************************
 *  LOCAL DATA PROTOTYPES
 **********************************************************************************************************************/

/**********************************************************************************************************************
 *  GLOBAL DATA
 **********************************************************************************************************************/
#define SPI_START_SEC_VAR_INIT_UNSPECIFIED
#include "MemMap.h"

static VAR(Dma_StatusType, SPI_VAR) Dma_ModuleInitFlag = DMA_UNINIT;
/* DMa support for max 5 HWUnits */

Dma_GlobalRegisterPtrType Dma_GlobalRegister = DMA_GLOBAL_REGISTER_BASE_ADDRESS;

#define SPI_STOP_SEC_VAR_INIT_UNSPECIFIED
/*SAFETYMCUSW 338 S MR:19.1 <APPROVED> "Based on Autosar Memory Map strategy" */
#include "MemMap.h"

/**********************************************************************************************************************
 *  LOCAL FUNCTION PROTOTYPES
 **********************************************************************************************************************/
#undef SPI_START_SEC_CODE
#define SPI_START_SEC_CODE
/*SAFETYMCUSW 338 S MR:19.1 <APPROVED> "Based on Autosar Memory Map strategy" */
#include "MemMap.h"

/**********************************************************************************************************************
 *  LOCAL FUNCTIONS
 **********************************************************************************************************************/

FUNC(void, SPI_CODE) Dma_Init( void )
{
    uint32 *volatile ReqMaskSet1 = VIM_REQMASKSET1;   /* Temporary pointer to interrupt request mask set register */
    uint32 *volatile ReqMaskClr1 = VIM_REQMASKCLR1;   /* Temporary pointer to interrupt request mask clear register */
    /*SAFETYMCUSW 7 C MR:14.7 <APPROVED> "Reason - Development error check "*/
    /* dma has already been initilized */
    if(Dma_ModuleInitFlag != DMA_IDLE)
    {
        /* ====== Initialization 1 of Global Control Register ====== */
        /* Cause a self reset of the DMA hardware module to reach a defined state of all global registers of DMA module,
        * switch the debug mode off and set DMA to disabled */
        Dma_GlobalRegister->DMA_GCTRL = 0x00000001U;
        /* Reset the reset bit of the DMA hardware module
        *  Stop at DMA arbitration boundary during suspend/debug and set DMA to disabled */
        Dma_GlobalRegister->DMA_GCTRL = 0x00000300U;

        /* ====== Initialization of HW Channel_u16 Enable Register ====== */
        /* No initialization needed, all Channel_u16s are disabled after reset. */
        /* Initialization not needed but done because there is no statement in manual about reset state of this register */
        Dma_GlobalRegister->DMA_HWCHENAR = 0xFFFFFFFFU;

        /* ====== Initialization of SW Channel_u16 Enable Register ====== */
        /* No initialization needed, all Channel_u16s are disabled after reset. */
        /* Initialization not needed but done because there is no statement in manual about reset state of this register */
        Dma_GlobalRegister->DMA_SWCHENAR = 0xFFFFFFFFU;

        /* ====== Initialization of Interrupt Enable Register ====== */
        /* Enable all Dma interrupts globally, but disable all Dma interrupts themselves */

        /* Initialization not needed but done because there is no statement in manual about reset state of this register */
        Dma_GlobalRegister->DMA_FTCINTENAR = 0xFFFFFFFFU;  /* disable frame transfer complete interrupt */
        /* Initialization not needed but done because there is no statement in manual about reset state of this register */
        Dma_GlobalRegister->DMA_LFSINTENAR = 0xFFFFFFFFU;  /* disable last frame started interrupt */
        /* Initialization not needed but done because there is no statement in manual about reset state of this register */
        Dma_GlobalRegister->DMA_HBCINTENAR = 0xFFFFFFFFU;  /* disable half block complete interrupt */
        /* Initialization not needed but done because there is no statement in manual about reset state of this register */
        Dma_GlobalRegister->DMA_BTCINTENAR = 0xFFFFFFFFU;  /* disable block transfer complete interrupt */

        /* DMA FTCA interrupt uses interrupt request line #33, enabled by REQMASKSET0 [33] = REQMASKSET1 [1]
         *                                                    disabled by REQMASKCLR0 [33] = REQMASKSET1 [1]
         * DMA LFSA interrupt uses interrupt request line #34, enabled by REQMASKSET0 [34] = REQMASKSET1 [2]
         *                                                    disabled by REQMASKCLR0 [34] = REQMASKSET1 [2]
         * DMA HBCA interrupt uses interrupt request line #39, enabled by REQMASKSET0 [39] = REQMASKSET1 [7]
         *                                                    disabled by REQMASKCLR0 [39] = REQMASKSET1 [7]
         * DMA BTCA interrupt uses interrupt request line #40, enabled by REQMASKSET0 [40] = REQMASKSET1 [8]
         *                                                    disabled by REQMASKCLR0 [40] = REQMASKSET1 [8]
		 */
		 
        *ReqMaskSet1 |= (DMA_BIT(1U) | DMA_BIT(8U));   /* enable needed Dma interrupts by setting the RequestMask */

        Dma_GlobalRegister->DMA_GCHIENAS = ((uint32) 0xFFFFFFFFU);    /* enable all Dma interrupts globally */

        /* ====== Initialization of Port Assignment Registers ====== */
        /* Set Port assignment of all Channel_u16s to Port B only. Port A seems to be not implemented in TMS570PSFC66 */
        Dma_GlobalRegister->DMA_PAR[0U] = 0x77777777U;
        #if DMA_HW_Channel_u16_NUMBER > 8U
        Dma_GlobalRegister->DMA_PAR[1U] = 0x77777777U;    /* only needed if more than 8 hardware Channel_u16s are available */
        #endif
        #if DMA_HW_Channel_u16_NUMBER > 16U
        Dma_GlobalRegister->DMA_PAR[2U] = 0x77777777U;    /* only needed if more than 16 hardware Channel_u16s are available */
        #endif
        #if DMA_HW_Channel_u16_NUMBER > 24U
        Dma_GlobalRegister->DMA_PAR[3U] = 0x77777777U;    /* only needed if more than 24 hardware Channel_u16s are available */
        #endif

        /* ====== Initialization of Channel_u16 Priority Register ====== */
        /* No initialization needed, all Channel_u16s are set to low priority after reset. */
        /* ====== Initialization of Interrupt Mapping Registers ====== */
        /* No initialization needed, all requests are routed to ARM core after reset. */
        /* ====== Initialization of Fall Back Register ====== */
        /* Currently unknown if initialization is needed. */
        /* ====== Initialization of Port Control Register ====== */
        /* Currently unknown if initialization is needed. */
        /* Note: Definition of priority scheme (fixed priority/round robin) can be made in this register. */
        /* Note: DMA module of TMS570 uses a FIFO buffer.
         * Bypassing of FIFO can be switched on in this register. */
        /* ====== Initialization of RAM Test Control Register ====== */
        /* Currently unknown if initialization is needed. */
        /* ====== Initialization of Debug Control Register ====== */
        /* Currently unknown if initialization is needed. */
        /* ====== Initialization of Watch Point Register ====== */
        /* Currently unknown if initialization is needed. */
        /* ====== Initialization of Watch Mask Register ====== */
        /* Currently unknown if initialization is needed. */
        /* ====== Initialization of Parity Control Register ====== */
        /* Currently unknown if initialization is needed. */
        /* ====== Initialization of Memory Protection Control Register ====== */
        /* Currently unknown if initialization is needed. */
        /* ====== Initialization of Memory Protection Region Registers ====== */
        /* Currently unknown if initialization is needed. */
        Dma_GlobalRegister->DMA_DMAPCR = 0x5U;
        /* ====== Initialization 2 of Global Control Register ====== */
        /* Set DMA to enabled */
        Dma_GlobalRegister->DMA_GCTRL    |= 0x00010000U;

        /* Set initialization flag to not uninit */
        Dma_ModuleInitFlag = DMA_IDLE;
	}
} /* End of Dma_Init() */

FUNC(void, SPI_CODE) Dma_DeInit( void )
{
	/*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Reason - Assigned global register base address"*/
    /* ====== disable and reset hardware ====== */
    /* Cause a self reset of the DMA hardware module to reach a defined state of all global registers of DMA module,
     * switch the debug mode off and set DMA to disabled */
    Dma_GlobalRegister->DMA_GCTRL = (uint32)0x00000001U;
    /* Reset the reset bit of the DMA hardware module */
    Dma_GlobalRegister->DMA_GCTRL = (uint32)0x00000000U;
    /* ====== set initialization flag to uninit ====== */
    Dma_ModuleInitFlag = DMA_UNINIT;

} /* End of Dma_DeInit() */

FUNC(void, SPI_CODE) Dma_Setup
(
    P2CONST(Dma_ChannelSetupType, AUTOMATIC, SPI_VAR) Setup
)
{
	CONST(Dma_RequestType, SPI_VAR) Dma_MapReqLine[5U] =
	{
	    {SPI_DLC_RXUNIT0, SPI_DLC_TXUNIT0},
	    {SPI_DLC_RXUNIT1, SPI_DLC_TXUNIT1},
	    {SPI_DLC_RXUNIT2, SPI_DLC_TXUNIT2},
	    {SPI_DLC_RXUNIT3, SPI_DLC_TXUNIT3},
	    {SPI_DLC_RXUNIT4, SPI_DLC_TXUNIT4}
	};

	uint16 Channel_u16;
    uint16 Unit_u16;

    Channel_u16 = Setup->Channel;
    Unit_u16    = Setup->Unit;

    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].ISADDR   = Setup->SrcAddr;
    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].IDADDR   = Setup->DstAddr;
    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].IFTCOUNT = Setup->FCount;
    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].IETCOUNT = Setup->ECount;
    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].CHCTRL   = Setup->ChCtrl;

    /* configure the Channel_u16s for Dma transmission channels [0 = Tx, 1= Rx]
     * they will be connected later to the Spi Channel_u16 in DMAxCTRL
     */
    if(Setup->Direction == DMA_TX)
    {
       DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].CHCTRL_CHAIN = 0U;
       /* DMA_REQ_SPIx for C66 TxData */
       Dma_GlobalRegister->DMA_DREQASI[Channel_u16] = Dma_MapReqLine[Unit_u16].DmaReq[1U];
       /* enable channel for hardware requests */
       Dma_GlobalRegister->DMA_HWCHENAS = ((uint32)1U << Channel_u16);
    }
    else
    {
       DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].CHCTRL_CHAIN = 0U;
       /* DMA_REQ_SPIx for C66 RxData */
       Dma_GlobalRegister->DMA_DREQASI[Channel_u16] = Dma_MapReqLine[Unit_u16].DmaReq[0U];
       /* RX channel Interrupt Enable is done based on Sync or Async */
       /* enable channel for hardware requests */
       Dma_GlobalRegister->DMA_HWCHENAS = ((uint32)1U << Channel_u16);
    }

    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].EIDXS    = Setup->EISrcInc;
    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].EIDXD    = Setup->EIDstInc;
    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].FIDXS    = Setup->FISrcInc;
    DMA_PRIMARY_CONTROL_PACKET_BASE_ADDRESS->DMA_CHCTRL[Channel_u16].FIDXD    = Setup->FIDstInc;
}

FUNC(Dma_ChannelType, SPI_CODE) Dma_GetFree_Channel(void)
{
	Dma_ChannelType  Dma_ChId ; /* DMA channel identifier */
	uint32 Dma_Hwchenas;

    for(Dma_ChId=0U; Dma_ChId < 32U; Dma_ChId++)
    {
    	Dma_Hwchenas = Dma_GlobalRegister->DMA_HWCHENAS;
    	if((Dma_Hwchenas & (0x00000001U << Dma_ChId)) == 0U)
    	{
    		break;
    	}
    }
    return(Dma_ChId);
}

FUNC(void, SPI_CODE) Dma_DisableInt(uint32 Channel_u32)
{

    /* Disable BTC interrupts only on channel 1 (Rx ready) */
    Dma_GlobalRegister->DMA_BTCINTENAR = (uint32) (1U << Channel_u32);

}

FUNC(void, SPI_CODE) Dma_EnableInt(uint32 Channel_u32)
{

    /* enable BTC interrupts only on channel 1 (Rx ready) */
    Dma_GlobalRegister->DMA_BTCINTENAS = (uint32) (1U << Channel_u32);

}

FUNC(uint32, SPI_CODE) Dma_IsTransferComplete(uint32 Channel_u32)
{

	uint32 BTC_status;

	BTC_status = Dma_GlobalRegister->DMA_BTCFLAG & (uint32)(1U << Channel_u32);

	if(BTC_status!= 0)
	{
		/* clear BTC interrupt */
		Dma_GlobalRegister->DMA_BTCFLAG = BTC_status;
	}
	return BTC_status;
}
#undef SPI_STOP_SEC_CODE
#define SPI_STOP_SEC_CODE
/*SAFETYMCUSW 3
 * 38 S MR:19.1 <APPROVED> "Based on Autosar Memory Map strategy" */
#include "MemMap.h"
