//*************************************************************************** //!file app_cbus.c //!brief Wraps board and device functions for the CBUS component // and the application // //***************************************************************************/ #include /* printk */ #include #include "drv_types.h" #include "cbus_app.h" #include "cbus_mid.h" #include "cbus_drv.h" #include #include #include "../hdmi_hw.h" #include "../hdmi_cfg.h" #include "../../../module_include/drv_hdmi_internal.h" //#include "../hdmi_hpd.h" #include "../hdmi_notice.h" #include "../sysreg.h" #include "../hdmi_time.h" #include "../hdmi_processing.h" #include "mhl_application.h" //#include //#include "pin_config.h" #include "../../../module_include/drv_gpio.h" //#include "drivers/drv_hdmi.h" //#include "pin_allocator.h" //------------------------------------------------------------------------------ // Module variables //------------------------------------------------------------------------------ static CBUS_APP_FSM_STATE_e eCbusAppState = CBUS_APP_FSM_UNATTACHED, eCbusAppNextState = CBUS_APP_FSM_UNATTACHED; static UINT32 HPDWaitConnectedCnt = 0; static UINT32 WaitDiscvCnt = 0; static UINT32 WaitPllCnt= 0; static UINT32 WaitHDCPCnt= 0; static MHLAppInstanceData_t MHLAppInstanceData= { 0, // statusFlags // CBUS App-specific FALSE, // discvDetect; FALSE, //srcDiscont; FALSE, //cbusCableSense FALSE, //Cbus connected }; MHLAppInstanceData_t *pMHLApp = &MHLAppInstanceData; void CbusAppInitialize(void) { eCbusAppNextState = CBUS_APP_FSM_UNATTACHED; } //------------------------------------------------------------------------------ // Function: CbusAppProcessRecvRcpMsg // Description: Process the passed RCP message. // Returns: The RCPK status code. //------------------------------------------------------------------------------ static UINT8 CbusAppProcessRecvRcpMsg(MHL_RCP_CMD_e rcpData) { MHL_RCPE_STATUS_e rcpkStatus = MHL_MSC_MSG_RCP_NO_ERROR; mhldbg("[%s] RCP Key Code: 0x%02X\n", __FUNCTION__, (INT32)rcpData); switch ( rcpData ) { case MHL_RCP_CMD_SELECT: printk("[MHL]SELECT received\n" ); break; case MHL_RCP_CMD_UP: printk("[MHL]UP received\n" ); break; case MHL_RCP_CMD_DOWN: printk("[MHL]DOWN received\n" ); break; case MHL_RCP_CMD_ROOT_MENU: printk("[MHL]ROOT_MENU received\n" ); break; case MHL_RCP_CMD_EXIT: printk("[MHL]EXIT received\n" ); break; case MHL_RCP_CMD_VOL_UP: printk("[MHL]VOL_UP received\n" ); break; case MHL_RCP_CMD_VOL_DOWN: printk("[MHL]VOL_DOWN received\n" ); break; default: printk("[MHL] un-support RCP key received 0x%x\n", rcpData); rcpkStatus = MHL_MSC_MSG_INEFFECTIVE_KEY_CODE; break; } if ( rcpkStatus == MHL_MSC_MSG_RCP_NO_ERROR ) { noticekmf(KMF2UMF_EVID_HDMI, KMF2UMF_EVTYPE_HDMI_MHL_RCP_CMD, (UINT8 *)&rcpData, sizeof(MHL_RCP_CMD_e)); } return( rcpkStatus ); } //------------------------------------------------------------------------------ // Function: CbusAppProcessRecvRapMsg // Description: Process the passed RAP message. // Returns: The RAPK status code. //------------------------------------------------------------------------------ static MHL_RAPE_STATUS_e CbusAppProcessRecvRapMsg(MHL_RAP_SUBCMD_e rapData) { MHL_RAPE_STATUS_e rapkStatus = MHL_MSC_MSG_RAP_NO_ERROR; mhldbg("[%s] RAP Key Code: 0x%02X\n", __FUNCTION__, (INT32)rapData); switch ( rapData ) { case MHL_RAP_CMD_POLL: mhldbg("POLL received\n" ); break; case MHL_RAP_CONTENT_ON: mhldbg("Change TO CONTENT_ON STATE received\n" ); HDMI_NoticeHandler(HDMINOTICE_MHL_CONTENT_ON, "MHL_RAP_CONTENT_ON"); break; case MHL_RAP_CONTENT_OFF: mhldbg("Change TO CONTENT_OFF STATE received\n" ); HDMI_NoticeHandler(HDMINOTICE_MHL_CONTENT_OFF, "MHL_RAP_CONTENT_OFF"); break; default: rapkStatus = MHL_MSC_MSG_RAP_UNRECOGNIZED_ACT_CODE; mhldbg("Action Code not recognized !! \n" ); break; } return( rapkStatus ); } //------------------------------------------------------------------------------ // Function: CbusAppProcessPrivateMessage // Description: Get the result of the last message sent and use it appropriately // or process a request from the connected device. // Parameters: channel - CBUS channel that has message data for us. //------------------------------------------------------------------------------ static void CbusAppProcessPrivateMessage(void) { UINT8 status; //cbus_req_t cmdRequest; UINT8 bCmdType, bData; //CbusMidRequestDataGet( &cmdRequest); if(CbusMidRequestDataGet( &bCmdType, &bData) == ERROR_INVALID) return; //mhldbg("[%s] received 0x%x 0x%x\n", __FUNCTION__, bCmdType, bData); switch ( bCmdType ) { case MHL_MSC_MSG_RCP: /* Acknowledge receipt of command and process it. Note that */ /* we could send the ack before processing anything, because it */ /* is an indicator that the command was properly received, not */ /* that it was executed, however, we use one function to parse */ /* the command for errors AND for processing. The only thing we */ /* must do is make sure that the processing does not exceed the */ /* ACK response time limit. */ status = CbusAppProcessRecvRcpMsg( bData ); //RCP ACK by HW //CbusRcpMessageAck(status, cmdRequest.offsetData ); break; case MHL_MSC_MSG_RCPK: break; case MHL_MSC_MSG_RCPE: break; case MHL_MSC_MSG_RAP: status = CbusAppProcessRecvRapMsg( bData ); CbusMidRapMessageAck(status ); break; case MHL_MSC_MSG_RAPK: break; default: break; } } //------------------------------------------------------------------------------ // Function: CbusAppDeviceInit // Description: Perform any board-level initialization required at the same // time as CBUS component initialization // Parameters: none // Returns: none //------------------------------------------------------------------------------ void CbusAppDeviceInit(void) { mhldbg("[%s]\n", __FUNCTION__); CbusAppInitialize(); CbusMidInitialize(); CbusDrvInitialize(); } void DRV_MHL_GetMHLAppInstanceData(MHLAppInstanceData_t * pMHLdata) { if(NULL == pMHLdata) return; memset(pMHLdata,0x0,sizeof(MHLAppInstanceData_t)); memcpy(pMHLdata,pMHLApp,sizeof(MHLAppInstanceData_t)); mhldbg("[%s] MHLConnected: %d \n", __FUNCTION__,pMHLApp->cbusConnected); //* Start MHL CBUS Work */ MHL_CBUS_Work_Enable(TRUE); } //------------------------------------------------------------------------------ // Function: CbusAppTask // Description: Wrapper for the CBUS Component at the application level // Parameters: none // Returns: none //------------------------------------------------------------------------------ void CbusAppTask(void) { // UINT8 status; BOOL fCbusConnected=FALSE; static UINT8 hdmi_source_change=0; // Check for any interrupt. CbusDrvProcessInterrupts(); MHLTaskInterruptMonitor(); /* Monitor all CBUS channels. */ CbusMidHandler(); // Monitor CBUS interrupts. /* do something at changing state once */ if(eCbusAppState != eCbusAppNextState) { mhldbg("[%s] state:%d -> %d\n", __FUNCTION__, eCbusAppState, eCbusAppNextState); switch(eCbusAppNextState) { case CBUS_APP_FSM_UNATTACHED: CbusMidInitialize(); if(GPIOGetValueByPinFunc(GPIO_PIN_MHL_CD_SENSE_DETECT)==0) { MHLTaskCableDetect(FALSE); fCbusConnected=FALSE; HPDWaitConnectedCnt=0; WaitDiscvCnt =0; WaitPllCnt=0; WaitHDCPCnt=0; hdmi_source_change=0; } pMHLApp->cbusConnected =fCbusConnected ; noticekmf(KMF2UMF_EVID_HDMI, KMF2UMF_EVTYPE_HDMI_MHL_CONNECTED, &fCbusConnected, sizeof(BOOL)); break; case CBUS_APP_FSM_ATTATCHED: MHLTaskCableDetect(TRUE); break; case CBUS_APP_FSM_CONNECTED: WaitDiscvCnt = 51; CbusMidSetDevCapReadyBit(FALSE); fCbusConnected=TRUE; HPDWaitConnectedCnt=0; pMHLApp->cbusConnected =fCbusConnected ; noticekmf(KMF2UMF_EVID_HDMI, KMF2UMF_EVTYPE_HDMI_MHL_CONNECTED, &fCbusConnected, sizeof(BOOL)); mhldbg("[%s] KMF2UMF_EVTYPE_HDMI_MHL_CONNECTED :%d\n", __FUNCTION__ ,fCbusConnected); /* Remove no signal timer */ hdmi_signal_check_stop(); break; case CBUS_APP_FSM_PATH_ENABLED: break; default: break; } eCbusAppState = eCbusAppNextState; } if (CbusMidGet_HPD_Status()==FALSE) { if((eCbusAppState >= CBUS_APP_FSM_CONNECTED) && (pMHLApp->cbusCableSense == TRUE)) { HPDWaitConnectedCnt++; } if(HPDWaitConnectedCnt>100)// *10ms { mhldbg("[%s] CbusMidSendCommand(MHL_SET_HPD)\n", __FUNCTION__); CbusMidSendCommand(MHL_SET_HPD); HPDWaitConnectedCnt=0; } } else { HPDWaitConnectedCnt=0; } /* 1. check status to change state machine 2. check received RCP & RAP after PATH_EN*/ switch(eCbusAppState) { case CBUS_APP_FSM_UNATTACHED: if(pMHLApp->cbusCableSense == TRUE) eCbusAppNextState = CBUS_APP_FSM_ATTATCHED; break; case CBUS_APP_FSM_ATTATCHED: //have CD_SENSE if(WaitDiscvCnt<=50)// *10ms { mhldbg("WaitDiscvCnt=%d.\n",WaitDiscvCnt); if(WaitDiscvCnt==50) { mhldbg("WaitDiscvCnt=%d=>MHL_VbusToggle().\n",WaitDiscvCnt); //sysset_Cbus_Z_CBUS_SINK_DISCOVER(Z_CBUS_SINK_DISCOVER_CFG_OFF); MHL_VbusToggle(); //sysset_Cbus_Z_CBUS_SINK_DISCOVER(Z_CBUS_SINK_DISCOVER_CFG_HARDWARE_AUTO); } WaitDiscvCnt++; } else { WaitDiscvCnt++; if((WaitDiscvCnt%100)==0){ mhldbg("WaitDiscvCnt=%d.\n",WaitDiscvCnt);} if((WaitDiscvCnt%500)==0) { mhldbg("WaitDiscvCnt=%d=>MHL_VbusToggle().\n",WaitDiscvCnt); MHL_VbusToggle(); HDMI_RegisterWrite(CTRLI_303_272__DW_001C,0x80000000);//auto mode } } break; case CBUS_APP_FSM_CONNECTED: //got discovery pulse if(CbusMidSendPathEn_RcvdAck()) { eCbusAppNextState = CBUS_APP_FSM_PATH_ENABLED; CbusMidGetSrcDevCap(TRUE);//Get source's device capability } else { if((CbusMidGetDevCapReadyBit() == FALSE) && (DrvHDMIPortSelectBitsGet()==CONFIG_HDMI_MHL_PORT)) CbusMidSendDcapRdyMsg(); //send DCAP_CHG DCAP_RDY PATH_EN } break; case CBUS_APP_FSM_PATH_ENABLED: //source sent PATH_EN //source's device capability changed, fetch it if(CbusDrvDevCapChangedGet() == TRUE) { CbusMidGetSrcDevCap(TRUE); } else { CbusMidGetSrcDevCap(FALSE); } //process received RCP or RAP command CbusAppProcessPrivateMessage(); if((CbusMidGetDevCapReceiveDone()==TRUE)&&(DrvHDMIPortSelectBitsGet()==CONFIG_HDMI_MHL_PORT)) { if(hdmi_source_change==1) { hdmi_source_change=0; if(CbusMidGetAdoptID()==ADOPTER_ID_HTC) { if (CbusMidGet_HPD_Status()==TRUE) CbusMidSendCommand(MHL_CLR_HPD); } } if((0 == HDMI_RegisterRead(HDMIRX_PHYPLLLOCK)) && (0 == HDMI_RegisterRead(HDMIRX_IN_RANGE))) { if ( ADOPTER_ID_SIMPLAY != CbusMidGetAdoptID()) // ignore mexiu { if(WaitPllCnt<=150)// *10ms { if((WaitPllCnt%10) == 0){mhldbg("WaitPllCnt=%d.\n",WaitPllCnt);} if(WaitPllCnt==150) { mhldbg("WaitPllCnt=%d=>hdmi_set_termination().\n",WaitPllCnt); if(CONFIG_HDMI_MHL_PORT==0) { hdmi_set_termination(DRV_HDMI_PORT_A, DRV_HPD_LEVEL_LOW); HDMI_DelayMs(500); hdmi_set_termination(DRV_HDMI_PORT_A, DRV_HPD_LEVEL_HIGH); } else if(CONFIG_HDMI_MHL_PORT==1) { hdmi_set_termination(DRV_HDMI_PORT_B, DRV_HPD_LEVEL_LOW); HDMI_DelayMs(500); hdmi_set_termination(DRV_HDMI_PORT_B, DRV_HPD_LEVEL_HIGH); } mhldbg("=>hdmi_set_termination().end.\n"); } WaitPllCnt++; } } } //if((0 == HDMI_RegisterRead(HDMIRX_PHYPLLLOCK)) && (0 == HDMI_RegisterRead(HDMIRX_IN_RANGE))) if(0 == HDMI_RegisterRead(HDMIRX_PHYPLLLOCK)) if(WaitHDCPCnt<=200)// *10ms { if((WaitHDCPCnt%10) == 0){mhldbg("WaitHDCPCnt=%d.\n",WaitHDCPCnt);} if(WaitHDCPCnt==200) { if(CbusMidGetAdoptID()==ADOPTER_ID_HTC) { mhldbg("WaitHDCPCnt=%d=>CbusMidSendCommand(MHL_CLR_HPD);\n",WaitHDCPCnt); CbusMidSendCommand(MHL_CLR_HPD); mhldbg("=>CbusMidSendCommand(MHL_CLR_HPD);).end.\n"); } WaitHDCPCnt=0; } else WaitHDCPCnt++; } } if(DrvHDMIPortSelectBitsGet()!=CONFIG_HDMI_MHL_PORT) { hdmi_source_change = 1; } break; default: break; } if((pMHLApp->discvDetect == TRUE) && (eCbusAppState != CBUS_APP_FSM_UNATTACHED)) { eCbusAppNextState = CBUS_APP_FSM_CONNECTED; pMHLApp->discvDetect = FALSE; } #if 1 if((pMHLApp->srcDiscont == TRUE) && (eCbusAppState != CBUS_APP_FSM_UNATTACHED)) { eCbusAppNextState = CBUS_APP_FSM_UNATTACHED; //WaitDiscvCnt =0; pMHLApp->srcDiscont = FALSE; } #endif /* if CableDetect is False, change to UNATTACHED state */ if((eCbusAppState != CBUS_APP_FSM_UNATTACHED) && (pMHLApp->cbusCableSense == FALSE)) eCbusAppNextState = CBUS_APP_FSM_UNATTACHED; } //------------------------------------------------------------------------------ // Function: MHLTaskCableDetect // Description: MHLCableDetect at the application level // Parameters: none // Returns: none //------------------------------------------------------------------------------ extern BOOL HAVE_MHL_ADOPTER_ID; void MHLTaskCableDetect(BOOL fCdSense) { if (fCdSense)//(MID_GPIO_GetGPIOInputLevel(GPIO_MHL_CD_SENSE))//Bryan@2013.0403 Need Config GPIO for MHL in IFH118 { mhldbg("MHL cable connect is TRUE.\n"); mhldbg("Cbus Reset Discovery Logic" ); //CbusMidSetDevCapReadyBit(FALSE ); HDMI_MHL_CABLE_IN(TRUE); #if 0 /* Turn VBUS ON */ if( MHL_ADOPTER_ID_Check()== FALSE) { mhldbg("=>TOGGLE MHL_VbusCtrl.\n"); MHL_VbusCtrl(VBUS_DISABLE); HDMI_DelayMs(500); } #endif MHL_VbusCtrl(VBUS_ENABLE); #ifdef CONFIG_HDMI_MHL_PORT if( DrvHDMIPortSelectBitsGet()==CONFIG_HDMI_MHL_PORT) { //CbusMhlHpdSetState(CbusHPD_TOGGLE);//Bryan@20140506 Marked for MHL CTS 4.3.17.2 HDMI_MHL_RxSense_Term_Debug(FALSE); //auto HDMI or MHL mode) if(CONFIG_HDMI_MHL_PORT==0) { //hdmi_set_termination(DRV_HDMI_PORT_A, DRV_HPD_LEVEL_HIGH); sysset_HDMI_HPD_1K_OnOff(HDMI_PORT_A, FALSE); sysset_HDMI_SW5V(HDMI_PORT_A, TRUE); } else if(CONFIG_HDMI_MHL_PORT==1) { //hdmi_set_termination(DRV_HDMI_PORT_B, DRV_HPD_LEVEL_HIGH); sysset_HDMI_HPD_1K_OnOff(HDMI_PORT_B, FALSE); sysset_HDMI_SW5V(HDMI_PORT_B, TRUE); } } else { HDMI_MHL_RxSense_Term_Debug(TRUE); } #endif } else { mhldbg("MHL cable connect is FALSE.\n"); if(GPIOGetValueByPinFunc(GPIO_PIN_MHL_CD_SENSE_DETECT)==0) { mhldbg("=>MHL_VbusCtrl(VBUS_DISABLE).\n"); MHL_VbusCtrl(VBUS_DISABLE); } HDMI_MHL_CABLE_IN(FALSE); #ifdef CONFIG_HDMI_MHL_PORT if( DrvHDMIPortSelectBitsGet()==CONFIG_HDMI_MHL_PORT) { HDMI_Set_PLL_Mode(HDMI_PLL_MODE_HDMI_ENABLE); HDMI_MHL_RxSense_Term_Debug(TRUE); //force HDMI mode for debug(not MHL mode) #ifdef HDMI_HPD_USE_1K_OHM if(CONFIG_HDMI_MHL_PORT==0) { //hdmi_set_termination(DRV_HDMI_PORT_A, DRV_HPD_LEVEL_LOW); sysset_HDMI_HPD_1K_OnOff(HDMI_PORT_A, TRUE); } else if(CONFIG_HDMI_MHL_PORT==1) { //hdmi_set_termination(DRV_HDMI_PORT_B, DRV_HPD_LEVEL_LOW); sysset_HDMI_HPD_1K_OnOff(HDMI_PORT_B, TRUE); } #endif } #endif } noticekmf(KMF2UMF_EVID_HDMI, KMF2UMF_EVTYPE_HDMI_MHL_PLUG_STATE, &fCdSense, sizeof(BOOL)); } //------------------------------------------------------------------------------------------------- //! @brief Monitors interrupts and notifies components that have received //! an interrupt. //------------------------------------------------------------------------------------------------- void MHLTaskInterruptMonitor(void) { CBUS_DRV_STATUS_e statusFlags; statusFlags =CbusDrvStatus(); if ( statusFlags & CBUS_INT )// CBUS_INT { if ( statusFlags & CBUS_SRC_DISCONT_INT)// CBUS_SRC_DISCONT_INT { printk("[MHL]** CBUS_SRC_DISCONT_INT **\n"); pMHLApp->srcDiscont=TRUE; eCbusAppState= 0; } if ( statusFlags & CBUS_DISCV_INT )// CBUS_DISCV_INT { printk("[MHL]** CBUS_DISCV_INT **\n"); pMHLApp->discvDetect=TRUE; eCbusAppState= 0; } if ( statusFlags & CBUS_ATTACH_INT )// CBUS_ATTACH_INT { printk("[MHL]** CBUS_ATTACH_INT **\n"); pMHLApp->cbusCableSense = TRUE; } else if ( statusFlags & CBUS_DEATCH_INT )// CBUS_DEATCH_INT { printk("[MHL]** CBUS_DEATCH_INT **\n"); HAVE_MHL_ADOPTER_ID =FALSE; pMHLApp->cbusCableSense = FALSE; } } if((MHL_CD_SENSE_SEL() == FALSE)&&(pMHLApp->cbusCableSense = TRUE)&&(GPIOGetValueByPinFunc(GPIO_PIN_MHL_CD_SENSE_DETECT)==0)) { HAVE_MHL_ADOPTER_ID =FALSE; pMHLApp->cbusCableSense = FALSE; } }