//<MStar Software>
//******************************************************************************
// MStar Software
// Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
// All software, firmware and related documentation herein ("MStar Software") are
// intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
// law, including, but not limited to, copyright law and international treaties.
// Any use, modification, reproduction, retransmission, or republication of all 
// or part of MStar Software is expressly prohibited, unless prior written 
// permission has been granted by MStar. 
//
// By accessing, browsing and/or using MStar Software, you acknowledge that you
// have read, understood, and agree, to be bound by below terms ("Terms") and to
// comply with all applicable laws and regulations:
//
// 1. MStar shall retain any and all right, ownership and interest to MStar
//    Software and any modification/derivatives thereof.
//    No right, ownership, or interest to MStar Software and any
//    modification/derivatives thereof is transferred to you under Terms.
//
// 2. You understand that MStar Software might include, incorporate or be
//    supplied together with third party`s software and the use of MStar
//    Software may require additional licenses from third parties.  
//    Therefore, you hereby agree it is your sole responsibility to separately
//    obtain any and all third party right and license necessary for your use of
//    such third party`s software. 
//
// 3. MStar Software and any modification/derivatives thereof shall be deemed as
//    MStar`s confidential information and you agree to keep MStar`s 
//    confidential information in strictest confidence and not disclose to any
//    third party.  
//
// 4. MStar Software is provided on an "AS IS" basis without warranties of any
//    kind. Any warranties are hereby expressly disclaimed by MStar, including
//    without limitation, any warranties of merchantability, non-infringement of
//    intellectual property rights, fitness for a particular purpose, error free
//    and in conformity with any international standard.  You agree to waive any
//    claim against MStar for any loss, damage, cost or expense that you may
//    incur related to your use of MStar Software.
//    In no event shall MStar be liable for any direct, indirect, incidental or
//    consequential damages, including without limitation, lost of profit or
//    revenues, lost or damage of data, and unauthorized system use.
//    You agree that this Section 4 shall still apply without being affected
//    even if MStar Software has been modified by MStar in accordance with your
//    request or instruction for your use, except otherwise agreed by both
//    parties in writing.
//
// 5. If requested, MStar may from time to time provide technical supports or
//    services in relation with MStar Software to you for your use of
//    MStar Software in conjunction with your or your customer`s product
//    ("Services").
//    You understand and agree that, except otherwise agreed by both parties in
//    writing, Services are provided on an "AS IS" basis and the warranty
//    disclaimer set forth in Section 4 above shall apply.  
//
// 6. Nothing contained herein shall be construed as by implication, estoppels
//    or otherwise:
//    (a) conferring any license or right to use MStar name, trademark, service
//        mark, symbol or any other identification;
//    (b) obligating MStar or any of its affiliates to furnish any person,
//        including without limitation, you and your customers, any assistance
//        of any kind whatsoever, or any information; or 
//    (c) conferring any license or right under any intellectual property right.
//
// 7. These terms shall be governed by and construed in accordance with the laws
//    of Taiwan, R.O.C., excluding its conflict of law rules.
//    Any and all dispute arising out hereof or related hereto shall be finally
//    settled by arbitration referred to the Chinese Arbitration Association,
//    Taipei in accordance with the ROC Arbitration Law and the Arbitration
//    Rules of the Association by three (3) arbitrators appointed in accordance
//    with the said Rules.
//    The place of arbitration shall be in Taipei, Taiwan and the language shall
//    be English.  
//    The arbitration award shall be final and binding to both parties.
//
//******************************************************************************
//<MStar Software>
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2009 MStar Semiconductor, Inc.
// All rights reserved.
//
// Unless otherwise stipulated in writing, any and all information contained
// herein regardless in any format shall remain the sole proprietary of
// MStar Semiconductor Inc. and be kept in strict confidence
// ("MStar Confidential Information") by the recipient.
// Any unauthorized act including without limitation unauthorized disclosure,
// copying, use, reproduction, sale, distribution, modification, disassembling,
// reverse engineering and compiling of the contents of MStar Confidential
// Information is unlawful and strictly prohibited. MStar hereby reserves the
// rights to any and all damages, losses, costs and expenses resulting therefrom.
//
////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////
///
/// file    drvMMIO.c
/// @brief  MMIO SYS Driver Interface
/// @author MStar Semiconductor Inc.
///////////////////////////////////////////////////////////////////////////////////////////////////


