/*----------------------------------------------------------------------------*
 * No Warranty                                                                *
 * Except as may be otherwise agreed to in writing, no warranties of any      *
 * kind, whether express or implied, are given by MTK with respect to any MTK *
 * Deliverables or any use thereof, and MTK Deliverables are provided on an   *
 * "AS IS" basis.  MTK hereby expressly disclaims all such warranties,        *
 * including any implied warranties of merchantability, non-infringement and  *
 * fitness for a particular purpose and any warranties arising out of course  *
 * of performance, course of dealing or usage of trade.  Parties further      *
 * acknowledge that Company may, either presently and/or in the future,       *
 * instruct MTK to assist it in the development and the implementation, in    *
 * accordance with Company's designs, of certain softwares relating to        *
 * Company's product(s) (the "Services").  Except as may be otherwise agreed  *
 * to in writing, no warranties of any kind, whether express or implied, are  *
 * given by MTK with respect to the Services provided, and the Services are   *
 * provided on an "AS IS" basis.  Company further acknowledges that the       *
 * Services may contain errors, that testing is important and Company is      *
 * solely responsible for fully testing the Services and/or derivatives       *
 * thereof before they are used, sublicensed or distributed.  Should there be *
 * any third party action brought against MTK, arising out of or relating to  *
 * the Services, Company agree to fully indemnify and hold MTK harmless.      *
 * If the parties mutually agree to enter into or continue a business         *
 * relationship or other arrangement, the terms and conditions set forth      *
 * hereunder shall remain effective and, unless explicitly stated otherwise,  *
 * shall prevail in the event of a conflict in the terms in any agreements    *
 * entered into between the parties.                                          *
 *---------------------------------------------------------------------------*/
/******************************************************************************
* [File]			msdc_test.c
* [Version]			v1.0
* [Revision Date]	2013-02-28
* [Author]			Shunli Wang, shunli.wang@mediatek.inc, 82896, 2013-02-28
* [Description]
*	extended code about MSDC
* [Copyright]
*	Copyright (C) 2007 MediaTek Incorporation. All Rights Reserved.
******************************************************************************/
#include "msdc_drv.h"
#include "drvcust_if.h"
#include "msdc_ext.h"
// AES Encrypt
#include "dmx_drm_if.h"
#include "x_hal_5381.h"
#include "x_os.h"
#include "x_lint.h"
#include "msdc_host_hw.h"


#ifdef CC_MTD_SUPPORT_64_PARTITION
	#define MSDCPART_PARTNUM                (64)
#else
	#define MSDCPART_PARTNUM                (32)
#endif

/*Warning! the buffer align has risk, if need to use it, shuold check in details. curretently in loader, not need to do this*/
#define MSDC_SUPPORT_BUF_ALIGN              (0)

#if defined(CC_MTD_ENCRYPT_SUPPORT)
#define AES_ADDR_ALIGN   0x20
#define AES_LEN_ALIGN    0x10
#define AES_BUFF_LEN     0x10000

#if MSDC_SUPPORT_BUF_ALIGN
unsigned char _u1MsdcBuf_AES[AES_BUFF_LEN + AES_ADDR_ALIGN], *_pu1MsdcBuf_Aes_Align;
#endif

