/**
 * @file hv_drv_HdcpRx.c
 * @brief HDCP RX 模块提供的驱动层
 * @details 该模块接口提供给Hiview-Madia-Ware及其他上层应用使用。
 * @author HiView SoC Software team
 * @version 0.0.1
 * @date 20230522
 * @copyright Copyright(c),2023-5, Hiview Software. All rights reserved.
 * @par History: 
 * <table>
 * <tr><th>作者                        <th>日期              <th>描述
 * <tr><td>HiView SoC Software team  <td>20220822        <td>Create and first Version.
 * </table>
**/

#include "hv_drv_HdcpRx.h"
#include "hv_cal_Hdcp.h"
#include "hv_hdcp_BigDigits.h"
#include "hv_hdcp2x_Common.h"
#include "hv_hdcp_engine_Aes256.h"

#define HV_HDCP_2X_RX_MMULT_R_SIZE 256  /* SIZE = 2048/8 */

#define HV_HDCP_1X_SIZE_DKS_WORD    (280/4)   /**< Device Key Set Size  */

#define PRI_P_SIZE                  16
#define PRI_Q_SIZE                  16
#define PRI_DP_SIZE                 16
#define PRI_DQ_SIZE                 16
#define PRI_QINV_SIZE               16
#define PRI_KEY_SIZE                64
#define PRI_KEY_DIV_SIZE            4

static volatile UINT32 g_uiHdcpRxIrqMask = 0;   /* 中断Flag记录 Reference: HdcpComIrqMask */

#define HV_HDCP_KEY_ID_LENTH 5

static UCHAR8 CountBit_1(UCHAR8 *pucData)
{
    UINT32 uiLoop = 0;
    UCHAR8 ucCount = 0;

    for(uiLoop = 0; uiLoop < HV_HDCP_KEY_ID_LENTH; uiLoop++)
    {
        pucData[uiLoop] = (pucData[uiLoop] & 0x55) + ((pucData[uiLoop] >> 1) & 0x55);
        pucData[uiLoop] = (pucData[uiLoop] & 0x33) + ((pucData[uiLoop] >> 2) & 0x33);
        pucData[uiLoop] = (pucData[uiLoop] & 0x0F) + ((pucData[uiLoop] >> 4) & 0x0f);
        ucCount += pucData[uiLoop];
    }

    return ucCount;
}

BOOL Hv_Drv_Hdcp_CheckKidValid(UCHAR8 *pucData)
{
    UCHAR8 aucData[HV_HDCP_KEY_ID_LENTH] = {0,};

    HV_MEMCPY(aucData, pucData, HV_HDCP_KEY_ID_LENTH);

    return (CountBit_1(aucData) == 20);
}

VOID Hv_Drv_Hdcp2x_RxGenRrxAndCaps(HdcpRx* pstHdcpRxIns, UCHAR8 ucCapRole)
{
    /*检查入参*/
    HV_ASSERT_VALID_PTR_VOID(pstHdcpRxIns);

    UINT32 uiRandomValue = rand();

    pstHdcpRxIns->stHdcp2xRx.stParams.RxCaps[0] = HdcpVesion_Hdcp2X;
    pstHdcpRxIns->stHdcp2xRx.stParams.RxCaps[1] = 0;
    pstHdcpRxIns->stHdcp2xRx.stParams.RxCaps[2] = ucCapRole;

    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[0] = uiRandomValue & 0xFF;
    uiRandomValue >>= 8;
    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[1] = uiRandomValue & 0xFF;
    uiRandomValue >>= 8;
    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[2] = uiRandomValue & 0xFF;
    uiRandomValue >>= 8;
    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[3] = uiRandomValue & 0xFF;

    uiRandomValue = rand();

    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[4] = uiRandomValue & 0xFF;
    uiRandomValue >>= 8;
    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[5] = uiRandomValue & 0xFF;
    uiRandomValue >>= 8;
    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[6] = uiRandomValue & 0xFF;
    uiRandomValue >>= 8;
    pstHdcpRxIns->stHdcp2xRx.stParams.Rrx[7] = uiRandomValue & 0xFF;

    return;
}