//-------------------------------------------------------------------------------------------------
//  Include Files
//-------------------------------------------------------------------------------------------------
#ifdef MSOS_TYPE_LINUX
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "MsCommon.h"
#include "drvMMIO.h"
#include "halMMIO.h"
#include "regCHIP.h"

/* Use 'I' as magic number */
#define MIOMAP_IOC_MAGIC                    'I'
#define MMIO_IOC_SET_MAP                    _IOW (MIOMAP_IOC_MAGIC, 0x01, MIOMap_Info_t)

/* MIOMAP_IOC_INFO */
typedef struct
{
    MS_U64                                  u64Addr;
    MS_U64                                  u64Size;
} MIOMap_Info_t;
#else // #ifdef MSOS_TYPE_LINUX
#include "MsCommon.h"
#include "drvMMIO.h"
#include "halMMIO.h"
#include "regCHIP.h"
#endif

#include "MsVersion.h"
#include "ULog.h"


//-------------------------------------------------------------------------------------------------
//  Driver Compiler Options
//-------------------------------------------------------------------------------------------------
#ifdef MS_DEBUG
#define MMIO_DEBUG
#endif


//-------------------------------------------------------------------------------------------------
//  Local Defines
//-------------------------------------------------------------------------------------------------
#ifdef MMIO_DEBUG
#define MMIO_ERROR(fmt, args...)        MS_DEBUG_MSG(ULOGE("MMIO", "[%s][%06d]     " fmt, __FUNCTION__, __LINE__, ##args))
#define MMIO_WARN(fmt, args...)         MS_DEBUG_MSG(ULOGW("MMIO", "[%s][%06d]     " fmt, __FUNCTION__, __LINE__, ##args))
#define MMIO_PRINT(fmt, args...)        MS_DEBUG_MSG(ULOGI("MMIO", "[%s][%06d]     " fmt, __FUNCTION__, __LINE__, ##args))
#define MMIO_ASSERT(_bool, _f)          if (!(_bool)) { MS_DEBUG_MSG(ULOGF("MMIO",_f)); MS_ASSERT(0);) }
#else
#define MMIO_ERROR(fmt, args...)        MS_DEBUG_MSG(while (0))
#define MMIO_WARN(fmt, args...)         MS_DEBUG_MSG(while (0))
#define MMIO_PRINT(fmt, args...)        MS_DEBUG_MSG(while (0))
#define MMIO_ASSERT(_bool, _f)          if (!(_bool)) { MS_DEBUG_MSG((_f)); }
#endif


//-------------------------------------------------------------------------------------------------
//  Local Structurs
//-------------------------------------------------------------------------------------------------
 static MS_S32 _s32MutexId      = -1;

//-------------------------------------------------------------------------------------------------
//  Global Variables
//-------------------------------------------------------------------------------------------------
MS_VIRT _virtPM_Bank            = 0x0;
MS_PHY  _u32PM_Bank_SIZE        = 0x0;
MS_VIRT _virtNonPM_Bank         = 0x0;
MS_PHY  _u32NonPM_Bank_SIZE     = 0x0;
MS_VIRT _virtEXTRIU_Bank        = 0x0;
MS_PHY  _u32EXTRIU_Bank_SIZE    = 0x0;
MS_VIRT _virtFRC_Bank           = 0x0;
MS_PHY  _u32FRC_Bank_SIZE       = 0x0;
MS_VIRT _virtXC_EXT_Bank        = 0x0;
MS_PHY  _u32XC_EXT_Bank_SIZE    = 0x0;
MS_VIRT _virtFlash_Bank0        = 0x0;
MS_PHY  _u32Flash_Bank0_SIZE    = 0x0;

