/**
 * @file  hv_drv_TypecPolicyEngineVdm.c
 * @brief  PD VDM Policy Engine Source file
 *         This file contains the function definition for VDM Policy Engine State Machine.
 * @details This file provides the following functions: \n
 *          (1) \n
 *          (2) \n
 *          (3) \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-25
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date         <th>Change Description
 * <tr><td>Hiview SoC Software Team       <td>2022-08-25   <td>init
 * </table>
*/


#include <hv_drv_TypecStdInc.h> 

#if (HV_TRUE == INCLUDE_PD_VDM)

void PE_RunVDMStateMachine (UINT8 u8PortNum, UINT8 *pu8DataBuf, UINT32 u32Header)
{   
    /* VDM Data Object Array */
    UINT32 u32aVDMDataObj[PRL_MAX_DATA_OBJ_COUNT] = {SET_TO_ZERO}; 
    
    /* VDM Data Object Count */
    UINT8 u8VDOCnt = SET_TO_ZERO; 
    
    /* Transmit Message Header */
    UINT32 u32TransmitHeader = SET_TO_ZERO;

    /* Transmit Data Object */
    UINT32 *u32pTransmitDataObj = SET_TO_ZERO; 
    
    /* Transmit Call back set to PE_StateChange_TransmitCB */
    PRLTxCallback pfnTransmitCB = PE_StateChange_TransmitCB;

    /* Transmit Call back variables */
    UINT32 u32TransmitTmrIDTxSt = SET_TO_ZERO;

    /* Transmit Flag */
    UINT8 u8IsTransmit = HV_FALSE;
    
    ePolicyState eTxDoneSt;
    ePolicySubState eTxDoneSS;
    
    if (PD_ROLE_SOURCE == DPM_GET_CURRENT_POWER_ROLE(u8PortNum))
    {
        eTxDoneSt = ePE_SRC_READY;
        eTxDoneSS = ePE_SRC_READY_END_AMS_SS;
    }
    else
    {
        eTxDoneSt = ePE_SNK_READY;
        eTxDoneSS = ePE_SNK_READY_END_AMS_SS;
    }          
    
    switch (gasPolicyEngine[u8PortNum].ePEState)
    {
        /************************** VDM Initiator State **********************/
        case ePE_VDM_INITIATE_VDM:
        {
            switch (gasPolicyEngine[u8PortNum].ePESubState)
            {
                case ePE_VDM_INITIATE_VDM_ENTRY_SS: 
                {
                    /* PE will enter this sub-state when sending a VDM request 
                       initiated by application via Client Request */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_INITIATE_VDM_ENTRY_SS\r\n");

                    /* Get the VDM Header and VDOs configured by the application */                                                   
                    u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader;
                    
#if (HV_TRUE == INCLUDE_PD_ALT_MODE)
                    /* This is used in cases where the response for SVID specific VDM 
                       commands like DPStatus, DPConfigure, etc., comes from the application 
                       */
                    u8VDOCnt = gasCfgStatusData.sAltModePerPortData[u8PortNum].u8VDOCnt;
                    if(u8VDOCnt)
                    {
                        (void) HV_PSF_HOOK_MEMCPY((u32aVDMDataObj + BYTE_LEN_1), gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aVDO, \
                                                                        (u8VDOCnt * BYTE_LEN_4));
                    }
#endif 
                    u32pTransmitDataObj = u32aVDMDataObj;
                    
                    /* Object Count is incremented by 1 to include VDM Header */
                    u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, (UINT8)PE_DATA_VENDOR_DEFINED,  \
                                                                    (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);                   

                    if (eSVDM_ATTENTION == (eSVDMCmd) DPM_GET_VDM_CMD(u32aVDMDataObj[INDEX_0]))
                    {
                        /* Attention command does not have a response. So, move to
                           ePE_VDM_INITIATE_VDM_END_AMS_SS sub-state since the AMS is 
                           considered complete on Good CRC reception */
                        DEBUG_PRINT_PORT_STR (u8PortNum,"eSVDM_ATTENTION\r\n");
                        u32TransmitTmrIDTxSt = PRL_BUILD_PKD_TXST_U32( ePE_VDM_INITIATE_VDM, \
                                                        ePE_VDM_INITIATE_VDM_END_AMS_SS, \
                                                        eTxDoneSt, eTxDoneSS);                                        
                    }
                    else 
                    {
                        /* Move to ePE_VDM_INITIATE_VDM_MSG_DONE_SS sub-state 
                        on Good CRC reception and to Ready state on Tx Failure since 
                        VDMs shall not be retried after a transmission failure */ 
                        u32TransmitTmrIDTxSt = PRL_BUILD_PKD_TXST_U32( ePE_VDM_INITIATE_VDM, \
                                                        ePE_VDM_INITIATE_VDM_MSG_DONE_SS, \
                                                        eTxDoneSt, eTxDoneSS);                
                    }
                    
                    u8IsTransmit = HV_TRUE;
                    
                    /* Move PE to an idle state to wait for Good CRC reception */
                    gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_INITIATE_VDM_IDLE_SS;                                       
                    
                    break; 
                }               
                case ePE_VDM_INITIATE_VDM_MSG_DONE_SS:
                {
                    /* PE will enter this sub-state when GoodCRC is received
                       for VDM Identity request sent to SOP */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_INITIATE_VDM_MSG_DONE_SS\r\n");
                
                    /* Start the VDMResponse timer, if timed out set the PE sub-state to 
                       ePE_VDM_INITIATE_VDM_NO_RESPONSE_SS */
                    gasPolicyEngine[u8PortNum].u8PETimerID = PDTimer_Start (
                                                            (PE_VDMRESPONSE_TIMEOUT_MS),
                                                            PE_SubStateChange_TimerCB,u8PortNum,  
                                                            (UINT8)ePE_VDM_INITIATE_VDM_NO_RESPONSE_SS);
                    
                    /* Move the PE to an idle state to wait for response */
                    gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_INITIATE_VDM_IDLE_SS;                    
                    break;
                }
                case ePE_VDM_INITIATE_VDM_RESPONSE_RCVD_SS:
                {
                    /* PE will enter this sub-state when response message is 
                       received for the VDM request sent to SOP */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_INITIATE_VDM_RESPONSE_RCVD_SS\r\n");

                    /* Store the received VDM Header and VDM response in status registers */                    
                    gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader = \
                        MAKE_UINT32_FROM_BYTES(pu8DataBuf[0], pu8DataBuf[1], pu8DataBuf[2], pu8DataBuf[3]);
                    
                    /* Current PSF does not support initiation of VDM commands
                       other than Discover Identity. */
                    if (eSVDM_DISCOVER_IDENTITY == (eSVDMCmd) DPM_GET_VDM_CMD(pu8DataBuf[DPM_VDM_HEADER_POS]))
                    {                                            
                        gasCfgStatusData.sVDMPerPortData[u8PortNum].u8PartnerPDIdentityCnt = \
                                            (PRL_GET_OBJECT_COUNT(u32Header) - BYTE_LEN_1);
                            
                        HV_PSF_HOOK_MEMCPY32_FROM_BYTE(gasCfgStatusData.sVDMPerPortData[u8PortNum].u32aPartnerPDIdentity, (pu8DataBuf + BYTE_LEN_4), \
                                            gasCfgStatusData.sVDMPerPortData[u8PortNum].u8PartnerPDIdentityCnt);                                                   
                    }                     
                         
                    /* Handle the response based on the VDM command type */
                    if (DPM_VDM_BUSY == DPM_GET_VDM_CMD_TYPE(pu8DataBuf[DPM_VDM_HEADER_POS]))
                    {   
                        /* BUSY Response Handling */
                        gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_INITIATE_VDM_BUSY_RCVD_SS;                       
                    }
                    else /* ACK or NAK response */
                    {
                        /* Reset the VDM Busy Counter on receiving a non-BUSY response */
                        gasPolicyEngine[u8PortNum].u8VDMBusyCounter = RESET_TO_ZERO;                          
                        
                        /* Move to Ready state based on the current power role */
                        gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt;
                        gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;                         
                        
                        /* Post eHV_PSF_VDM_RESPONSE_RCVD notification */
                        (void)DPM_NotifyClient (u8PortNum, eHV_PSF_VDM_RESPONSE_RCVD);                                                
                    }
                    break; 
                }
                case ePE_VDM_INITIATE_VDM_BUSY_RCVD_SS:
                {
                    /* PE will enter this sub-state when a BUSY response is 
                       received for the VDM request sent to SOP */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_INITIATE_VDM_BUSY_RCVD_SS\r\n");

                    /* Clear the internal event since it will be re-initiated when 
                       the VDM Busy Timer expires */                        
                    gasDPM[u8PortNum].u16DPMInternalEvents &= ~(DPM_INT_EVT_INITIATE_VDM);                        

                    /* This logic will re-initiate the VDM request for a maximum of 
                       6 times. Responder is allowed to send BUSY response for a 
                       maximum of 5 times. To know whether the responder port sends 
                       ACK/NAK after 5 times, initiator port has to retry the 6th time */
                    if (gasPolicyEngine[u8PortNum].u8VDMBusyCounter < PE_N_BUSY_COUNT)
                    {              
                        /* Increment the VDM Busy Counter */
                        gasPolicyEngine[u8PortNum].u8VDMBusyCounter++;
                        
                        /* Start the VDM Busy Retry Timer */            
                        gasDPM[u8PortNum].u8VDMBusyTmrID = PDTimer_Start (
                                                                (PE_VDM_BUSY_TIMEOUT_MS),
                                                                DPM_VDMBusy_TimerCB,u8PortNum,  
                                                                (UINT8)SET_TO_ZERO);  
                        
                        /* Move to Ready state based on the current power role */
                        gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt;
                        gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;                                                 
                    }
                    else
                    {
                        /* Reset the VDM Busy Counter when it exceeds PE_N_BUSY_COUNT */
                        gasPolicyEngine[u8PortNum].u8VDMBusyCounter = RESET_TO_ZERO;
                         
                        /* Partner has sent BUSY for the 6th time. But, as per PD Spec, a responder 
                           is allowed to send BUSY for a maximum of 5 times. So, consider this 
                           as no response and do not retry further */
                        gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_INITIATE_VDM_NO_RESPONSE_SS; 
                    }
                    
                    break; 
                }
                case ePE_VDM_INITIATE_VDM_NO_RESPONSE_SS:
                {
                    /* PE will enter this sub-state when it determines that the
                       partner has not sent any response for the VDM request */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_INITIATE_VDM_NO_RESPONSE_SS\r\n");
                    
                    /* No response from port partner for the VDM request sent. 
                       Post notification and move to Ready state 
                       based on the current power role */
                    gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt;
                    gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS; 
                    
                    /* Post eHV_PSF_VDM_RESPONSE_NOT_RCVD notification */
                    (void)DPM_NotifyClient (u8PortNum, eHV_PSF_VDM_RESPONSE_NOT_RCVD); 
                                        
                    break; 
                }
                case ePE_VDM_INITIATE_VDM_END_AMS_SS:
                {
                    /* PE will enter this sub-state when Good CRC is received for 
                       a VDM request that does not have a response. */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_INITIATE_VDM_END_AMS_SS\r\n");
                    
                    /* Clear the VDM internal event since the AMS is complete */
                    gasDPM[u8PortNum].u16DPMInternalEvents &= ~(DPM_INT_EVT_INITIATE_VDM);
                    
                    /* Move to Ready state based on the current power role*/
                    gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt;
                    gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS; 
                    
                    /* Post eHV_PSF_VDM_AMS_COMPLETE notification */
                    (void)DPM_NotifyClient (u8PortNum, eHV_PSF_VDM_AMS_COMPLETE); 
                    
                    break; 
                }
                case ePE_VDM_INITIATE_VDM_IDLE_SS:
                {
                    /* Hook to notify PE state machine entry into idle sub-state */
                    HV_PSF_HOOK_NOTIFY_IDLE(u8PortNum, eIDLE_PE_NOTIFY); 
                    
                    break; 
                }
                default:
                {
                    break; 
                }
            }            
            break; 
        }         
        /************************** VDM Evaluation State *********************/
        case ePE_VDM_EVALUATE_VDM:
        {
            /* PE will enter this state when PSF has received a VDM request
               from port partner which needs evaluation by the DPM */
            DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_EVALUATE_VDM\r\n");
                    
            /* Store the received VDM Header in u32PartnerVDMHeader */                    
            HV_PSF_HOOK_MEMCPY32_FROM_BYTE(&gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader, \
                                                                pu8DataBuf, BYTE_LEN_1);      
                    
#if (HV_TRUE == INCLUDE_PD_ALT_MODE)
            /* For Enter Mode and other SVID specific commands, copy the
               received VDOs in the status registers for the application to 
               handle the evaluation and response */
            gasCfgStatusData.sAltModePerPortData[u8PortNum].u8PartnerVDOCnt = \
                                (PRL_GET_OBJECT_COUNT(u32Header) - BYTE_LEN_1);
                            
            HV_PSF_HOOK_MEMCPY32_FROM_BYTE(gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aPartnerVDO, (pu8DataBuf + BYTE_LEN_4), \
                                gasCfgStatusData.sAltModePerPortData[u8PortNum].u8PartnerVDOCnt);                                                   
#endif 
                    
            /* Get Evaluation of VDM request from Device Policy Manager */
            if (DPM_IGNORE_VDM_RESPONSE == DPM_EvaluateVDMRequest (u8PortNum, &gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader))
            {
                /* It is expected that the user application will evaluate the 
                   VDM request and send response by raising VDM Client request.
                   So, move to Ready state */
                gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt; 
                gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;                        
            }
            else /* DPM_RESPOND_VDM_ACK or DPM_RESPOND_VDM_NAK */
            {
                gasPolicyEngine[u8PortNum].ePEState = ePE_VDM_RESPOND_VDM;
                gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_RESPOND_VDM_ENTRY_SS;

                /* move the process in state here */
                /* PE will enter this sub-state to send the ACK or NAK
                    response for the VDM request received from port partner
                    Application initiated VDM response will be sent through
                    ePE_VDM_RESPOND_VDM_SVID_SPECIFIC_SS sub-state */
                DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_RESPOND_VDM_ENTRY_SS-0-\r\n");

                /* Copy the received VDM Header */
                u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader;

                /* PD3.1 CTS PDMER_PROT_VDM_SNK_CAP_PD2_PD3 TEST.PD.VDM.SNK.6
                    VDM Version Obt:3 and Exp:0 in REVISION_2_0 mode
                    VDM Version Obt:3 and Exp:1 in REVISION_3_0 mode */
                // DEBUG_PRINT_PORT_STR (DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum),"DPM_GET_CURRENT_PD_SPEC_REV\r\n");
                u32aVDMDataObj[INDEX_0] &= ~DPM_VDM_VERSION_MASK;

                if (PD_SPEC_REVISION_3_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
                {
                    u32aVDMDataObj[INDEX_0] |= (1 << DPM_VDM_VERSION_POS);
                }
                else if (PD_SPEC_REVISION_2_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
                {
                    u32aVDMDataObj[INDEX_0] |= (0 << DPM_VDM_VERSION_POS);
                }
                else
                {
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PD Spec Rev not correct.\r\n");
                }

                /* Clear the command type bits in VDM header */
                u32aVDMDataObj[INDEX_0] &= ~DPM_VDM_CMD_TYPE_MASK;

                if (gasDPM[u8PortNum].u32DPMStatus & DPM_VDM_RESPONSE_MASK)
                {
                    u32aVDMDataObj[INDEX_0] |= (DPM_VDM_ACK << DPM_VDM_CMD_TYPE_POS);

                    /* Get VDOs from DPM */
                    DPM_ReturnVDOs (u8PortNum, u32aVDMDataObj[INDEX_0], &u8VDOCnt, (u32aVDMDataObj + BYTE_LEN_1));
                }
                else /* DPM_RESPOND_VDM_NAK */
                {
                    u32aVDMDataObj[INDEX_0] |= (DPM_VDM_NAK << DPM_VDM_CMD_TYPE_POS);
                }

                /* u8VDOCnt returned by DPM during ACK will not include VDM
                    Header. So, Object count is incremented by 1 to include
                    VDM Header. In case of NAK, u8VDOCnt will be 0 */
                u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, PE_DATA_VENDOR_DEFINED, \
                                                                    (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);
                u32pTransmitDataObj = u32aVDMDataObj;

                /* Move to ePE_VDM_RESPOND_VDM_END_AMS_SS sub-state on Good CRC reception
                    and to Ready state on Tx failure */
                u32TransmitTmrIDTxSt = PRL_BUILD_PKD_TXST_U32( ePE_VDM_RESPOND_VDM, \
                                                ePE_VDM_RESPOND_VDM_END_AMS_SS, eTxDoneSt, eTxDoneSS);

                u8IsTransmit = HV_TRUE;

                /* Move the PE to an idle state to wait for message transmit
                    completion */
                gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_RESPOND_VDM_IDLE_SS;
            }
            break; 
        }
        /************************** VDM Responder State **********************/
        case ePE_VDM_RESPOND_VDM:
        {
            switch (gasPolicyEngine[u8PortNum].ePESubState)
            {
                case ePE_VDM_RESPOND_VDM_ENTRY_SS:
                {                 
                    /* PE will enter this sub-state to send the ACK or NAK 
                       response for the VDM request received from port partner
                       Application initiated VDM response will be sent through
                       ePE_VDM_RESPOND_VDM_SVID_SPECIFIC_SS sub-state */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_RESPOND_VDM_ENTRY_SS\r\n");
                    
                    /* Copy the received VDM Header */
                    u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader; 

                    /* PD3.1 CTS PDMER_PROT_VDM_SNK_CAP_PD2_PD3 TEST.PD.VDM.SNK.6
                       VDM Version Obt:3 and Exp:0 in REVISION_2_0 mode
                       VDM Version Obt:3 and Exp:1 in REVISION_3_0 mode */
                    // DEBUG_PRINT_PORT_STR (DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum),"DPM_GET_CURRENT_PD_SPEC_REV\r\n");
                    u32aVDMDataObj[INDEX_0] &= ~DPM_VDM_VERSION_MASK;

                    if (PD_SPEC_REVISION_3_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
                    {
                        u32aVDMDataObj[INDEX_0] |= (1 << DPM_VDM_VERSION_POS);
                    }
                    else if (PD_SPEC_REVISION_2_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
                    {
                        u32aVDMDataObj[INDEX_0] |= (0 << DPM_VDM_VERSION_POS);
                    }
                    else
                    {
                        DEBUG_PRINT_PORT_STR (u8PortNum,"PD Spec Rev not correct.\r\n");
                    }

                    /* Clear the command type bits in VDM header */
                    u32aVDMDataObj[INDEX_0] &= ~DPM_VDM_CMD_TYPE_MASK; 
                        
                    if (gasDPM[u8PortNum].u32DPMStatus & DPM_VDM_RESPONSE_MASK)
                    {
                        u32aVDMDataObj[INDEX_0] |= (DPM_VDM_ACK << DPM_VDM_CMD_TYPE_POS);
                            
                        /* Get VDOs from DPM */
                        DPM_ReturnVDOs (u8PortNum, u32aVDMDataObj[INDEX_0], &u8VDOCnt, (u32aVDMDataObj + BYTE_LEN_1));                                           
                    }
                    else /* DPM_RESPOND_VDM_NAK */
                    {
                        u32aVDMDataObj[INDEX_0] |= (DPM_VDM_NAK << DPM_VDM_CMD_TYPE_POS); 
                    }
                        
                    /* u8VDOCnt returned by DPM during ACK will not include VDM 
                       Header. So, Object count is incremented by 1 to include 
                       VDM Header. In case of NAK, u8VDOCnt will be 0 */
                    u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, PE_DATA_VENDOR_DEFINED, \
                                                                        (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);                                        
                    u32pTransmitDataObj = u32aVDMDataObj;
                    
                    /* Move to ePE_VDM_RESPOND_VDM_END_AMS_SS sub-state on Good CRC reception 
                       and to Ready state on Tx failure */
                    u32TransmitTmrIDTxSt = PRL_BUILD_PKD_TXST_U32( ePE_VDM_RESPOND_VDM, \
                                                    ePE_VDM_RESPOND_VDM_END_AMS_SS, eTxDoneSt, eTxDoneSS);              
                        
                    u8IsTransmit = HV_TRUE; 
                        
                    /* Move the PE to an idle state to wait for message transmit 
                       completion */
                    gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_RESPOND_VDM_IDLE_SS;                                                                                       
                                                                    
                    break;
                }
#if (HV_TRUE == INCLUDE_PD_ALT_MODE)                  
                case ePE_VDM_RESPOND_VDM_SVID_SPECIFIC_SS:
                {
                    /* PE will enter this sub-state when application raises a 
                       DPM_CLIENT_REQ_RESPOND_VDM client request */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_RESPOND_VDM_SVID_SPECIFIC_SS\r\n");

                    /* Get the VDM Header and VDOs configured by the application */
                    u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader;
  
                    /* This is used in cases where the response for SVID specific VDM 
                       commands like DPStatus, DPConfigure, etc., comes from the application 
                       */
                    u8VDOCnt = gasCfgStatusData.sAltModePerPortData[u8PortNum].u8VDOCnt;
                            
                    (void) HV_PSF_HOOK_MEMCPY((u32aVDMDataObj + BYTE_LEN_1), gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aVDO, \
                                                                        (u8VDOCnt * BYTE_LEN_4));                                                                        
                                        
                    u32pTransmitDataObj = u32aVDMDataObj;
                    
                    /* Object Count is incremented by 1 to include VDM Header */
                    u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, (UINT8)PE_DATA_VENDOR_DEFINED,  \
                                                                    (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);                    
                    
                    /* Move to ePE_VDM_RESPOND_VDM_END_AMS_SS sub-state on Good CRC reception 
                       and to Ready state on Tx failure */
                    u32TransmitTmrIDTxSt = PRL_BUILD_PKD_TXST_U32( ePE_VDM_RESPOND_VDM, \
                                                    ePE_VDM_RESPOND_VDM_END_AMS_SS, eTxDoneSt, eTxDoneSS);                                                                                                                    
              
                    u8IsTransmit = HV_TRUE;
                    
                    gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_RESPOND_VDM_IDLE_SS;                                                                                       
                    
                    break; 
                }
#endif
                case ePE_VDM_RESPOND_VDM_END_AMS_SS:
                {
                    /* PE will enter this sub-state when Good CRC is received for 
                       a VDM response sent. */
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_RESPOND_VDM_END_AMS_SS\r\n");
                    gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMAttentionFlag = gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMConfigFlag;
                    /* Move to Ready state based on the current power role*/
                    gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt;
                    gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS; 

                    if(gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMConfigFlag)
                    {
                        gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMConfigFlag = 0;
                        (void)DPM_NotifyClient (u8PortNum, eHV_PSF_VDM_AMS_DONE); 
                    }
                    
                    /* Post eHV_PSF_VDM_AMS_COMPLETE notification */
                    (void)DPM_NotifyClient (u8PortNum, eHV_PSF_VDM_AMS_COMPLETE); 
                    
                    break; 
                }     
                case ePE_VDM_RESPOND_VDM_IDLE_SS:
                {
                    /* Hook to notify PE state machine entry into idle sub-state */
                    HV_PSF_HOOK_NOTIFY_IDLE(u8PortNum, eIDLE_PE_NOTIFY);
                    
                    break; 
                }
                default:
                {
                    break; 
                }
            }
            break; 
        }
#if (HV_TRUE == INCLUDE_PD_UVDM)
        /************************** UVDM Evaluation State *********************/
        case ePE_UVDM_EVALUATE_VDM:
        {
            /* PE will enter this state when PSF has received a VDM request
               from port partner which needs evaluation by the DPM */
            // DEBUG_PRINT_PORT_STR (u8PortNum,"PE_UVDM_EVALUATE_VDM\r\n");

            /* Store the received VDM Header in u32PartnerUVDMHeader */
            HV_PSF_HOOK_MEMCPY32_FROM_BYTE(&gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32PartnerVDMHeader, \
                                                                pu8DataBuf, BYTE_LEN_1);

            gasCfgStatusData.sUVDMPerPortData[u8PortNum].u8PartnerVDOCnt = \
                                (PRL_GET_OBJECT_COUNT(u32Header) - BYTE_LEN_1);

            HV_PSF_HOOK_MEMCPY32_FROM_BYTE(gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32aPartnerVDO, (pu8DataBuf + BYTE_LEN_4), \
                                gasCfgStatusData.sUVDMPerPortData[u8PortNum].u8PartnerVDOCnt);

            // DEBUG_PRINT_PORT_STR (gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32PartnerVDMHeader,"u32PartnerVDMHeader\r\n");
            // DEBUG_PRINT_PORT_STR (gasCfgStatusData.sUVDMPerPortData[u8PortNum].u8PartnerVDOCnt,"u8PartnerVDOCnt\r\n");
            // int index = 0;
            // for (index = 0; index < gasCfgStatusData.sUVDMPerPortData[u8PortNum].u8PartnerVDOCnt; index++)
            // {
            //     DEBUG_PRINT_PORT_STR (gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32aPartnerVDO[index],"u32aPartnerVDO\r\n");
            // }

            /* DPM_RESPOND_VDM_ACK or DPM_RESPOND_VDM_NAK */
            {
                gasPolicyEngine[u8PortNum].ePEState = ePE_UVDM_RESPOND_VDM;
                gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_RESPOND_VDM_ENTRY_SS;
            }
            break;
        }
        /************************** VDM Responder State **********************/
        case ePE_UVDM_RESPOND_VDM:
        {
            switch (gasPolicyEngine[u8PortNum].ePESubState)
            {
                case ePE_VDM_RESPOND_VDM_ENTRY_SS:
                {
                    // DEBUG_PRINT_PORT_STR (u8PortNum,"PE_UVDM_RESPOND_VDM_ENTRY_SS\r\n");

                    /* Copy the received VDM Header */
                    u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32PartnerVDMHeader;

                    /* Clear the command type bits in VDM header */
                    u32aVDMDataObj[INDEX_0] &= 0xFFFF8000;

                    // if (gasDPM[u8PortNum].u32DPMStatus & DPM_VDM_RESPONSE_MASK)
                    {
                        u32aVDMDataObj[INDEX_0] |= 0x40;
                        /* Get VDOs from DPM */
                        DPM_ReturnUVDMVDOs (u8PortNum, u32aVDMDataObj[INDEX_0], &u8VDOCnt, (u32aVDMDataObj + BYTE_LEN_1));
                    }

                    /* u8VDOCnt returned by DPM during ACK will not include VDM
                       Header. So, Object count is incremented by 1 to include
                       VDM Header. In case of NAK, u8VDOCnt will be 0 */
                    u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, PE_DATA_VENDOR_DEFINED, \
                                                                        (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);
                    u32pTransmitDataObj = u32aVDMDataObj;

                    /* Move to ePE_VDM_RESPOND_VDM_END_AMS_SS sub-state on Good CRC reception
                       and to Ready state on Tx failure */
                    u32TransmitTmrIDTxSt = PRL_BUILD_PKD_TXST_U32( ePE_UVDM_RESPOND_VDM, \
                                                    ePE_VDM_RESPOND_VDM_END_AMS_SS, eTxDoneSt, eTxDoneSS);

                    u8IsTransmit = HV_TRUE;

                    /* Move the PE to an idle state to wait for message transmit
                       completion */
                    gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_RESPOND_VDM_IDLE_SS;

                    break;
                }
                case ePE_VDM_RESPOND_VDM_END_AMS_SS:
                {
                    /* PE will enter this sub-state when Good CRC is received for
                       a VDM response sent. */
                    // DEBUG_PRINT_PORT_STR (u8PortNum,"PE_UVDM_RESPOND_VDM_END_AMS_SS\r\n");
                    /* Move to Ready state based on the current power role*/
                    gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt;
                    gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;

                    /* Post eHV_PSF_VDM_AMS_COMPLETE notification */
                    (void)DPM_NotifyClient (u8PortNum, eHV_PSF_VDM_AMS_COMPLETE);

                    break;
                }
                case ePE_VDM_RESPOND_VDM_IDLE_SS:
                {
                    /* Hook to notify PE state machine entry into idle sub-state */
                    HV_PSF_HOOK_NOTIFY_IDLE(u8PortNum, eIDLE_PE_NOTIFY);

                    break;
                }
                default:
                {
                    break;
                }
            }
            break;
        }
#endif
        default:
        {
            break; 
        }
    }
    
    /* Transmit the message if u8IsTransmit is set */
    if (u8IsTransmit)
    {
        (void) PRL_TransmitMsg (u8PortNum, (UINT8) PRL_SOP_TYPE, u32TransmitHeader, \
                    (UINT8 *)u32pTransmitDataObj, pfnTransmitCB, u32TransmitTmrIDTxSt); 
    }
    
}

void Hv_Drv_Typec_HandleVDM(UINT8 u8PortNum, UINT32 u32Header, UINT8 *pu8DataBuf)
{   
    /* VDM Data Object Array */
    UINT32 u32aVDMDataObj[PRL_MAX_DATA_OBJ_COUNT] = {SET_TO_ZERO}; 
    
    /* VDM Data Object Count */
    UINT8 u8VDOCnt = SET_TO_ZERO; 
    
    /* Transmit Message Header */
    UINT32 u32TransmitHeader = SET_TO_ZERO;

    /* Transmit Data Object */
    UINT32 *u32pTransmitDataObj = SET_TO_ZERO; 

    /* Transmit Call back variables */
    UINT32 u32TransmitTmrIDTxSt = SET_TO_ZERO;

    
    ePolicyState eTxDoneSt;
    ePolicySubState eTxDoneSS;
    
    if (PD_ROLE_SOURCE == DPM_GET_CURRENT_POWER_ROLE(u8PortNum))
    {
        eTxDoneSt = ePE_SRC_READY;
        eTxDoneSS = ePE_SRC_READY_END_AMS_SS;
    }
    else
    {
        eTxDoneSt = ePE_SNK_READY;
        eTxDoneSS = ePE_SNK_READY_END_AMS_SS;
    }          
    
    if (DPM_VDM_STRUCTURED_VDM == DPM_GET_VDM_TYPE (*(pu8DataBuf + BYTE_LEN_1)))
    {
        /* PE will enter this state when PSF has received a VDM request
            from port partner which needs evaluation by the DPM */
        // DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_EVALUATE_VDM\r\n");
                
        /* Store the received VDM Header in u32PartnerVDMHeader */                    
        HV_PSF_HOOK_MEMCPY32_FROM_BYTE(&gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader, \
                                                            pu8DataBuf, BYTE_LEN_1);      
                
#if (HV_TRUE == INCLUDE_PD_ALT_MODE)
        /* For Enter Mode and other SVID specific commands, copy the
            received VDOs in the status registers for the application to 
            handle the evaluation and response */
        gasCfgStatusData.sAltModePerPortData[u8PortNum].u8PartnerVDOCnt = \
                            (PRL_GET_OBJECT_COUNT(u32Header) - BYTE_LEN_1);
                        
        HV_PSF_HOOK_MEMCPY32_FROM_BYTE(gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aPartnerVDO, (pu8DataBuf + BYTE_LEN_4), \
                            gasCfgStatusData.sAltModePerPortData[u8PortNum].u8PartnerVDOCnt);                                                   
#endif 

        /* Get Evaluation of VDM request from Device Policy Manager */
        if (DPM_IGNORE_VDM_RESPONSE == DPM_EvaluateVDMRequest (u8PortNum, &gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader))
        {
            /* It is expected that the user application will evaluate the 
                VDM request and send response by raising VDM Client request.
                So, move to Ready state */
            gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt; 
            gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;                        
        }
        else /* DPM_RESPOND_VDM_ACK or DPM_RESPOND_VDM_NAK */
        {
            gasPolicyEngine[u8PortNum].ePEState = ePE_VDM_RESPOND_VDM;
            gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_RESPOND_VDM_ENTRY_SS;

            /* move the process in state here */
            /* PE will enter this sub-state to send the ACK or NAK
                response for the VDM request received from port partner
                Application initiated VDM response will be sent through
                ePE_VDM_RESPOND_VDM_SVID_SPECIFIC_SS sub-state */
            DEBUG_PRINT_PORT_STR (u8PortNum,"PE_VDM_RESPOND_VDM_ENTRY_SS\r\n");

            /* Copy the received VDM Header */
            u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader;

            /* PD3.1 CTS PDMER_PROT_VDM_SNK_CAP_PD2_PD3 TEST.PD.VDM.SNK.6
                VDM Version Obt:3 and Exp:0 in REVISION_2_0 mode
                VDM Version Obt:3 and Exp:1 in REVISION_3_0 mode */
            // DEBUG_PRINT_PORT_STR (DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum),"DPM_GET_CURRENT_PD_SPEC_REV\r\n");
            u32aVDMDataObj[INDEX_0] &= ~DPM_VDM_VERSION_MASK;

            if (PD_SPEC_REVISION_3_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
            {
                u32aVDMDataObj[INDEX_0] |= (1 << DPM_VDM_VERSION_POS);
            }
            else if (PD_SPEC_REVISION_2_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
            {
                u32aVDMDataObj[INDEX_0] |= (0 << DPM_VDM_VERSION_POS);
            }
            else
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"PD Spec Rev not correct.\r\n");
            }

            /* Clear the command type bits in VDM header */
            u32aVDMDataObj[INDEX_0] &= ~DPM_VDM_CMD_TYPE_MASK;

            if (gasDPM[u8PortNum].u32DPMStatus & DPM_VDM_RESPONSE_MASK)
            {
                u32aVDMDataObj[INDEX_0] |= (DPM_VDM_ACK << DPM_VDM_CMD_TYPE_POS);

                /* Get VDOs from DPM */
                DPM_ReturnVDOs (u8PortNum, u32aVDMDataObj[INDEX_0], &u8VDOCnt, (u32aVDMDataObj + BYTE_LEN_1));
            }
            else /* DPM_RESPOND_VDM_NAK */
            {
                u32aVDMDataObj[INDEX_0] |= (DPM_VDM_NAK << DPM_VDM_CMD_TYPE_POS);
            }

            /* u8VDOCnt returned by DPM during ACK will not include VDM
                Header. So, Object count is incremented by 1 to include
                VDM Header. In case of NAK, u8VDOCnt will be 0 */
            u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, PE_DATA_VENDOR_DEFINED, \
                                                                (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);
            u32pTransmitDataObj = u32aVDMDataObj;

            gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt; 
            gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;

            (void) PRL_TransmitUrgentMsg (u8PortNum, (UINT8) PRL_SOP_TYPE, u32TransmitHeader, \
                        (UINT8 *)u32pTransmitDataObj, NULL, u32TransmitTmrIDTxSt);

            if(gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMConfigFlag)
            {
                gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMConfigFlag = HV_FALSE;
                DEBUG_PRINT_PORT_STR (u8PortNum,"eHV_PSF_VDM_AMS_DONE and notify DP\r\n");
                (void)DPM_NotifyClient (u8PortNum, eHV_PSF_VDM_AMS_DONE);
            }
        }
    }
    else if (DPM_VDM_UNSTRUCTURED_VDM == DPM_GET_VDM_TYPE (*(pu8DataBuf + BYTE_LEN_1)))
    {
#if (HV_TRUE == INCLUDE_PD_UVDM)
        /* Store the received VDM Header in u32PartnerUVDMHeader */
        HV_PSF_HOOK_MEMCPY32_FROM_BYTE(&gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32PartnerVDMHeader, \
                                                            pu8DataBuf, BYTE_LEN_1);

        gasCfgStatusData.sUVDMPerPortData[u8PortNum].u8PartnerVDOCnt = \
                            (PRL_GET_OBJECT_COUNT(u32Header) - BYTE_LEN_1);

        if (gasCfgStatusData.sUVDMPerPortData[u8PortNum].u8PartnerVDOCnt == 0)
        {
            gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt; 
            gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;
            return;
        }

        HV_PSF_HOOK_MEMCPY32_FROM_BYTE(gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32aPartnerVDO, (pu8DataBuf + BYTE_LEN_4), \
                            gasCfgStatusData.sUVDMPerPortData[u8PortNum].u8PartnerVDOCnt);

        /* Copy the received VDM Header */
        u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32PartnerVDMHeader;

        /* Clear the command type bits in VDM header */
        u32aVDMDataObj[INDEX_0] &= 0xFFFF8000;

        // if (gasDPM[u8PortNum].u32DPMStatus & DPM_VDM_RESPONSE_MASK)
        {
            u32aVDMDataObj[INDEX_0] |= 0x40;
            /* Get VDOs from DPM */
            DPM_ReturnUVDMVDOs (u8PortNum, u32aVDMDataObj[INDEX_0], &u8VDOCnt, (u32aVDMDataObj + BYTE_LEN_1));
        }

        /**
         * Special handling for Nintendo Switch devices to prevent display issues.
         * Without this handling, the Switch device may not display images on the 
         * motherboard after waking from sleep mode.
         *
         * The following three sections of code are specifically designed to address 
         * this issue.
         */
        if (gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32aPartnerVDO[0] == 0x00010101)
        {
            // hpd irq
            (void)PDTimer_Start (PE_SEND_HPD_ACTION_TIMEOUT_MS, PE_UVDM_SpecialCmdSent_TimerCB, u8PortNum,(UINT8)SET_HPD_IRQ);
        }

        if (gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32aPartnerVDO[0] == 0x001C0101)
        {
            // hpd low
            (void)PDTimer_Start (PE_SEND_HPD_ACTION_TIMEOUT_MS, PE_UVDM_SpecialCmdSent_TimerCB, u8PortNum,(UINT8)SET_HPD_LOW);
        }

        if (gasCfgStatusData.sUVDMPerPortData[u8PortNum].u32aPartnerVDO[0] == 0x00200101)
        {
            // hpd low -500ms-> hpd high
            (void)PDTimer_Start (PE_SEND_HPD_ACTION_TIMEOUT_MS, PE_UVDM_SpecialCmdSent_TimerCB, u8PortNum,(UINT8)SET_HPD_LOW);
            (void)PDTimer_Start (2*PE_SEND_HPD_ACTION_TIMEOUT_MS, PE_UVDM_SpecialCmdSent_TimerCB, u8PortNum,(UINT8)SET_HPD_HIGH);
        }

        /* u8VDOCnt returned by DPM during ACK will not include VDM
            Header. So, Object count is incremented by 1 to include
            VDM Header. In case of NAK, u8VDOCnt will be 0 */
        u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, PE_DATA_VENDOR_DEFINED, \
                                                            (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);
        u32pTransmitDataObj = u32aVDMDataObj;

        gasPolicyEngine[u8PortNum].ePEState = eTxDoneSt; 
        gasPolicyEngine[u8PortNum].ePESubState = eTxDoneSS;

        (void) PRL_TransmitUrgentMsg (u8PortNum, (UINT8) PRL_SOP_TYPE, u32TransmitHeader, \
                    (UINT8 *)u32pTransmitDataObj, NULL, u32TransmitTmrIDTxSt);
#else
        /* Unstructured VDMs are unsupported by PSF */
        UINT8 temp_header = *(pu8DataBuf + BYTE_LEN_1);
        DEBUG_PRINT_PORT_STR (temp_header,"[Debug] PE_HandleUnsupportedVDM is called.\r\n");
        PE_HandleUnsupportedVDM (u8PortNum);
#endif
    }
}
#endif /* INCLUDE_PD_VDM */ 



/* u8TypecHpd
  0: Hpd Low
  1: Hpd High
  2: Irq
  */
void PE_HandleHpdAction (UINT8 u8PortNum, UINT8 u8TypecHpd)
{
    /* VDM Data Object Array */
    UINT32 u32aVDMDataObj[PRL_MAX_DATA_OBJ_COUNT] = {SET_TO_ZERO}; 
    
    /* VDM Data Object Count */
    UINT8 u8VDOCnt = SET_TO_ZERO; 
    
    /* Transmit Message Header */
    UINT32 u32TransmitHeader = SET_TO_ZERO;

    /* Transmit Data Object */
    UINT32 *u32pTransmitDataObj = SET_TO_ZERO; 
    
    /* Transmit Call back set to PE_StateChange_TransmitCB */
    PRLTxCallback pfnTransmitCB = PE_StateChange_TransmitCB;

    /* Transmit Call back variables */
    UINT32 u32TransmitTmrIDTxSt = SET_TO_ZERO;

    ePolicyState eTxDoneSt;
    ePolicySubState eTxDoneSS;
    
    if (PD_ROLE_SOURCE == DPM_GET_CURRENT_POWER_ROLE(u8PortNum))
    {
        eTxDoneSt = ePE_SRC_READY;
        eTxDoneSS = ePE_SRC_READY_END_AMS_SS;
    }
    else
    {
        eTxDoneSt = ePE_SNK_READY;
        eTxDoneSS = ePE_SNK_READY_END_AMS_SS;
    }

    if (!DPM_IS_MODAL_OPERATION_ACTIVE(u8PortNum))
    {
        return;
    }

    if (gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader == 0)
    {
        gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader = (1<<DPM_VDM_VERSION_POS);
    }

    if (u8TypecHpd == SET_HPD_LOW)
    {
         /* 0xFF01A106 : [USB PD Attention] [REQ] [Index 1] [Version 2.0] [Structured VDM] [SVID 0xFF01]*/
        gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader = 0xFF018106;
        gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader |= (gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader & DPM_VDM_VERSION_MASK);

        gasCfgStatusData.sAltModePerPortData[u8PortNum].u8VDOCnt = 1;
        /* 0x0000000A: [DP Sink device] [Adapter normally] [DP enabled] [NO Multi-function Preferred]*/
        /*               [DP Config] [NO Exit DisplayPort Alt Mode] [HPD_LOW] [NO IRQ_HPD]*/
        gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aVDO[0] = 0x0000000A;

        DEBUG_PRINT_PORT_STR (u8PortNum,"Set HPD Low\r\n"); 
    }
    else if (u8TypecHpd == SET_HPD_HIGH)
    {
        /* 0xFF01A106 : [USB PD Attention] [REQ] [Index 1] [Version 2.0] [Structured VDM] [SVID 0xFF01]*/
        gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader = 0xFF018106;

        gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader |= (gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader & DPM_VDM_VERSION_MASK);

        gasCfgStatusData.sAltModePerPortData[u8PortNum].u8VDOCnt = 1;
        /* 0x0000008A: [DP Sink device] [Adapter normally] [DP enabled] [NO Multi-function Preferred]*/
        /*               [DP Config] [NO Exit DisplayPort Alt Mode] [HPD_High] [NO IRQ_HPD]*/
        gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aVDO[0] = 0x0000008A;        

        DEBUG_PRINT_PORT_STR (u8PortNum,"Set HPD High\r\n");
    }
    else if (u8TypecHpd == SET_HPD_IRQ)
    {
         /* 0xFF01A106 : [USB PD Attention] [REQ] [Index 1] [Version 2.0] [Structured VDM] [SVID 0xFF01]*/
        gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader = 0xFF018106;
        gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader |= (gasCfgStatusData.sVDMPerPortData[u8PortNum].u32PartnerVDMHeader & DPM_VDM_VERSION_MASK);

        gasCfgStatusData.sAltModePerPortData[u8PortNum].u8VDOCnt = 1;
        /* 0x0000018A: [DP Sink device] [Adapter normally] [DP enabled] [NO Multi-function Preferred]*/
        /*               [DP Config] [NO Exit DisplayPort Alt Mode] [HPD_High] [IRQ_HPD]*/        
        gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aVDO[0] = 0x0000018A;        
        
        gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMIrqHpdFlag = HV_FALSE;

        DEBUG_PRINT_PORT_STR (u8PortNum,"Set Irq HPD\r\n"); 
    }

    /* Get the VDM Header and VDOs configured by the application */                                                   
    u32aVDMDataObj[INDEX_0] = gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader;
    
#if (HV_TRUE == INCLUDE_PD_ALT_MODE)
    /* This is used in cases where the response for SVID specific VDM 
        commands like DPStatus, DPConfigure, etc., comes from the application 
        */
    u8VDOCnt = gasCfgStatusData.sAltModePerPortData[u8PortNum].u8VDOCnt;
    if(u8VDOCnt)
    {
        (void) HV_PSF_HOOK_MEMCPY((u32aVDMDataObj + BYTE_LEN_1), gasCfgStatusData.sAltModePerPortData[u8PortNum].u32aVDO, \
                                                        (u8VDOCnt * BYTE_LEN_4));
    }
#endif 
    u32pTransmitDataObj = u32aVDMDataObj;
    
    /* Object Count is incremented by 1 to include VDM Header */
    u32TransmitHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, (UINT8)PE_DATA_VENDOR_DEFINED,  \
                                                    (u8VDOCnt + BYTE_LEN_1), PE_NON_EXTENDED_MSG);                   
    /* if DP ALT Mode error, need to check as below */
    /* if (eSVDM_ATTENTION == (eSVDMCmd) DPM_GET_VDM_CMD(u32aVDMDataObj[INDEX_0])) */
    if (eSVDM_ATTENTION == (eSVDMCmd) DPM_GET_VDM_CMD(gasCfgStatusData.sVDMPerPortData[u8PortNum].u32VDMHeader))
    {
        /* Attention command does not have a response. So, move to
            ePE_VDM_INITIATE_VDM_END_AMS_SS sub-state since the AMS is 
            considered complete on Good CRC reception */
        DEBUG_PRINT_PORT_STR (u8PortNum,"eSVDM_ATTENTION\r\n");
        u32TransmitTmrIDTxSt = PRL_BUILD_PKD_TXST_U32( ePE_VDM_INITIATE_VDM, \
                                        ePE_VDM_INITIATE_VDM_END_AMS_SS, \
                                        eTxDoneSt, eTxDoneSS);                                        
    }

    /* Move PE to an idle state to wait for Good CRC reception */
    gasPolicyEngine[u8PortNum].ePESubState = ePE_VDM_INITIATE_VDM_IDLE_SS;

    (void) PRL_TransmitMsg (u8PortNum, (UINT8) PRL_SOP_TYPE, u32TransmitHeader, \
                (UINT8 *)u32pTransmitDataObj, pfnTransmitCB, u32TransmitTmrIDTxSt); 
}
/* *****************************************************************************
 End of File
 */