Status Hv_Drv_Hdcp2x_RxResetParams(Hdcp2xRx *pstHdcp2xRxIns)
{
    HV_ASSERT_VALID_PTR(pstHdcp2xRxIns);

    /* Clear stored parameters */
    memset(pstHdcp2xRxIns->stParams.Km,           0, sizeof(pstHdcp2xRxIns->stParams.Km));
    memset(pstHdcp2xRxIns->stParams.Ks,           0, sizeof(pstHdcp2xRxIns->stParams.Ks));
    memset(pstHdcp2xRxIns->stParams.Rn,           0, sizeof(pstHdcp2xRxIns->stParams.Rn));
    memset(pstHdcp2xRxIns->stParams.EKh,          0, sizeof(pstHdcp2xRxIns->stParams.EKh));
    memset(pstHdcp2xRxIns->stParams.Riv,          0, sizeof(pstHdcp2xRxIns->stParams.Riv));
    memset(pstHdcp2xRxIns->stParams.Rrx,          0, sizeof(pstHdcp2xRxIns->stParams.Rrx));
    memset(pstHdcp2xRxIns->stParams.Rtx,          0, sizeof(pstHdcp2xRxIns->stParams.Rtx));
    memset(pstHdcp2xRxIns->stParams.TxCaps,       0, sizeof(pstHdcp2xRxIns->stParams.TxCaps));
    memset(pstHdcp2xRxIns->stParams.HPrime,       0, sizeof(pstHdcp2xRxIns->stParams.HPrime));
    memset(pstHdcp2xRxIns->stParams.LPrime,       0, sizeof(pstHdcp2xRxIns->stParams.LPrime));
    memset(pstHdcp2xRxIns->stParams.VPrime,       0, sizeof(pstHdcp2xRxIns->stParams.VPrime));
    memset(pstHdcp2xRxIns->stParams.SeqNumM,      0, sizeof(pstHdcp2xRxIns->stParams.SeqNumM));
    memset(pstHdcp2xRxIns->stParams.StreamIdType, 0, sizeof(pstHdcp2xRxIns->stParams.StreamIdType));
    memset(pstHdcp2xRxIns->stParams.MPrime,       0, sizeof(pstHdcp2xRxIns->stParams.MPrime));

    return HV_SUCCESS;
}

VOID Hv_Drv_Hdcp_ComIrqEnable(void)
{
    return Hv_Cal_Hdcp_ComIrqEnable();
}

UINT32 Hv_Drv_Hdcp_GetIrqFlag(VOID)
{
    volatile UINT32 uiIsrFlag =  Hv_Cal_Hdcp_GetIrqFlag();

    uiIsrFlag |= g_uiHdcpRxIrqMask;

    g_uiHdcpRxIrqMask |= uiIsrFlag;

    g_uiHdcpRxIrqMask &= 0xFFFEFFFE;

    return uiIsrFlag;
}

#if 0
VOID Hv_Drv_Hdcp_SetIrqMask(UINT32 uiIrqMask)
{
    g_uiHdcpRxIrqMask = uiIrqMask;
    return;
}

UINT32 Hv_Drv_Hdcp_GetIrqMask(VOID)
{
    return g_uiHdcpRxIrqMask;
}
#endif

VOID Hv_Drv_Hdcp_ClrIrqMask(VOID)
{
    g_uiHdcpRxIrqMask &= (0x10001);
    return;
}

VOID Hv_Drv_Hdcp2x_RxSaveKsRivToReg(const UCHAR8* pucKs, const UCHAR8* pucRiv, UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_VALID_PTR_VOID(pucKs);
    HV_ASSERT_VALID_PTR_VOID(pucRiv);

    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp2x_RxSaveKsRivToReg(pucKs, pucRiv, ucHdcpPortIndex);
}

VOID Hv_Drv_Hdcp2x_StartRxAuth(UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp2x_StartRxAuth(ucHdcpPortIndex);
}

VOID Hv_Drv_Hdcp_MiscIrqClr(UINT32 uiIrqNum)
{
    Hv_Vos_WClrMiscInt(uiIrqNum - HV_CHIP_IRQ_BASE);
    return;
}

