//-------------------------------------------------------------------------------------------------------------------------
// Copyright (c) Samsung Electronics Co., Ltd.  All rights reserved.
//-------------------------------------------------------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
//
// Module Name :    ser_dma.cpp
//
//-------------------------------------------------------------------------------------------------------------------------




#ifdef USE_DMA 

/****************************************************************************************
 ***** INCLUDE FILES
 ****************************************************************************************/
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <bsp.h>
#include <ddkreg.h>
#include <serhw.h>
//#include <Serdbg.h>
#include <common_pdd_ser.h>
#include <register_map.h>
#include <oal_intr.h>
#include <dma_controller.h>

/****************************************************************************************
 ***** DEFINES
 ****************************************************************************************/


#define UART_DMA_INIT 0
#define UART_MSG 0

#define VERSION_INFO		"UART_DMA"
#define DateInformation		"001"

/****************************************************************************************
 ***** GLOBALS
 ****************************************************************************************/




/****************************************************************************************
 ***** FUNCTIONS
 ****************************************************************************************/

DWORD CPddUart::DMA_Init()
{
        BOOL bResult = TRUE;
        PHYSICAL_ADDRESS ioPhysicalBase = {0, 0};

/*  // not necessary
        if ( !pUartDma )
        {
                bResult = FALSE;
                goto CleanUp;
        }
*/
        // Syscon Virtual alloc
#ifdef NOUSE_MMI  
        ioPhysicalBase.LowPart = BASE_REG_PA_CMU_CLK;      
        pUartDma->pSYSCONregs = (volatile CMU_CLK_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(CMU_CLK_REG), FALSE);
#else
        pUartDma->pSYSCONregs = (volatile CMU_CLK_REG *)ML_VirtualAlloc(INDEX_SYSCON_CLK);
#endif 
        if (pUartDma->pSYSCONregs == NULL)
        {
                ERRMSG((TEXT("[UART][ERR] For pSYSCONregs: MmMapIoSpace failed !\r\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        // MDMAC Virtual alloc
#ifdef NOUSE_MMI     
        ioPhysicalBase.LowPart = BASE_REG_PA_MDMA;
        pUartDma->pDMACregs = (volatile DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
#else
        pUartDma->pDMACregs = (volatile DMAC_REG *)ML_VirtualAlloc(INDEX_MDMA);
#endif 
        if (pUartDma->pDMACregs == NULL)
        {
                ERRMSG((TEXT("[UART][ERR] For pDMACregs: MmMapIoSpace failed !\r\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        // DMAC0 Virtual alloc
#ifdef NOUSE_MMI         
        ioPhysicalBase.LowPart = BASE_REG_PA_PDMA0;      
        pUartDma->pDMAC0regs = (volatile DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
#else
        pUartDma->pDMAC0regs = (volatile DMAC_REG *)ML_VirtualAlloc(INDEX_PDMA0);
#endif 
        if (pUartDma->pDMAC0regs == NULL)
        {
                ERRMSG((TEXT("[UART][ERR] For pDMAC0regs: MmMapIoSpace failed !\r\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        // DMAC1 Virtual alloc
#ifdef NOUSE_MMI      
        ioPhysicalBase.LowPart = BASE_REG_PA_PDMA1;      
        pUartDma->pDMAC1regs = (volatile DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
#else
        pUartDma->pDMAC1regs = (volatile DMAC_REG *)ML_VirtualAlloc(INDEX_PDMA1);
#endif
        if (pUartDma->pDMAC1regs == NULL)
        {
                ERRMSG((TEXT("[UART][ERR] For pDMAC1regs: MmMapIoSpace failed !\r\n")));
                bResult = FALSE;
                goto CleanUp;
        }

CleanUp:
#ifdef NOUSE_MMI    
        if ( !bResult)
        {
                if (pUartDma->pDMACregs)
                {
                        MmUnmapIoSpace((PVOID)pUartDma->pDMACregs, sizeof(DMAC_REG));
                        pUartDma->pDMACregs = NULL;
                }

                if (pUartDma->pDMAC0regs)
                {
                        MmUnmapIoSpace((PVOID)pUartDma->pDMAC0regs, sizeof(DMAC_REG));
                        pUartDma->pDMAC0regs = NULL;
                }

                if (pUartDma->pDMAC1regs)
                {
                        MmUnmapIoSpace((PVOID)pUartDma->pDMAC1regs, sizeof(DMAC_REG));
                        pUartDma->pDMAC1regs = NULL;
                }

                if (pUartDma->pSYSCONregs)
                {
                        MmUnmapIoSpace((PVOID)pUartDma->pSYSCONregs, sizeof(CMU_CLK_REG));
                        pUartDma->pSYSCONregs = NULL;
                }

                bResult = FALSE;
        }
#endif 

        DMA_initialize_register_address((void *)pUartDma->pDMAC0regs,
                (void *)pUartDma->pDMAC1regs,
                (void *)pUartDma->pDMACregs,
                (void *)pUartDma->pSYSCONregs);

        return bResult;
}


BOOL CPddUart::InitializeBuffer()
{
        BOOL bResult = TRUE;
        DMA_ADAPTER_OBJECT Adapter1, Adapter2;

        DBGMSG(UART_USR1,(TEXT("++[UART] InitializeBuffer\n")));

        memset( &Adapter1, 0, sizeof(DMA_ADAPTER_OBJECT));
        Adapter1.InterfaceType = Internal;
        Adapter1.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
        Adapter1.BusNumber= 0;
        
        memset( &Adapter2, 0, sizeof(DMA_ADAPTER_OBJECT));
        Adapter2.InterfaceType = Internal;
        Adapter2.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
        Adapter2.BusNumber= 0;

        // Allocate a block of virtual memory (physically contiguous) for the DMA buffers.
        pVirtDmaRxBufferAddr = (PBYTE)HalAllocateCommonBuffer( &Adapter1, RX_BUFFER_SIZE, &PhysDmaRxBufferAddr, FALSE);
        DBGMSG(UART_USR1, (TEXT("[UART] InitializeBuffer() pVirtDmaRxBufferAddr: %x\r\n"),pVirtDmaRxBufferAddr));

        if (pVirtDmaRxBufferAddr == NULL)
        {
                ERRMSG((TEXT("[UART][ERR] InitializeBuffer() - Failed to allocate DMA buffer for UART\r\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        pVirtDmaSrcBufferAddr = (PBYTE)HalAllocateCommonBuffer( &Adapter2, Buffer_Mem_Size, &PhysDmaSrcBufferAddr, FALSE);
        DBGMSG(UART_USR1, (TEXT("[UART] InitializeBuffer() pVirtDmaSrcBufferAddr: %x\r\n"),pVirtDmaSrcBufferAddr));

        if (pVirtDmaSrcBufferAddr == NULL)
        {
                ERRMSG((TEXT("[UART][ERR] InitializeBuffer() - Failed to allocate DMA buffer for UART\r\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        DmaRxAddress = (UINT)(PhysDmaRxBufferAddr.LowPart);    
        DmaSrcAddress = (UINT)(PhysDmaSrcBufferAddr.LowPart);    

        memset(pVirtDmaRxBufferAddr, 0xFF, RX_BUFFER_SIZE);
        
        DBGMSG(UART_USR1, (TEXT("[UART] pVirtDmaSrcBufferAddr 0x%x   DmaSrcAddress 0x%x \r\n"),pVirtDmaSrcBufferAddr, DmaSrcAddress));    
        DBGMSG(UART_USR1, (TEXT("[UART] pVirtDmaRxBufferAddr 0x%x   DmaRxAddress 0x%x \r\n"),pVirtDmaRxBufferAddr, DmaRxAddress));            
        DBGMSG(UART_USR1,(TEXT("-[UART] InitializeBuffer\n")));

CleanUp:
        return bResult;
}


BOOL CPddUart::InitializeChannel()
{
        BOOL bResult= TRUE;
        int  RxDMASrc = DMAsrc_UART_0_RX + (pUartDma->m_chnum*2);
        int  TxDMASrc = DMAsrc_UART_0_TX + (pUartDma->m_chnum*2);
        
        //RX DMA Init    
        if( DMA_request_channel( pRxDMA, (DREQ_SRC)RxDMASrc) != TRUE )
        {
                ERRMSG((TEXT("[UART][ERR] DMA UART TX channel request is failed\n")));
                bResult = FALSE;   
        }

        //TX DMA Init    
        if( DMA_request_channel( pOutputDMA, (DREQ_SRC)TxDMASrc) != TRUE )
        {
                ERRMSG((TEXT("[UART][ERR] DMA UART TX channel request is failed\n")));
                bResult = FALSE;   
        }

        return bResult;    
}

PVOID CPddUart::InitializeDMA(DWORD nCH)
{

        BOOL  bResult = TRUE;
        DWORD dwHwIntr= 0;

        DBGMSG(UART_USR1,(TEXT("++[UART] InitializeDMA Function\r\n")));

        DBGMSG(UART_USR1,(TEXT("********************************\r\n")));
        DBGMSG(UART_USR1,(TEXT("[UART] %a_%a\r\n"),VERSION_INFO,DateInformation));
        DBGMSG(UART_USR1,(TEXT("********************************\r\n")));

        if ( !(pUartDma = (PDMA_PUBLIC_CONTEXT)LocalAlloc( LPTR, sizeof(DMA_PUBLIC_CONTEXT) )) )
        {
                ERRMSG((TEXT("[UART][ERR] Can not allocate for UART Context\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        if ( !(pRxDMA = (DMA_CH_CONTEXT *)LocalAlloc( LPTR, sizeof(DMA_CH_CONTEXT) )) )
        {
                ERRMSG((TEXT("[UART][ERR] Can not allocate for RxDMA Context\n")));
                bResult = FALSE;
                goto CleanUp;
        }
        
        if ( !(pOutputDMA = (DMA_CH_CONTEXT *)LocalAlloc( LPTR, sizeof(DMA_CH_CONTEXT) )) )
        {
                ERRMSG((TEXT("[UART][ERR] Can not allocate for OutputDMA Context\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        pUartDma->m_chnum = nCH;
        pUartDma->dwRxDmaThreadPrio = RX_DMA_THREAD_PRIORITY;
        pUartDma->dwTxDmaThreadPrio = TX_DMA_THREAD_PRIORITY;

        if( !InitializeBuffer())
        {
                ERRMSG((TEXT("[UART][ERR] InitializeBuffer is failed\n")));
                bResult = FALSE;
                goto CleanUp;
        }

        DMA_Init();
        InitializeChannel();

        do
        {

             //Rx DMA Done ISR
                pUartDma->dwRxDmaDoneSysIntr = SYSINTR_NOP;
                dwHwIntr = pRxDMA->dwIRQ;
                pUartDma->hRxDmaDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
                pUartDma->hRxDmaTimeoutEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

                if ( !KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwHwIntr, sizeof(DWORD), &pUartDma->dwRxDmaDoneSysIntr, sizeof(DWORD), NULL))
                {
                        ERRMSG((TEXT("[UART][ERR] Failed to request the UART_RX_DMA sysintr.\n")));
                        pUartDma->dwRxDmaDoneSysIntr = SYSINTR_UNDEFINED;
                        bResult = FALSE;
                        break;
                }

                if ( !InterruptInitialize(pUartDma->dwRxDmaDoneSysIntr, pUartDma->hRxDmaDoneEvent, NULL, 0))
                {
                        ERRMSG((TEXT("[UART][ERR] RX DMA Interrupt Initialization failed !!!\n")));
                        bResult = FALSE;
                        break;
                }
                //Tx DMA Done ISR
                pUartDma->dwTxDmaDoneSysIntr = SYSINTR_NOP;
                dwHwIntr = pOutputDMA->dwIRQ;
                pUartDma->hTxDmaDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

                pUartDma->RXDMAEventHandles[1] = pUartDma->hRxDmaDoneEvent;
                pUartDma->RXDMAEventHandles[0] = pUartDma->hRxDmaTimeoutEvent;                

                if ( !KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwHwIntr, sizeof(DWORD), &pUartDma->dwTxDmaDoneSysIntr, sizeof(DWORD), NULL))
                {
                        ERRMSG((TEXT("[UART][ERR] Failed to request the UART_DMA sysintr.\n")));
                        pUartDma->dwTxDmaDoneSysIntr = SYSINTR_UNDEFINED;
                        bResult = FALSE;
                        break;
                }

                if ( !InterruptInitialize(pUartDma->dwTxDmaDoneSysIntr, pUartDma->hTxDmaDoneEvent, NULL, 0))
                {
                        ERRMSG((TEXT("[UART][ERR] DMA Interrupt Initialization failed !!!\n")));
                        bResult = FALSE;
                        break;
                }
        } while (0);

CleanUp:
        DBGMSG(UART_USR1,(TEXT("--[UART] InitializeDMA  Function\r\n")));
        if(bResult)
        {
                return pUartDma;
        }
        else
        {
                return NULL;
        }
}


BOOL DmaPowerUp()
{
        BOOL bResult = TRUE;
        return bResult;
}

BOOL DmaPowerDown()
{
        BOOL bResult = TRUE;
        return bResult;
}

#endif //USE_DMA