int MSDCEXT_EncryptInit(unsigned short u2KeyLen)
{
    #if MSDC_SUPPORT_BUF_ALIGN
    unsigned int tmp = 0;
    #endif
  
    #if MSDC_AES_SUPPORT
    /*MSDC build-in AES open ,not need GCPU enc/dec*/
    Msdc_AES_InitConfig();
    return MSDC_SUCCESS;
    #endif

	#ifdef CC_UBOOT
    unsigned char u1Key[16] = {0};

    if(DMX_NAND_AES_INIT(u1Key, u2KeyLen))
    {
        MSDC_LOG(MSG_LVL_ERR, "AES init success!\n");
        return MSDC_SUCCESS;
    }
    else
    {
        MSDC_LOG(MSG_LVL_ERR, "AES init failed!\n");
        return MSDC_FAILED;
    }
	#else
	//Loader not need do init, it's done in other place
    #endif


#if MSDC_SUPPORT_BUF_ALIGN
    memset(_u1MsdcBuf_AES, 0x00, AES_BUFF_LEN + AES_ADDR_ALIGN);

    tmp = (unsigned int)_u1MsdcBuf_AES & (AES_ADDR_ALIGN - 1);
    if(tmp != 0x0)
        _pu1MsdcBuf_Aes_Align = (unsigned char *)(((unsigned int)_u1MsdcBuf_AES & (~(AES_ADDR_ALIGN - 1))) + AES_ADDR_ALIGN);
    else
    	  _pu1MsdcBuf_Aes_Align = (unsigned char *)_u1MsdcBuf_AES;
#endif

    return MSDC_SUCCESS;
}

int MSDCEXT_Block_Encrypted(unsigned int u4BlkIdx, unsigned int *pu4Data)
{
	  unsigned int u4PartId, u4Encryped, i;
    UINT64 u8Offset, u8PartSize;

    for (u4PartId = 0; u4PartId < MSDCPART_PARTNUM; u4PartId++)
    {
        u8PartSize = DRVCUST_InitGet64((QUERY_TYPE_T)(eNANDFlashPartSize0 + u4PartId));
        u8Offset   = DRVCUST_InitGet64((QUERY_TYPE_T)(eNANDFlashPartOffset0 + u4PartId));
        u4Encryped = DRVCUST_InitGet((QUERY_TYPE_T)(eNANDFlashPartEncypt0 + u4PartId));

        if((u4Encryped != 0) &&
        	 ((unsigned int)(u8Offset>>9) <= u4BlkIdx) &&
        	 ((unsigned int)((u8Offset + u8PartSize)>>9) > u4BlkIdx))
        {
            for(i = 0; i < 0x80; i++)
            {
                if(pu4Data[i] != 0xFFFFFFFF)
                {
                    return 1;
                }
            }
        }
    }

    return 0;
}

int MsdcPartitionEncrypted(unsigned int u4BlkIdx)
{
    unsigned int u4PartId, u4Encryped;
    UINT64 u8Offset, u8PartSize;


    for (u4PartId = 0; u4PartId < MSDCPART_PARTNUM; u4PartId++)
    {
        u8PartSize = DRVCUST_InitGet64((QUERY_TYPE_T)(eNANDFlashPartSize0 + u4PartId));
        u8Offset   = DRVCUST_InitGet64((QUERY_TYPE_T)(eNANDFlashPartOffset0 + u4PartId));
        u4Encryped = DRVCUST_InitGet((QUERY_TYPE_T)(eNANDFlashPartEncypt0 + u4PartId));

        if((u4Encryped != 0) &&
        	 ((unsigned int)(u8Offset>>9) <= u4BlkIdx) &&
        	 ((unsigned int)((u8Offset + u8PartSize)>>9) > u4BlkIdx))
        {
        	  MSDC_LOG(MSG_LVL_INFO, "This partition is encrypted(blkidx:0x%08X)!\n", u4BlkIdx);
            return 1;
        }
    }

    MSDC_LOG(MSG_LVL_INFO, "This partition is not encrypted(blkidx:0x%08X)!\n", u4BlkIdx);
    return 0;
}