HV_ATTR_ISR_SECTION BOOL Hv_Drv_Hdcp_GetComIrqFlag(HdcpComIrqMask enComIrqType)
{
    BOOL ucIrqFlag = HV_FALSE;
    static UINT32 uiCnt = 0;

    Hv_Vos_Delayus(10);
    g_uiHdcpRxIrqMask |= Hv_Cal_Hdcp_GetIrqFlag();

    if((g_uiHdcpRxIrqMask & enComIrqType) || (uiCnt > 2000))
    {
        g_uiHdcpRxIrqMask &= (0x10001);
        ucIrqFlag = HV_TRUE;
        uiCnt = 0;
    }
    else
    {
        /* Do Noting */
    }
    uiCnt++;
    return ucIrqFlag;
}

Status Hv_Drv_Hdcp_LoadLc128(const UCHAR8 *pucLc128)
{
    HV_ASSERT_VALID_PTR(pucLc128);
    Hv_Cal_Hdcp_SaveLc128toReg(pucLc128);

    return HV_SUCCESS;
}

static VOID Hv_Drv_Hdcp2x_CalcMmulArrays(Hdcp2xRxMmult* pstmmult, const HDCP2X_RX_KPriv *PrivateKey)
{
    HV_ASSERT_VALID_PTR_VOID(PrivateKey);
    HV_ASSERT_VALID_PTR_VOID(pstmmult);

    UINT32 auiR[HV_HDCP_2X_RX_MMULT_R_SIZE/2]     = {0};
    UINT32 auiA[PRI_KEY_SIZE/PRI_KEY_DIV_SIZE]    = {0};
    UINT32 auiB[PRI_KEY_SIZE/PRI_KEY_DIV_SIZE]    = {0};

    UINT32 NDigitsBase = 16;
    UINT32 NDigits = 0;

    Hv_Engine_ConvFromOctets(auiA, Hv_Hdcp2x_RxMpSizeof(auiA), PrivateKey->p, sizeof(PrivateKey->p));
    Hv_Engine_ConvFromOctets(auiB, Hv_Hdcp2x_RxMpSizeof(auiB), PrivateKey->q, sizeof(PrivateKey->q));

    /*2^2k mod p   k=512*/

    /* Step 0: R = 2^(NDigits*32) */
    auiR[0] = 1;
    NDigits = NDigitsBase << 7;
    Hv_Engine_ShiftLeft(auiR, auiR, NDigits, NDigits/NDigitsBase);
    /* Step 1: Xbar = 1*R*mod(N) */
    Hv_Engine_Modulo(pstmmult->AmodP, auiR, NDigits/NDigitsBase, auiA, NDigitsBase);

    /*2^2k mod q   k=512*/

    /* Step 0: R = 2^(NDigits*32) */
    auiR[0] = 1;
    NDigits = NDigitsBase << 7;
    Hv_Engine_ShiftLeft(auiR, auiR, NDigits, NDigits/NDigitsBase);
    /* Step 1: Xbar = 1*R*mod(N) */
    Hv_Engine_Modulo(pstmmult->AmodQ, auiR, NDigits/NDigitsBase, auiB, NDigitsBase);

    /*2^k mod p   k=512*/

    /* Step 0: R = 2^(NDigits*32) */
    auiR[0] = 1;
    NDigits = NDigitsBase << 6;
    Hv_Engine_ShiftLeft(auiR, auiR, NDigits, NDigits/NDigitsBase);
    /* Step 1: Xbar = 1*R*mod(N) */
    Hv_Engine_Modulo(pstmmult->CmodP, auiR, NDigits/NDigitsBase, auiA, NDigitsBase);

    /*2^k mod q   k=512*/

    /* Step 0: R = 2^(NDigits*32) */
    auiR[0] = 1;
    NDigits = NDigitsBase << 6;
    Hv_Engine_ShiftLeft(auiR, auiR, NDigits, NDigits/NDigitsBase);
    /* Step 1: Xbar = 1*R*mod(N) */
    Hv_Engine_Modulo(pstmmult->CmodQ, auiR, NDigits/NDigitsBase, auiB, NDigitsBase);

    return ;
  }