MS_VIRT _virtVDEC_Bank          = 0x0;
MS_PHY  _u32VDEC_BankSize       = 0x0;
MS_VIRT _virtOTP_Bank           = 0x0;
MS_PHY  _u32OTP_BankSize        = 0x0;
MS_VIRT _virtOTP_Bank2          = 0x0;
MS_PHY  _u32OTP_Bank2Size       = 0x0;
MS_VIRT _virtSPRAM_Bank         = 0x0;
MS_PHY  _u32SPRAM_BankSize      = 0x0;
MS_VIRT _virtNSK_Bank           = 0x0;
MS_PHY  _u32NSK_BankSize        = 0x0;


//-------------------------------------------------------------------------------------------------
//  Local Variables
//-------------------------------------------------------------------------------------------------
static MSIF_Version _drv_mmio_version = {
    .DDI = { MMIO_DRV_VERSION },
};

#ifdef MSOS_TYPE_LINUX
static MS_S32   _s32MIOMapFd    = -1;
#endif

//-------------------------------------------------------------------------------------------------
//  Debug Functions
//-------------------------------------------------------------------------------------------------


//-------------------------------------------------------------------------------------------------
//  Local Functions
//-------------------------------------------------------------------------------------------------
static MS_BOOL _MDrv_MMIO_Init_Bank(MS_VIRT *virtBank, MS_PHY *phyBankSize, MS_U32 u32BankType,
                                    char *pBankName, MS_BOOL bAssert)
{
    MS_PHY          virtTmpBank = 0;
    MS_PHY          phyTmpBankSize = 0;
    MS_BOOL         bRet = FALSE;

    bRet = HAL_MMIO_GetBase(&virtTmpBank, &phyTmpBankSize, u32BankType);

#ifdef MSOS_TYPE_LINUX
    MIOMap_Info_t   stMIOMapInfo = {0};

    /* Assert or not */
    if ((FALSE == bRet) && (TRUE == bAssert))
        MS_ASSERT(0);

    /* Check bank size*/
    if ((phyTmpBankSize == 0) || (FALSE == bRet))
        return TRUE;

    /* Fill data struct */
    stMIOMapInfo.u64Addr = (MS_U64)virtTmpBank;
    stMIOMapInfo.u64Size = (MS_U64)phyTmpBankSize;

    /* Ioctl to mapping and Get mapping result. */
    MsOS_ObtainMutex(_s32MutexId, MSOS_WAIT_FOREVER);
    if ((bRet = (MS_BOOL)ioctl(_s32MIOMapFd, MMIO_IOC_SET_MAP , &stMIOMapInfo)) == 0)
    {
        (*virtBank) = (MS_VIRT)mmap(0,
                                    stMIOMapInfo.u64Size,
                                    PROT_READ | PROT_WRITE,
                                    MAP_SHARED,
                                    _s32MIOMapFd,
                                    0);
    }
    MsOS_ReleaseMutex(_s32MutexId);
    if ((bRet != 0) || ((MS_VIRT)MAP_FAILED == (*virtBank)))
    {
        (*virtBank) = 0x0;
        (*phyBankSize) = 0x0;
        MS_ASSERT(0);
        return FALSE;
    }
    (*phyBankSize) = phyTmpBankSize;

    /* Show mapping log */
    if (pBankName)
       MMIO_PRINT("%s mapping success. Base=[%zx], Size=[%zx]\n",
                    pBankName, (size_t)(*virtBank), (size_t)(*phyBankSize));
#else
    if (bRet == TRUE)
    {
        (*virtBank) = (MS_VIRT)virtTmpBank;
        (*phyBankSize) = phyTmpBankSize;
    }
#endif
    return TRUE;
}


//-------------------------------------------------------------------------------------------------
//  Global Functions
//-------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief \b Function  \b Name: MDrv_MSOS_GetLibVer
/// @brief \b Function  \b Description: Show the MSOS driver version
/// @param ppVersion    \b Out: Library version string
/// @return             \b Result
////////////////////////////////////////////////////////////////////////////////
MS_BOOL MDrv_MMIO_GetLibVer(const MSIF_Version **ppVersion)
{
    if (!ppVersion)
        return FALSE;

    *ppVersion = &_drv_mmio_version;
    return TRUE;
}