/*
the PHYSICAL is not need in loader, it's not affect the result, confirmd with erik.
*/
int MsdcAesEncryption(unsigned int buff, unsigned int len)
{
    //unsigned int len_used = 0, len_total = 0;

    if((len & (AES_LEN_ALIGN - 1)) != 0x0)
	  {
	      MSDC_LOG(MSG_LVL_ERR, " the buffer to be encrypted is not align to %d bytes! \n", AES_LEN_ALIGN);
	      return MSDC_FAILED;
	  }

	/*buffer not need align in loader&uboot, we just need care the length should be align with 16 bytes*/


#if MSDC_SUPPORT_BUF_ALIGN

	  if (buff & (AES_ADDR_ALIGN - 1) != 0x0)
	  {
			  len_total = (int)len;
			  do
			  {
			  	  len_used = (len_total > AES_BUFF_LEN)?AES_BUFF_LEN:len_total;
			      memcpy((void *)_pu1MsdcBuf_Aes_Align, (void *)buff, len_used);
				  #ifdef CC_UBOOT
			      if(DMX_NAND_AES_Encryption((unsigned int)_pu1MsdcBuf_Aes_Align, (unsigned int)_pu1MsdcBuf_Aes_Align, len_used))
				  #else
				  if(DMX_NAND_AES_Encryption(PHYSICAL((unsigned int)_pu1MsdcBuf_Aes_Align), PHYSICAL((unsigned int)_pu1MsdcBuf_Aes_Align), len_used))
				  #endif
  		        {
  		            MSDC_LOG(MSG_LVL_INFO, "Encryption to buffer(addr:0x%08X size:0x%08X) success!\n", (unsigned int)_pu1MsdcBuf_Aes_Align, len_used);
  		        }
		        else
		        {
		            MSDC_LOG(MSG_LVL_ERR, "Encryption to buffer(addr:0x%08X size:0x%08X) failed!\n", (unsigned int)_pu1MsdcBuf_Aes_Align, len_used);
		            return MSDC_FAILED;
		        }
		        memcpy((void *)buff, (void *)_pu1MsdcBuf_Aes_Align, len_used);

		        len_total -= len_used;
		        buff += len_used;

			  }while(len_total > 0);
	  }
	  else
	#endif
	  {
	  	  #ifdef CC_UBOOT
		  if(DMX_NAND_AES_Encryption(buff, buff, len))
		  #else
	      if(DMX_NAND_AES_Encryption(PHYSICAL(buff), PHYSICAL(buff), len))
		  #endif
		    {
		        MSDC_LOG(MSG_LVL_INFO, "Encryption to buffer(addr:0x%08X size:0x%08X) success!\n", buff, len);
		    }
		    else
		    {
		        MSDC_LOG(MSG_LVL_ERR, "Encryption to buffer(addr:0x%08X size:0x%08X) failed!\n", buff, len);
		        return MSDC_FAILED;
		    }
	  }

	  return MSDC_SUCCESS;
}

int MsdcAesDecryption(unsigned int buff, unsigned int len)
{
    //unsigned int len_used = 0, len_total = 0;
    if((len & (AES_LEN_ALIGN - 1)) != 0x0)
	  {
	      MSDC_LOG(MSG_LVL_ERR, " the buffer to be encrypted is not align to %d bytes!\n", AES_LEN_ALIGN);
	      return MSDC_FAILED;
	  }

	/*buffer not need align in loader&uboot, we just need care the length should be align with 16 bytes*/
#if MSDC_SUPPORT_BUF_ALIGN
	  if (buff & (AES_ADDR_ALIGN - 1) != 0x0)
	  {
			  len_total = len;
			  do
			  {
			  	  len_used = (len_total > AES_BUFF_LEN)?AES_BUFF_LEN:len_total;
			      memcpy((void *)_pu1MsdcBuf_Aes_Align, (void *)buff, len_used);
				  #ifdef CC_UBOOT
				  if(DMX_NAND_AES_Decryption((unsigned int)_pu1MsdcBuf_Aes_Align, (unsigned int)_pu1MsdcBuf_Aes_Align, len_used))
				  #else
			      if(DMX_NAND_AES_Decryption(PHYSICAL((unsigned int)_pu1MsdcBuf_Aes_Align), PHYSICAL((unsigned int)_pu1MsdcBuf_Aes_Align), len_used))
				  #endif
		        {
		            MSDC_LOG(MSG_LVL_INFO, "Decryption to buffer(addr:0x%08X size:0x%08X) success!\n", (unsigned int)_pu1MsdcBuf_Aes_Align, len_used);
		            //return MSDC_SUCCESS;
		        }
		        else
		        {
		            MSDC_LOG(MSG_LVL_ERR, "Decryption to buffer(addr:0x%08X size:0x%08X) failed!\n", (unsigned int)_pu1MsdcBuf_Aes_Align, len_used);
		            return MSDC_FAILED;
		        }
		        memcpy((void *)buff, (void *)_pu1MsdcBuf_Aes_Align, len_used);

		        len_total -= len_used;
		        buff += len_used;

			  }while(len_total > 0);
    }
    else
#endif
	  {
	  	  #ifdef CC_UBOOT
		  if(DMX_NAND_AES_Decryption(buff, buff, len))
		  #else
	      if(DMX_NAND_AES_Decryption(PHYSICAL(buff), PHYSICAL(buff), len))
		  #endif
		    {
		        MSDC_LOG(MSG_LVL_INFO, "Decryption to buffer(addr:0x%08X size:0x%08X) success!\n", buff, len);
		    }
		    else
		    {
		        MSDC_LOG(MSG_LVL_ERR, "Decryption to buffer(addr:0x%08X size:0x%08X) failed!\n", buff, len);
		        return MSDC_FAILED;
		    }
	  }

	  return MSDC_SUCCESS;
}