Status Hv_Drv_Hdcp_LoadPrivateKey(Hdcp2xRxMmult* pstmmult, const HDCP2X_RX_KPriv *PrivateKey)
{
    /* Verify arguments */
    HV_ASSERT_VALID_PTR(PrivateKey);
    HV_ASSERT_VALID_PTR(pstmmult);

    UINT32 priP[PRI_P_SIZE]       = {0};
    UINT32 priQ[PRI_Q_SIZE]       = {0};
    UINT32 priDP[PRI_DP_SIZE]     = {0};
    UINT32 priDQ[PRI_DQ_SIZE]     = {0};
    UINT32 priQINV[PRI_QINV_SIZE] = {0};

    //memset(priP, 0, sizeof(priP));
    //memset(priQ, 0, sizeof(priQ));
    //memset(priDP, 0, sizeof(priDP));
    //memset(priDQ, 0, sizeof(priDQ));
    //memset(priQINV, 0, sizeof(priQINV));

    /* 顺便计算了MMult */
    Hv_Drv_Hdcp2x_CalcMmulArrays(pstmmult, PrivateKey);

    Hv_Engine_ConvFromOctets(priP, PRI_P_SIZE, PrivateKey->p, PRI_KEY_SIZE);
    Hv_Engine_ConvFromOctets(priQ, PRI_Q_SIZE, PrivateKey->q, PRI_KEY_SIZE);
    Hv_Engine_ConvFromOctets(priDP, PRI_DP_SIZE, PrivateKey->dp, PRI_KEY_SIZE);
    Hv_Engine_ConvFromOctets(priDQ, PRI_DQ_SIZE, PrivateKey->dq, PRI_KEY_SIZE);
    Hv_Engine_ConvFromOctets(priQINV, PRI_QINV_SIZE, PrivateKey->qinv, PRI_KEY_SIZE);

    Hv_Cal_Hdcp_SavePriKeytoReg(priP, priQ, priDP, priDQ, priQINV);

    return HV_SUCCESS;
}

Status Hv_Drv_Hdcp_LoadDKSTable(UCHAR8 *pucDKS)
{
    UINT32 auiBkeyTable[HV_HDCP_1X_SIZE_DKS_WORD]={0};
    HV_ASSERT_VALID_PTR(pucDKS);

    Hv_Engine_ConvFromOctets(auiBkeyTable, HV_HDCP_1X_SIZE_DKS_WORD, pucDKS, HV_HDCP_1X_SIZE_DKS_BYTE);

    Hv_Cal_Hdcp_SaveDKStoReg(auiBkeyTable, HV_HDCP_1X_SIZE_DKS_WORD);

    return HV_SUCCESS;
}

VOID Hv_Drv_Hdcp_InitSel(UCHAR8 ucHdcpPortIndex, UCHAR8 ucValueSet)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp_InitSel(ucHdcpPortIndex, ucValueSet);
}

VOID Hv_Drv_Hdcp_SetLaneClk(UCHAR8 ucValueSet, UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    Hv_Cal_Hdcp_SetLaneClk(ucValueSet, ucHdcpPortIndex);
}

Status Hv_Drv_Hdcp_CheckExist(UCHAR8 ucPortIndex)
{
    return Hv_Cal_Hdcp_CheckExist(ucPortIndex);
}
VOID Hv_Drv_Hdcp_RealseStatus(UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp_RealseStatus(ucHdcpPortIndex);
}

VOID Hv_Drv_Hdcp_RxModuleInit(UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp_Init(ucHdcpPortIndex);
}

VOID Hv_Drv_Hdcp_Reset(UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp_Reset(ucHdcpPortIndex);
}

VOID Hv_Drv_Hdcp1X_ClrDpFifo(UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp1X_ClrDpFifo(ucHdcpPortIndex);
}

VOID Hv_Drv_Hdcp2X_ClrDpFifo(UCHAR8 ucHdcpPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    return Hv_Cal_Hdcp2X_ClrDpFifo(ucHdcpPortIndex);
}