MS_BOOL MDrv_MMIO_Init(void)
{
#ifdef MSOS_TYPE_LINUX
    /* Check init or not */
    if (0 <= _s32MIOMapFd)
    {
        MMIO_WARN("Already inited.\n");
        return TRUE;
    }

    /* Check open /dev/miomap */
    if (0 > (_s32MIOMapFd = open("/dev/miomap", O_RDWR)))
    {
        MMIO_ERROR("Open /dev/miomap fail\n");
        MS_ASSERT(0);
        return FALSE;
    }

    /* Create mutex. */
    if (_s32MutexId == -1)
    {
        if ((_s32MutexId = MsOS_CreateMutex(E_MSOS_FIFO, __func__, MSOS_PROCESS_SHARED)) < 0)
            MMIO_ERROR("MsOS_CreateMutex() fail.\n");
    }

#endif
    /* Check mapping result */
    if (!_MDrv_MMIO_Init_Bank(&_virtPM_Bank,     &_u32PM_Bank_SIZE,     DRV_MMIO_PM_BANK,     "PM Bank",      TRUE) ||
        !_MDrv_MMIO_Init_Bank(&_virtNonPM_Bank,  &_u32NonPM_Bank_SIZE,  DRV_MMIO_NONPM_BANK,  "NonPM Bank",   TRUE) ||
        !_MDrv_MMIO_Init_Bank(&_virtFlash_Bank0, &_u32Flash_Bank0_SIZE, DRV_MMIO_FLASH_BANK0, "Flash Bank0",  TRUE))
        return FALSE;

    if (!_MDrv_MMIO_Init_Bank(&_virtEXTRIU_Bank, &_u32EXTRIU_Bank_SIZE, DRV_MMIO_EXTRIU_BANK, "EXTRIU Bank",  FALSE) ||
        !_MDrv_MMIO_Init_Bank(&_virtFRC_Bank,    &_u32FRC_Bank_SIZE,    DRV_MMIO_FRC_BANK,    "FRC Bank",     FALSE) ||
        !_MDrv_MMIO_Init_Bank(&_virtXC_EXT_Bank, &_u32XC_EXT_Bank_SIZE, DRV_MMIO_XC_EXT_BANK, "XC EXT Bank",  FALSE) ||
        !_MDrv_MMIO_Init_Bank(&_virtVDEC_Bank,   &_u32VDEC_BankSize,    DRV_MMIO_VDEC_BANK,   "VDEC Bank",    FALSE) ||
        !_MDrv_MMIO_Init_Bank(&_virtOTP_Bank,    &_u32OTP_BankSize,     DRV_MMIO_OTP_BANK,    "OTP Bank",     FALSE) ||
        !_MDrv_MMIO_Init_Bank(&_virtOTP_Bank2,   &_u32OTP_Bank2Size,    DRV_MMIO_OTP_BANK2,   "OTP Bank RAW", FALSE) ||
        !_MDrv_MMIO_Init_Bank(&_virtSPRAM_Bank,  &_u32SPRAM_BankSize,   DRV_MMIO_SPRAM_BANK,  "SPRAM Bank",   FALSE) ||
        !_MDrv_MMIO_Init_Bank(&_virtNSK_Bank,    &_u32NSK_BankSize,     DRV_MMIO_NSK_BANK,    "NSK Bank",     FALSE))
        return FALSE;

    return TRUE;
}