int MSDCEXT_AES_Encryption_S(unsigned int u4BufStart, unsigned int u4BufSize)
{
    BOOL fgRet;
    unsigned int u4TmpBufStart;

    u4TmpBufStart = (unsigned int)x_mem_alloc(u4BufSize);
    if(NULL == (void *)u4TmpBufStart)
    {
        MSDC_LOG(MSG_LVL_ERR, "alloc memory(size:0x%08X) failed in Encryption routine!\n", u4TmpBufStart);
        return MSDC_FAILED;
    }

    fgRet = DMX_NAND_AES_Encryption(PHYSICAL(u4BufStart), PHYSICAL(u4TmpBufStart), u4BufSize);

    x_memcpy((void *)u4BufStart, (void *)u4TmpBufStart, u4BufSize);

    x_mem_free((void *)u4TmpBufStart);

    return fgRet?MSDC_SUCCESS:MSDC_FAILED;
}

int MSDCEXT_AES_Decryption_S(unsigned int u4BufStart, unsigned int u4BufSize)
{
    BOOL fgRet;
    unsigned int u4TmpBufStart;

    u4TmpBufStart = (unsigned int)x_mem_alloc(u4BufSize);
    if(NULL == (void *)u4TmpBufStart)
    {
        MSDC_LOG(MSG_LVL_ERR, "alloc memory(size:0x%08X) failed in Decryption routine!\n", u4TmpBufStart);
        return MSDC_FAILED;
    }

    fgRet = DMX_NAND_AES_Decryption(PHYSICAL(u4BufStart), PHYSICAL(u4TmpBufStart), u4BufSize);

    x_memcpy((void *)u4BufStart, (void *)u4TmpBufStart, u4BufSize);

    x_mem_free((void *)u4TmpBufStart);

    return fgRet?MSDC_SUCCESS:MSDC_FAILED;

}

int MSDCEXT_AES_Encryption(unsigned int u4InBufStart, unsigned int u4OutBufStart, unsigned int u4BufSize)
{
    BOOL fgRet;

    fgRet = DMX_NAND_AES_Encryption(u4InBufStart, u4OutBufStart, u4BufSize);

    return fgRet?MSDC_SUCCESS:MSDC_FAILED;
}

int MSDCEXT_AES_Decryption(unsigned int u4InBufStart, unsigned int u4OutBufStart, unsigned int u4BufSize)
{
    BOOL fgRet;

    fgRet = DMX_NAND_AES_Decryption(PHYSICAL(u4InBufStart), PHYSICAL(u4OutBufStart), u4BufSize);

    return fgRet?MSDC_SUCCESS:MSDC_FAILED;
}

#endif // defined(CC_MTD_ENCRYPT_SUPPORT)