MS_BOOL MDrv_MMIO_Close(void)
{
#ifdef MSOS_TYPE_LINUX
    /* Check init or not */
    if (0 > _s32MIOMapFd)
    {
        MMIO_ERROR("Need to init.\n");
        return FALSE;
    }

    /* Delete mutex. */
    if (_s32MutexId >= 0)
    {
        MsOS_DeleteMutex(_s32MutexId);
        _s32MutexId = -1;
    }

    /* un mapping */
    munmap((void *)_virtPM_Bank,     _u32PM_Bank_SIZE);
    munmap((void *)_virtNonPM_Bank,  _u32NonPM_Bank_SIZE);
    munmap((void *)_virtEXTRIU_Bank, _u32EXTRIU_Bank_SIZE);
    munmap((void *)_virtFlash_Bank0, _u32Flash_Bank0_SIZE);

    munmap((void *)_virtFRC_Bank,    _u32FRC_Bank_SIZE);
    munmap((void *)_virtXC_EXT_Bank, _u32XC_EXT_Bank_SIZE);
    munmap((void *)_virtVDEC_Bank,   _u32VDEC_BankSize);
    munmap((void *)_virtOTP_Bank,    _u32OTP_BankSize);
    munmap((void *)_virtOTP_Bank2,   _u32OTP_Bank2Size);
    munmap((void *)_virtSPRAM_Bank,  _u32SPRAM_BankSize);
    munmap((void *)_virtNSK_Bank,    _u32NSK_BankSize);

    close(_s32MIOMapFd);
    _s32MIOMapFd = -1;
#endif
    return TRUE;
}

MS_BOOL MDrv_MMIO_GetBASE(MS_VIRT *virtBaseaddr, MS_PHY *phyBasesize, MS_U32 u32Module)
{
    MS_U16  u16Type = 0;

#ifdef MSOS_TYPE_LINUX
    /* Check init or not */
    if (0 > _s32MIOMapFd)
    {
        MMIO_ERROR("Need to init.\n");
        return FALSE;
    }
#else
    /* Make sure can be read data */
    MDrv_MMIO_Init();
#endif

    u16Type = HAL_MMIO_GetType(u32Module);

    if ((u16Type == DRV_MMIO_PM_BANK) && (_u32PM_Bank_SIZE))
    {
        *virtBaseaddr = _virtPM_Bank;
        *phyBasesize = _u32PM_Bank_SIZE;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_NONPM_BANK) && (_u32NonPM_Bank_SIZE))
    {
        *virtBaseaddr = _virtNonPM_Bank;
        *phyBasesize = _u32NonPM_Bank_SIZE;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_EXTRIU_BANK) && (_u32EXTRIU_Bank_SIZE))
    {
        *virtBaseaddr = _virtEXTRIU_Bank;
        *phyBasesize = _u32EXTRIU_Bank_SIZE;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_FRC_BANK) && (_u32FRC_Bank_SIZE))
    {
        *virtBaseaddr = _virtFRC_Bank;
        *phyBasesize = _u32FRC_Bank_SIZE;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_XC_EXT_BANK) && (_u32XC_EXT_Bank_SIZE))
    {
        *virtBaseaddr = _virtXC_EXT_Bank;
        *phyBasesize = _u32XC_EXT_Bank_SIZE;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_FLASH_BANK0) && (_u32Flash_Bank0_SIZE))
    {
        *virtBaseaddr = _virtFlash_Bank0;
        *phyBasesize = _u32Flash_Bank0_SIZE;
        return TRUE;
    }

    if ((u16Type == DRV_MMIO_VDEC_BANK) && (_u32VDEC_BankSize))
    {
        *virtBaseaddr = _virtVDEC_Bank;
        *phyBasesize = _u32VDEC_BankSize;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_OTP_BANK) && (_u32OTP_BankSize))
    {
        *virtBaseaddr = _virtOTP_Bank;
        *phyBasesize = _u32OTP_BankSize;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_OTP_BANK2) && (_u32OTP_Bank2Size))
    {
        *virtBaseaddr = _virtOTP_Bank2;
        *phyBasesize = _u32OTP_Bank2Size;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_SPRAM_BANK) && (_u32SPRAM_BankSize))
    {
        *virtBaseaddr = _virtSPRAM_Bank;
        *phyBasesize = _u32SPRAM_BankSize;
        return TRUE;
    }
    if ((u16Type == DRV_MMIO_NSK_BANK) && (_u32NSK_BankSize))
    {
        *virtBaseaddr = _virtNSK_Bank;
        *phyBasesize = _u32NSK_BankSize;
        return TRUE;
    }
    // Particular HW base address
    if (HAL_MMIO_GetIPBase(virtBaseaddr, u16Type))
    {
        *phyBasesize = 0;
        return TRUE;
    }

    return FALSE;
}
