//*************************************************************************** //!file mid_cbus.c //!brief // //***************************************************************************/ #include /* printk */ #include #include "cbus_mid.h" #include "cbus_drv.h" #include "cbus_debug.h" #include "../hdmi_cfg.h" #include "drv_hdmi_external.h" #include "../hdmi_hw.h" #include #include #include "../hdmi_notice.h" #include "../hdmi_time.h" #include "../sysreg.h" #include "../../../module_include/drv_hdmi_internal.h" //------------------------------------------------------------------------------ // CBUS Component Instance Data //------------------------------------------------------------------------------ #define CH_ACTIVE_INDEX (pMidCbus->chState.activeIndex) #define CH_NEXT_INDEX ((pMidCbus->chState.activeIndex + 1) % CBUS_MAX_COMMAND_QUEUE) //------------------------------------------------------------------------------ // CBUS Instance Data //------------------------------------------------------------------------------ CbusMidInstanceData_t cbusInstance[NUM_CBUS]; CbusMidInstanceData_t *pMidCbus = &cbusInstance[0]; //------------------------------------------------------------------------------ // CBUS Global Data //------------------------------------------------------------------------------ #define DEV_CAP_OFFSET_ARRAY_SIZE 9 static const UINT8 bGetDevCapOffsetArray[DEV_CAP_OFFSET_ARRAY_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e}; BOOL MHL_DEV_CAN_PERFORM_CBUS_RESET=TRUE; //------------------------------------------------------------------------------ // Function: CbusMidRequestStatus // Description: Return the status of the message currently in process, if any. // Parameters: // Returns: CBUS_REQ_IDLE, CBUS_REQ_PENDING, CBUS_REQ_SENT, or CBUS_REQ_RECEIVED //------------------------------------------------------------------------------ CBUS_REQ_e CbusMidRequestStatus(void) { return(pMidCbus->chState.request[ CH_ACTIVE_INDEX ].reqStatus); } //------------------------------------------------------------------------------ // Function: CbusMidRequestSetStatus // Description: Set the active request to the specified state // Parameters: //------------------------------------------------------------------------------ void CbusMidRequestSetStatus(CBUS_REQ_e newState) { pMidCbus->chState.request[ CH_ACTIVE_INDEX ].reqStatus = newState; } //------------------------------------------------------------------------------ // Function: CbusMidRequestDataGet // Description: Return a copy of the currently active request structure // Parameters: pbCmdType: return received MSC Command Type // pbData: return received MSC Command data // Returns: none //------------------------------------------------------------------------------ UINT8 CbusMidRequestDataGet(UINT8 *pbCmdType, UINT8 *pbData) { if(CbusDrvMSCSubDataGet(pbCmdType, pbData) == FALSE) //if no received sub command { return ERROR_INVALID; } //mhldbg("[%s] received MSC SubCmd 0x%x 0x%x\n", __FUNCTION__, *pbCmdType, *pbData); return CBUS_SUCCESS; } //------------------------------------------------------------------------------ // Function: CbusMidChannelConnected // Description: Return the CBUS channel connected status for this channel. // Returns: TRUE if connected. // FALSE if disconnected. //------------------------------------------------------------------------------ BOOL CbusMidChannelConnected(void) { return(pMidCbus->chState.connected); } //------------------------------------------------------------------------------ // Function: CbusMidSendNextInQueue // Description: Starting at the current active index, send the next pending // entry, if any //------------------------------------------------------------------------------ static INT32 CbusMidSendNextInQueue(void) { INT32 result = CBUS_SUCCESS; INT32 nextIndex = 0, endIndex = (CH_ACTIVE_INDEX+CBUS_MAX_COMMAND_QUEUE-1)%CBUS_MAX_COMMAND_QUEUE; nextIndex =CH_ACTIVE_INDEX; while(1) { if(pMidCbus->chState.request[ nextIndex].reqStatus == CBUS_REQ_PENDING) break; if(nextIndex == endIndex) // Searched whole queue, no pending messages { return(CBUS_SUCCESS); // No pending messages, return success } nextIndex =(nextIndex ==(CBUS_MAX_COMMAND_QUEUE - 1))? 0 :(nextIndex + 1); } //CbusMidPrintChannelInfo(__FUNCTION__, __LINE__); mhldbg("[%s] index:%d cmd:0x%x offset: 0x%x\n", __FUNCTION__, nextIndex, pMidCbus->chState.request[ nextIndex].command, pMidCbus->chState.request[ nextIndex].offsetData); // Found a pending message, send it out if(CbusDrvWriteCommand(&pMidCbus->chState.request[ nextIndex])) { pMidCbus->chState.request[nextIndex].reqStatus = CBUS_REQ_SENT; pMidCbus->chState.state = CBUS_SENT_WAIT_RESPONSE; pMidCbus->chState.lastSendTime = HDMI_GetSysTime(); pMidCbus->chState.sendNextWaitTime = 0; //reset wait time if(pMidCbus->chState.request[CH_ACTIVE_INDEX].command == MHL_CLR_HPD) { pMidCbus->chState.sendNextWaitTime = CBUS_HPD_WAIT_TIME; } } else { result = ERROR_WRITE_FAILED; } //CbusMidPrintChannelInfo(__FUNCTION__, __LINE__); return(result); } //------------------------------------------------------------------------------ // Function: CbusMidResetToIdle // Description: Set the specified channel state to IDLE. Clears any messages that // are in progress or queued. Usually used if a channel connection // changed or the channel heartbeat has been lost. //------------------------------------------------------------------------------ static void CbusMidResetToIdle(void) { UINT8 queueIndex; mhldbg("[%s]\n", __FUNCTION__); pMidCbus->chState.state = CBUS_IDLE; for(queueIndex = 0; queueIndex < CBUS_MAX_COMMAND_QUEUE; queueIndex++) { pMidCbus->chState.request[ queueIndex].reqStatus = CBUS_REQ_IDLE; } } //------------------------------------------------------------------------------ // Function: CbusMidInsertCmdToQueue // Description: Place a command in the CBUS message queue. If queue was empty, // send the new command immediately. // // Parameters: // pReq - Pointer to a cbus_req_t structure containing the // command to write // Returns: TRUE - successful queue/write // FALSE - write and/or queue failed //------------------------------------------------------------------------------ BOOL CbusMidInsertCmdToQueue(cbus_req_t *pReq) { INT32 queueIndex; BOOL success = FALSE; #ifdef CBUS_DETAIL_DEBUG_MSG UINT8 i = 0; UINT8 bStr[100] = ""; char bTemp[10] = ""; mhldbg("[%s] Channel State: cmd:0x%02x offset:0x%02x len:%d\n", __FUNCTION__, pReq->command, pReq->offsetData, pReq->length); memset(bStr, 0, 100); for(i = 0; i< MHL_MAX_BUFFER_SIZE;i++) { sprintf(bTemp, "0x%x ",pReq->msgData[i]); strcat(bStr, bTemp); } mhldbg("\tmsg: %s\n",bStr); #endif //print request for debug //CbusMidPrintChannelInfo(__FUNCTION__, __LINE__); if(pMidCbus->chState.connected) { queueIndex = CH_NEXT_INDEX; do{ if(pMidCbus->chState.request[ queueIndex].reqStatus == CBUS_REQ_IDLE) { // Found an idle queue entry, copy the request and set to pending. memcpy(&pMidCbus->chState.request[ queueIndex], pReq, sizeof(cbus_req_t)); pMidCbus->chState.request[ queueIndex].reqStatus = CBUS_REQ_PENDING; success = TRUE; mhldbg("[%s] index:%d cmd:0x%x offset: 0x%x\n", __FUNCTION__, queueIndex, pReq->command, pReq->offsetData); break; } queueIndex=((queueIndex+1)%CBUS_MAX_COMMAND_QUEUE); }while(queueIndex != CH_NEXT_INDEX); /* If successful at putting the request into the queue */ if(success == FALSE) { printk("[MHL]CBUS:: Queue full - skip cmd:0x%x offset:0x%x\n", pReq->command, pReq->offsetData); } } //print queue data for debug //CbusMidPrintChannelInfo(__FUNCTION__, __LINE__); return(success); } //------------------------------------------------------------------------------ // Function: CbusMidMscMsgSubCmdSend // Description: Send MSC_MSG(RCP)message to the specified CBUS channel(port) // // Parameters: channel - CBUS channel // vsCommand - MSC_MSG cmd(RCP, RCPK or RCPE) // cmdData - MSC_MSG data // Returns: TRUE - successful queue/write // FALSE - write and/or queue failed //------------------------------------------------------------------------------ BOOL CbusMidMscMsgSubCmdSend(UINT8 vsCommand, UINT8 cmdData) { cbus_req_t req; // Send MSC_MSG command(Vendor Specific command) req.command = MHL_MSC_MSG; req.msgData[0] = vsCommand; req.msgData[1] = cmdData; if(!(CbusMidInsertCmdToQueue(&req))) { printk("[MHL]Couldn't send MHL_MSC_MSG to peer\n"); return FALSE; } return TRUE; } //------------------------------------------------------------------------------ // Function: CbusMidRapMessageAck // Description: Send RAPK(acknowledge)message to the specified CBUS channel // and set the request status to idle. // // Returns: TRUE - successful queue/write // FALSE - write and/or queue failed //------------------------------------------------------------------------------ BOOL CbusMidRapMessageAck(MHL_RAPE_STATUS_e cmdStatus) { return(CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RAPK, (UINT8)cmdStatus)); } //------------------------------------------------------------------------------ // Function: CbusMidProcessFailureInterrupts // Description: Check for and process any failure interrupts. // Returns: SUCCESS or ERROR_CBUS_ABORT //------------------------------------------------------------------------------ static UINT8 CbusMidProcessFailureInterrupts(UINT32 CbusTransIntStatus) { UINT8 result = CBUS_SUCCESS; UINT8 mscAbortReason, ddcAbortReason; UINT8 mscFailReason; CbusDrvDdcAbortReasonGet(&ddcAbortReason); CbusDrvMscAbortReasonGet(&mscAbortReason); CbusDrvMscFailReasonGet(&mscFailReason); if(CbusTransIntStatus) { // Check for failure interrupts. if(mscFailReason != 0) { mhldbg("CBUS:: ----mscFailReason:%x----\n",mscFailReason); mhldbg("CBUS:: ----mscAbortReason:%x----\n",mscAbortReason); if(CbusDrvNackFromPeerGet()) { mhldbg("NACK received from peer!!! \n"); pMidCbus->chState.sendNextWaitTime = CBUS_NACK_WAIT_TIME; //responder nack, retry this command pMidCbus->chState.state = CBUS_IDLE; pMidCbus->chState.request[CH_ACTIVE_INDEX].reqStatus = CBUS_REQ_PENDING; result = ERROR_NACK_FROM_PEER; } else if(mscFailReason != 0) { //send fail, skip this command pMidCbus->chState.state = CBUS_IDLE; pMidCbus->chState.request[CH_ACTIVE_INDEX].reqStatus = CBUS_REQ_IDLE; if(CbusDrvAbortFromPeerGet()) { //responder abort pMidCbus->chState.sendNextWaitTime = CBUS_ABORT_WAIT_TIME; mhldbg("ABORT received from peer!!! \n"); result = ERROR_ABORT_FROM_PEER; } else if(CbusDrvIneffectCodeFromPeerGet()) { //responder ineffect code mhldbg("INEFFECT CODE received from peer!!! \n"); result = ERROR_INEFFECT_CODE_FROM_PEER; } else { mhldbg("MSC other fail 0x%x received from peer!!! \n", mscFailReason); result = ERROR_WRITE_FAILED; } } if(CbusTransIntStatus & wrt_stat_intr) { mhldbg("CBUS:: ----wrt_stat Fail----\n"); } if(CbusTransIntStatus & red_devc_intr) { mhldbg("CBUS:: ----red_devc Fail----\n"); } if(CbusTransIntStatus & get_state_intr) { mhldbg("CBUS:: ----get_state Fail----\n"); } if(CbusTransIntStatus & get_ven_id_intr) { mhldbg("CBUS:: ----get_ven_id Fail----\n"); } if(CbusTransIntStatus & get_src1_err_intr) { mhldbg("CBUS:: ----get_src1_err Fail----\n"); } if(CbusTransIntStatus & get_ddc_err_intr) { mhldbg("CBUS:: ----get_ddc_err Fail----\n"); } if(CbusTransIntStatus & get_msc_err_intr) { mhldbg("CBUS:: ----get_msc_err Fail----\n"); } if(CbusTransIntStatus & get_src3_err_intr) { mhldbg("CBUS:: ----get_src3_err Fail----\n"); } if(CbusTransIntStatus & wrt_burst_intr) { mhldbg("CBUS:: ----wrt_burst Fail----\n"); } if(CbusTransIntStatus & set_hpd_intr) { mhldbg("CBUS:: ----set_hpd Fail----\n"); } if(CbusTransIntStatus & clr_hpd_intr) { mhldbg("CBUS:: ----clr_hpd Fail----\n"); } if(CbusTransIntStatus & rap_act_ack_intr) { mhldbg("CBUS:: ----rap_act_ack Fail----\n"); } //NACK packet of MSC_MSG back from respender, wait T_NACK_RETRY_NEXT = 1000ms if(CbusTransIntStatus & rcp_cmd_intr) { mhldbg("CBUS:: ----rcp_cmd Fail----\n"); } if(CbusTransIntStatus & ucp_cmd_intr) { mhldbg("CBUS:: ----ucp_cmd Fail----\n"); } if(CbusTransIntStatus & rap_cmd_intr) { mhldbg("CBUS:: ----rap_cmd Fail----\n"); } } else { pMidCbus->chState.state = CBUS_IDLE; pMidCbus->chState.request[CH_ACTIVE_INDEX].reqStatus = CBUS_REQ_IDLE; } if(pMidCbus->chState.request[CH_ACTIVE_INDEX].reqStatus == CBUS_REQ_IDLE) CH_ACTIVE_INDEX = CH_NEXT_INDEX; //next index if(ddcAbortReason != 0) { mhldbg("CBUS:: ----ddcAbortReason:%x----\n",ddcAbortReason); } } return(result); } //------------------------------------------------------------------------------ // Function: CbusMidCheckInterruptStatus // Description: If any interrupts on the specified channel are set, process them. // Parameters: // Returns: SUCCESS or CBUS_SW_ERR_e error code. //------------------------------------------------------------------------------ BOOL HAVE_MHL_ADOPTER_ID=FALSE; static CBUS_SW_ERR_e CbusMidCheckInterruptStatus(void) { UINT32 CbusTransIntStatus, CbusLinkIntStatus, result; UINT8 bData1, bData2; UINT16 wAdopterId; /* Read CBUS interrupt status. */ CbusDrvInterruptStatusGet(&CbusTransIntStatus, &CbusLinkIntStatus); /* Check for interrupts. */ result = CBUS_SUCCESS; if(CbusTransIntStatus != 0) { //CbusDrvWriteCommand's intr if((CbusTransIntStatus & wrt_stat_intr)||(CbusTransIntStatus & red_devc_intr)||(CbusTransIntStatus & get_state_intr)||(CbusTransIntStatus & get_ven_id_intr)|| (CbusTransIntStatus & get_src1_err_intr)||(CbusTransIntStatus & get_ddc_err_intr)||(CbusTransIntStatus & get_msc_err_intr)||(CbusTransIntStatus & get_src3_err_intr)||(CbusTransIntStatus & wrt_burst_intr)|| (CbusTransIntStatus & rcp_cmd_intr)||(CbusTransIntStatus & rap_cmd_intr)||(CbusTransIntStatus & ucp_cmd_intr)||(CbusTransIntStatus & rap_act_ack_intr)|| (CbusTransIntStatus & set_hpd_intr)||(CbusTransIntStatus & clr_hpd_intr)) { /* A previous MSC sub-command has been acknowledged by the responder. */ /* Does not include MSC MSG commands.*/ mhldbg("CBUS:: Transfer Done \n"); /* Check for failure interrupts. */ result = CbusMidProcessFailureInterrupts(CbusTransIntStatus); //mhldbg("CBUS:: Transfer Done - Data returned: %02X %02X\n", *pData, *pData1); } if(CbusDrvWrtStateAckInfoGet(&bData1, &bData2) == TRUE) { if((bData1 == 0x31) && ((bData2 & 0x08) != 0)) { pMidCbus->chState.sinkPathEn = TRUE; } else if((bData1 == 0x20) && ((bData2 & 0x02) != 0)) { pMidCbus->chState.sinkDscrChgAck = TRUE; } } if(CbusTransIntStatus & rcp_cmd_intr) { #ifdef MHL_ONLY_ONE_RCP_IN_QUEUE if(pMidCbus->chState.SrcNotSprtRcpRelease == TRUE) //if source does not support RCP release command, there is one RCP command in queue { if(pMidCbus->chState.request[CH_ACTIVE_INDEX].reqStatus == CBUS_REQ_IDLE) //RCP command done, needn't retry { pMidCbus->chState.existRcpInQueue = FALSE; } } else //if source supports RCP release command, there is two RCP command in queue { if((pMidCbus->chState.request[CH_ACTIVE_INDEX].reqStatus == CBUS_REQ_IDLE) && (pMidCbus->chState.request[CH_ACTIVE_INDEX].msgData[1] & 0x80) == 0x80) //RCP command done, needn't retry { pMidCbus->chState.existRcpInQueue = FALSE; } } #endif //source does not support RCP release command if((result == ERROR_INEFFECT_CODE_FROM_PEER) && (pMidCbus->chState.request[CH_ACTIVE_INDEX].command == MHL_MSC_MSG) && (pMidCbus->chState.request[CH_ACTIVE_INDEX].msgData[0] == MHL_MSC_MSG_RCP) && ((pMidCbus->chState.request[CH_ACTIVE_INDEX].msgData[1] & 0x80) == 0x80)) { mhldbg("Source does not support RCP release command!!! \n"); pMidCbus->chState.SrcNotSprtRcpRelease = TRUE; } } if(CbusTransIntStatus & req_3d_intr) { pMidCbus->chState.srcReq3D = TRUE; CbusMidSend3DVideoSupportList(TRUE); } if(CbusTransIntStatus & req_wrt_intr) { // request received from peer to write into scratchpad if(CbusDrvReqWrtGet()) { mhldbg("\n\ngranting peer's request to write scratchpad!!\n"); CbusMidGrtWrt(); } } if(CbusTransIntStatus & grt_wrt_intr) { // request to write into peer's scratchpad is granted if(CbusDrvGrtWrtGet()) { mhldbg("peer sent grtWrt!!\n"); pMidCbus->chState.srcGrtWrt = TRUE; } } if(CbusTransIntStatus & clr_hpd_intr) { CbusMidSendCommand(MHL_SET_HPD); } if(CbusTransIntStatus & set_hpd_intr) { pMidCbus->chState.setHPD = TRUE; } if(CbusTransIntStatus & red_devc_intr) { CbusDrvDevCapGet(&bData1, &bData2); pMidCbus->chState.stSrcDevCap.bDevCap[bData1] = bData2; if(bData1 == bGetDevCapOffsetArray[DEV_CAP_OFFSET_ARRAY_SIZE-1]) //fetch read_device_capability done { pMidCbus->chState.stSrcDevCap.fDevCapReady = TRUE; wAdopterId = pMidCbus->chState.stSrcDevCap.wAdopterId; noticekmf(KMF2UMF_EVID_HDMI, KMF2UMF_EVTYPE_HDMI_MHL_ADOPTER_ID, (UINT8 *)&wAdopterId, 2); //print device capability mhldbg("[%s] source dev_cap: MHL_VER: 0x%x Dev_type:0x%x Adopter_ID:0x%x\n \tsupport RCP:%d, RAP:%d SP:%d UCP_Send:%d UCP_RECV:%d\n \tDevice_ID:0x%x SP_Size:%d INT_size:%d STAT_Size:%d\n", __FUNCTION__, pMidCbus->chState.stSrcDevCap.bMhlVersion, pMidCbus->chState.stSrcDevCap.bDevType, pMidCbus->chState.stSrcDevCap.wAdopterId, pMidCbus->chState.stSrcDevCap.bRcpSupport, pMidCbus->chState.stSrcDevCap.bRapSupport, pMidCbus->chState.stSrcDevCap.bSpSupport, pMidCbus->chState.stSrcDevCap.bUcpSendSupport, pMidCbus->chState.stSrcDevCap.bUcpRecvSupport, pMidCbus->chState.stSrcDevCap.wDeviceId, pMidCbus->chState.stSrcDevCap.bScratchpadSize, pMidCbus->chState.stSrcDevCap.bIntSize, pMidCbus->chState.stSrcDevCap.bStatSize); /* SAMSUNG S2, Note3, Xiaomi do not support RCP release */ if((pMidCbus->chState.stSrcDevCap.wAdopterId == ADOPTER_ID_SAMSUNG) || (pMidCbus->chState.stSrcDevCap.wAdopterId == ADOPTER_ID_SIMPLAY)) { pMidCbus->chState.SrcNotSprtRcpRelease = TRUE; } if((pMidCbus->chState.stSrcDevCap.wAdopterId == ADOPTER_ID_LG) && (pMidCbus->chState.stSrcDevCap.wDeviceId == DEVICE_ID_LG_E975W)) { MHL_DEV_CAN_PERFORM_CBUS_RESET = FALSE; } else { MHL_DEV_CAN_PERFORM_CBUS_RESET = TRUE; } if((pMidCbus->chState.stSrcDevCap.wAdopterId == ADOPTER_ID_SIMPLAY) && (pMidCbus->chState.stSrcDevCap.wDeviceId == DEVICE_ID_SIMPLAY)) { mhldbg("Set MHL_CTS = TRUE !!\n"); HDMI_MHL_CTS(TRUE); } else { mhldbg("Set MHL_CTS = FALSE !!\n"); HDMI_MHL_CTS(FALSE); } if(pMidCbus->chState.stSrcDevCap.wAdopterId == 0x00 ) { mhldbg("MHL ADOPTER_ID == 0x00 !!\n"); HAVE_MHL_ADOPTER_ID = FALSE; } else { HAVE_MHL_ADOPTER_ID = TRUE; } if(CONFIG_HDMI_MHL_PORT==0) { HDMI_RegisterWrite(HDMIRX_HDMIP0_Rx_Sense_external, 1); HDMI_RegisterWrite(HDMIRX_HDMIP0_Rx_Sense_mux, 1); } else if(CONFIG_HDMI_MHL_PORT==1) { HDMI_RegisterWrite(HDMIRX_HDMIP1_Rx_Sense_external, 1); HDMI_RegisterWrite(HDMIRX_HDMIP1_Rx_Sense_mux, 1); } } } //Peer's Device Capability ready if(CbusTransIntStatus & connected_rdy_intr) { CbusMidSendCommand(MHL_SET_HPD); } } if(CbusLinkIntStatus != 0) { if((CbusLinkIntStatus & connt_intr)||(CbusLinkIntStatus & attach_intr)||(CbusLinkIntStatus & discv_intr)||(CbusLinkIntStatus & detach_intr)||(CbusLinkIntStatus & src_discon_intr))//[2]HDMIRX_CBUS_connt_int__p Nedd check ?? { BOOL Connected; /* The connection change interrupt has been received. */ mhldbg("CBUS:: ----Connection Change----\n"); // Update component bus status for this channel. CbusDrvConnectedGet(&Connected); pMidCbus->chState.connected = Connected; //printk("[MD_INT] pMidCbus->chState.connected = %d\n", pMidCbus->chState.connected); if((CbusLinkIntStatus & discv_intr)) { pMidCbus->chState.sinkPathEn = FALSE; pMidCbus->chState.setHPD =FALSE; pMidCbus->chState.SrcNotSprtRcpRelease = FALSE; HDMI_RegisterWrite(HDMIRX_CBUS_r_reset_reg, 1); HDMI_RegisterWrite(HDMIRX_CBUS_r_reset_reg, 0); CbusMidResetToIdle(); #ifdef CONFIG_HDMI_MHL_PORT if(DrvHDMIPortSelectBitsGet()==CONFIG_HDMI_MHL_PORT) { DRV_HDMI_SW_HDCP_RSTN();//After plug in HTC EVO then plug in XIAOMI display NG CbusMidSendCommand(MHL_CLR_HPD);//For Samsung 9100 display NG //CbusMidSendCommand(MHL_SET_HPD); } else { CbusMidSendCommand(MHL_CLR_HPD); } #else // Send MHL_SET_HPD command(same as heartbeat) CbusMidSendCommand(MHL_CLR_HPD);//For Samsung 9100 display NG CbusMidSendCommand(MHL_SET_HPD); #endif } // If a disconnect, reset the channel write request state machine if(pMidCbus->chState.connected == FALSE) { //set the cbus to idle CbusMidResetToIdle(); } } } CbusDrvInterruptStatusSet(0, 0);//Clear return(result); } //------------------------------------------------------------------------------ // Function: CbusMidGetDevCapReceiveDone // Description: see if dev cap receive done // Parameters: channel to check // Returns: TRUE - success // FALSE - failure //------------------------------------------------------------------------------ BOOL CbusMidGetDevCapReceiveDone(void) { return(pMidCbus->chState.stSrcDevCap.fDevCapReady); } //------------------------------------------------------------------------------ // Function: CbusMidGetDevCapReadyBit // Description: see if dev cap ready msg has been sent or not // Parameters: channel to check // Returns: TRUE - success // FALSE - failure //------------------------------------------------------------------------------ BOOL CbusMidGetDevCapReadyBit(void) { return(pMidCbus->chState.dev_cap_regs_ready_bit); } //------------------------------------------------------------------------------ // Function: CbusMidSetDevCapReadyBit // Description: set the devCapReady bit // Parameters: channel to check, value to set // Returns: void //------------------------------------------------------------------------------ void CbusMidSetDevCapReadyBit(BOOL value) { pMidCbus->chState.dev_cap_regs_ready_bit = value; } //------------------------------------------------------------------------------ // Function: CbusMidSendDcapRdyMsg // Description: Send a msg to peer informing the devive capability registers are // ready to be read. // Parameters: channel to check // Returns: TRUE - success // FALSE - failure //------------------------------------------------------------------------------ BOOL CbusMidSendDcapRdyMsg(void) { BOOL result = TRUE; if(CbusMidChannelConnected()&&(pMidCbus->chState.setHPD==TRUE)) { mhldbg("CbusMidSendDcapRdyMsg() Called!!\n"); //send a msg to peer that the device capability registers are ready to be read. //set DCAP_RDY bit CbusMidSendDcapRdy(); //set DCAP_CHG bit CbusMidSendDcapChange(); CbusMidSetDevCapReadyBit(TRUE); // set path_en bit too result = CbusMidPathEnable(); } return result; } //------------------------------------------------------------------------------ // Function: CbusMidSendWriteBurst // Description: sends MHL write burst cmd // Parameters: //------------------------------------------------------------------------------ BOOL CbusMidSendWriteBurst(UINT8 startOffset, UINT8 length, UINT8* pMsgData) { cbus_req_t req; INT32 i; req.command = MHL_WRITE_BURST; req.offsetData = startOffset; req.length = length; // write different values in different registers for(i = 0; i < length; i++) { req.msgData[i] = pMsgData[i]; } if(!(CbusMidInsertCmdToQueue(&req))) { printk("[MHL]Couldn't send Write Burst to peer\n"); return FALSE; } return TRUE; } //------------------------------------------------------------------------------ // Function: CbusMidSendCommand // Description: sends general MHL commands // Parameters: //------------------------------------------------------------------------------ BOOL CbusMidSendCommand(UINT8 cmd) { cbus_req_t req; req.command = cmd; if(!(CbusMidInsertCmdToQueue(&req))) { printk("[MHL]Couldn't send cmd: %02X to peer\n", cmd); return FALSE; } return TRUE; } //------------------------------------------------------------------------------ // Function: CbusMidSetInt // Description: write peer's status registers // regOffset - peer's register offset // regBit - bit to be set //------------------------------------------------------------------------------ BOOL CbusMidSetInt(UINT8 regOffset, UINT8 regBit) { cbus_req_t req; req.command = MHL_SET_INT; req.offsetData = regOffset; req.msgData[0] = regBit; if(!(CbusMidInsertCmdToQueue(&req))) { printk("[MHL]Couldn't send MHL_SET_INT to peer\n"); return FALSE; } return TRUE; } //------------------------------------------------------------------------------ // Function: EdidChange // Description: set edid_chg interrupt // Parameters: channel - CBUS channel to check, must be in range, NOT 0xFF //------------------------------------------------------------------------------ BOOL CbusMidEdidChange(void) { return(CbusMidSetInt(0x01, BIT1)); } //------------------------------------------------------------------------------ // Function: DcapChange // Description: // Parameters: channel - CBUS channel to check, must be in range, NOT 0xFF //------------------------------------------------------------------------------ BOOL CbusMidSendDcapChange(void) { return(CbusMidSetInt(0x00, BIT0)); } //------------------------------------------------------------------------------ // Function: CbusDscrChange // Description: // Parameters: channel - CBUS channel to check, must be in range, NOT 0xFF //------------------------------------------------------------------------------ BOOL CbusMidSendDscrChange(void) { return(CbusMidSetInt(0x00, BIT1)); } //------------------------------------------------------------------------------ // Function: CbusMidReqWrt // Description: // Parameters: channel - CBUS channel to check, must be in range, NOT 0xFF //------------------------------------------------------------------------------ BOOL CbusMidReqWrt(void) { return(CbusMidSetInt(0x00, BIT2)); } //------------------------------------------------------------------------------ // Function: CbusMidGrtWrt // Description: // Parameters: channel - CBUS channel to check, must be in range, NOT 0xFF //------------------------------------------------------------------------------ BOOL CbusMidGrtWrt(void) { return(CbusMidSetInt(0x00, BIT3)); } //------------------------------------------------------------------------------ // Function: CbusMidWriteStatus // Description: write peer's status registers // Parameters: channel - CBUS channel to check, must be in range, NOT 0xFF // regOffset - peer's register offset // value - value to be written //------------------------------------------------------------------------------ BOOL CbusMidWriteStatus(UINT8 regOffset, UINT8 value) { cbus_req_t req; req.command = MHL_WRITE_STAT; req.offsetData = regOffset; req.msgData[0] = value; if(!(CbusMidInsertCmdToQueue(&req))) { printk("[MHL]Couldn't send MHL_WRITE_STAT to peer\n"); return FALSE; } return TRUE; } //------------------------------------------------------------------------------ // Function: CbusMidPathEnable // Description: Check if the channel is an active channel // Parameters: port - current active port //------------------------------------------------------------------------------ BOOL CbusMidPathEnable(void) { mhldbg("[%s]\n", __FUNCTION__); #ifdef CONFIG_HDMI_MHL_PORT if(DrvHDMIPortSelectBitsGet()==CONFIG_HDMI_MHL_PORT) { CbusMidWriteStatus(0x01, 0);//Disable PATH_EN bit on peer's appropriate status register(offset 0x31) // enable PATH_EN bit on peer's appropriate status register(offset 0x31) mhldbg("PathEnable:: Setting bit 3 to peer's status register.\n"); pMidCbus->isPrevPortMHL = TRUE; #if 0 //Need marked for MHL CTS 4.3.23.2 if(CONFIG_HDMI_MHL_PORT==0) { HDMI_RegisterWrite(HDMIRX_HDMIP0_Rx_Sense_external, 1); HDMI_RegisterWrite(HDMIRX_HDMIP0_Rx_Sense_mux, 1); } else if(CONFIG_HDMI_MHL_PORT==1) { HDMI_RegisterWrite(HDMIRX_HDMIP1_Rx_Sense_external, 1); HDMI_RegisterWrite(HDMIRX_HDMIP1_Rx_Sense_mux, 1); } #endif return(CbusMidWriteStatus(0x01, BIT3)); } else { if(pMidCbus->isPrevPortMHL) { // disable PATH_EN bit on peer's appropriate status register(offset 0x31) mhldbg("PathEnable:: Clearing bit 3 to peer's status register.\n"); pMidCbus->isPrevPortMHL = FALSE; return(CbusMidWriteStatus(0x01, 0)); } } #endif return(TRUE); } //------------------------------------------------------------------------------ // Function: CbusMidReadDevCap // Description: read peer's status registers // Parameters: regOffset - peer's register offset //------------------------------------------------------------------------------ BOOL CbusMidReadDevCap(UINT8 regOffset) { cbus_req_t req; req.command = MHL_READ_DEVCAP; req.offsetData = regOffset; if(!(CbusMidInsertCmdToQueue(&req))) { printk("[MHL]Couldn't send MHL_READ_DEVCAP to peer\n"); return FALSE; } return TRUE; } //------------------------------------------------------------------------------ // Function: CbusMidSendDcapRdy // Description: // Parameters: channel - CBUS channel to check, must be in range, NOT 0xFF //------------------------------------------------------------------------------ BOOL CbusMidSendDcapRdy(void) { return(CbusMidWriteStatus(0x00, BIT0)); } //------------------------------------------------------------------------------ // Function: CbusMidSendPathEn_RcvdAck // Description: check if PATH_EN msg has been sent and received ACK or not // Parameters: channel to check // Returns: TRUE - success // FALSE - failure //------------------------------------------------------------------------------ BOOL CbusMidSendPathEn_RcvdAck(void) { return(pMidCbus->chState.sinkPathEn); } //------------------------------------------------------------------------------ // Function: CbusMidGet_HPD_Status // Description: check if Set HPD msg has been sent or not // Returns: TRUE - success // FALSE - failure //------------------------------------------------------------------------------ BOOL CbusMidGet_HPD_Status(void) { return(pMidCbus->chState.setHPD ); } //------------------------------------------------------------------------------ // Function: CbusMidSend3DVideoSupportList // Description: sends 3D Support list by Write Burst // Parameters: //------------------------------------------------------------------------------ BOOL CbusMidSend3DVideoSupportList(BOOL fReset) { static CBUS_3D_FSM_STATE_e eSend3dListState = CBUS_3D_FSM_FINISHED; #ifdef CONFIG_SUPPORT_3D_EN #define CBUS_3DLIST_NUM 4 static UINT8 pb3DList[CBUS_3DLIST_NUM][MHL_MAX_BUFFER_SIZE] = {{0x00, 0x11, 0xEB, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //DTD_3D {0x00, 0x10, 0xD3, 0x0f, 0x01, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, //VIC_3D {0x00, 0x10, 0xD6, 0x0f, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, //VIC_3D {0x00, 0x10, 0xD4, 0x0f, 0x03, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VIC_3D #else #define CBUS_3DLIST_NUM 2 static UINT8 pb3DList[CBUS_3DLIST_NUM][MHL_MAX_BUFFER_SIZE] = {{0x00, 0x11, 0xEE, 0x0, 0x1, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //DTD_3D null {0x00, 0x10, 0xEF, 0x0, 0x1, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VIC_3D null #endif static UINT8 b3DListIndex = 0, bTimeout_cnt = 0, bTimeout_target =20; if(eSend3dListState != CBUS_3D_FSM_FINISHED) { mhldbg("%s state:%d\n", __FUNCTION__, eSend3dListState); } if(pMidCbus->chState.srcReq3D == FALSE) return TRUE; if(fReset == TRUE) //new 3d_intr happened, reset FSM { eSend3dListState = CBUS_3D_FSM_IDLE; b3DListIndex = 0; } switch(eSend3dListState) { case CBUS_3D_FSM_IDLE: if(pMidCbus->chState.srcReq3D == TRUE) eSend3dListState = CBUS_3D_FSM_SEND_REQ_WRT; break; case CBUS_3D_FSM_SEND_REQ_WRT: if(!CbusMidReqWrt()) //send REQ_WRT to request BURST_WRITE { mhldbg("Couldn't send REQ_WRT list to peer\n"); return FALSE; } eSend3dListState = CBUS_3D_FSM_WAIT_GRT_WRT; break; //case CBUS_3D_FSM_WAIT_REQ_WRT_ACK: case CBUS_3D_FSM_WAIT_GRT_WRT: if(pMidCbus->chState.srcGrtWrt == TRUE) { pMidCbus->chState.srcGrtWrt = FALSE; eSend3dListState = CBUS_3D_FSM_SEND_BURST_WRT; } break; case CBUS_3D_FSM_SEND_BURST_WRT: if(!CbusMidSendWriteBurst(0, MHL_MAX_BUFFER_SIZE, pb3DList[b3DListIndex])) { mhldbg("Couldn't send 3D[%d] list to peer\n", b3DListIndex); return FALSE; } eSend3dListState = CBUS_3D_FSM_WAIT_BURST_WRT_ACK; bTimeout_cnt =0; break; case CBUS_3D_FSM_WAIT_BURST_WRT_ACK: if(CbusDrvWrtBurstAckGet() == TRUE) eSend3dListState = CBUS_3D_FSM_SEND_DSCR_CHG; else { bTimeout_cnt++; if(bTimeout_cnt == bTimeout_target) eSend3dListState = CBUS_3D_FSM_SEND_BURST_WRT; } break; case CBUS_3D_FSM_SEND_DSCR_CHG: if(!CbusMidSendDscrChange()) { mhldbg("Couldn't send DSCR_CHG list to peer\n"); return FALSE; } eSend3dListState = CBUS_3D_FSM_WAIT_DSCR_CHG_ACK; break; case CBUS_3D_FSM_WAIT_DSCR_CHG_ACK: if(pMidCbus->chState.sinkDscrChgAck == TRUE) { b3DListIndex++; if(b3DListIndex < CBUS_3DLIST_NUM) { eSend3dListState = CBUS_3D_FSM_SEND_REQ_WRT; } else { pMidCbus->chState.srcReq3D = FALSE; eSend3dListState = CBUS_3D_FSM_FINISHED; } pMidCbus->chState.sinkDscrChgAck = FALSE; } break; case CBUS_3D_FSM_FINISHED: default: break; } return TRUE; } //------------------------------------------------------------------------------ // Function: CbusMidGetSrcDevCap // Description: get interest device capabilityies of source // Parameters: fReset - reset the flow of fetching Device Capability // Returns: TRUE - success // FALSE - failure //------------------------------------------------------------------------------ BOOL CbusMidGetSrcDevCap(BOOL fReset) { static UINT8 bGetIndex = 0xff; if(fReset == TRUE) { bGetIndex = 0; pMidCbus->chState.stSrcDevCap.fDevCapReady = FALSE; } if((bGetIndex >= DEV_CAP_OFFSET_ARRAY_SIZE) || (pMidCbus->chState.dev_cap_regs_ready_bit == FALSE)) return TRUE; else { if(CbusMidReadDevCap(bGetDevCapOffsetArray[bGetIndex]) == TRUE) { //mhldbg("[%s] Offset 0x%x\n", __FUNCTION__, bGetDevCapOffsetArray[bGetIndex]); bGetIndex++; } else { mhldbg("[%s] Offset 0x%x fail\n", __FUNCTION__, bGetDevCapOffsetArray[bGetIndex]); return FALSE; } } return TRUE; } //------------------------------------------------------------------------------ // Function: CbusMidGetAdoptID // Description: get AdoptID // Returns: AdoptID //------------------------------------------------------------------------------ UINT16 CbusMidGetAdoptID(void) { return pMidCbus->chState.stSrcDevCap.wAdopterId; } //------------------------------------------------------------------------------ // Function: CbusMidGetWhiteListToResetCubs // Description: get WhitList For reset cbus // Returns: true : device can reset cbus false: reset cbus is forbidden //------------------------------------------------------------------------------ UINT16 CbusMidGetWhiteListToResetCubs(void) { return MHL_DEV_CAN_PERFORM_CBUS_RESET; } // This is to check all the Timers BOOL CbusMidIsTimeout(void) { UINT32 tNow = HDMI_GetSysTime(); if((tNow - pMidCbus->chState.lastSendTime) >= pMidCbus->chState.sendNextWaitTime) { //mhldbg("[%s] timeout!\n", __FUNCTION__); return TRUE; } else { mhldbg("[%s] wait timeout!now:%d lastSend:%d wait:%d\n", __FUNCTION__, tNow, pMidCbus->chState.lastSendTime, pMidCbus->chState.sendNextWaitTime); return FALSE; } } //------------------------------------------------------------------------------ // Function: CbusMidHandler // Description: Check the state of any current CBUS message on specified channel. // Handle responses or failures and send any pending message if // channel is IDLE. // Returns: SUCCESS or one of CBUS_SW_ERR_e //------------------------------------------------------------------------------ CBUS_SW_ERR_e CbusMidHandler(void) { CBUS_SW_ERR_e result; /* Check the channel interrupt status to see if anybody is */ /* talking to us. If they are, talk back. */ result = CbusMidCheckInterruptStatus(); if(result != CBUS_SUCCESS) { return (result); } CbusMidSend3DVideoSupportList(FALSE); // check timer for send next command if(CbusMidIsTimeout() == FALSE) return (result); /* check channel to send next command */ if(pMidCbus->chState.state == CBUS_IDLE) CbusMidSendNextInQueue(); else result = CBUS_SUCCESS; return (result); } //------------------------------------------------------------------------------ // Function: CbusMidInitialize // Description: Initialize the CBUS. //------------------------------------------------------------------------------ void CbusMidInitialize(void) { mhldbg("[%s]\n", __FUNCTION__); memset(pMidCbus, 0, sizeof(CbusMidInstanceData_t)); } //------------------------------------------------------------------------------ // Function: DRV_MHL_SendRcpCmd // Description: Receive RCP Command from APP. // Returns: None //------------------------------------------------------------------------------ void DRV_MHL_SendRcpCmd(MHL_RCP_CMD_e eRcpCmd) { mhldbg("[%s] 0x%x\n", __FUNCTION__, eRcpCmd); //if(pMidCbus->chState.stSrcDevCap.bRcpSupport == FALSE) //{ // mhldbg("this device does not support RCP\n"); // return; //} #ifdef MHL_ONLY_ONE_RCP_IN_QUEUE if(pMidCbus->chState.existRcpInQueue == TRUE) { mhldbg("there is already one RCP in queue, skip this RCP 0x%x\n", eRcpCmd); } if(CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, eRcpCmd) == TRUE) //key press pMidCbus->chState.existRcpInQueue = TRUE; if(pMidCbus->chState.SrcNotSprtRcpRelease == FALSE) { CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, 0x80 | eRcpCmd); //key release } #else CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, eRcpCmd); //key press if(pMidCbus->chState.SrcNotSprtRcpRelease == FALSE) { CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, 0x80 | eRcpCmd); //key release } #endif } //------------------------------------------------------------------------------ // Function: DRV_MHL_SendRcpPressAndHoldCmd // Description: Receive Press And Hold RCP Command from APP. // Returns: None //------------------------------------------------------------------------------ void DRV_MHL_SendRcpPressAndHoldCmd(MHL_RCP_CMD_e eRcpCmd ,BOOL fPress) { mhldbg("[%s] 0x%x Press:%x\n", __FUNCTION__, eRcpCmd,fPress); //if(pMidCbus->chState.stSrcDevCap.bRcpSupport == FALSE) //{ // mhldbg("this device does not support RCP\n"); // return; //} #ifdef MHL_ONLY_ONE_RCP_IN_QUEUE if(pMidCbus->chState.existRcpInQueue == TRUE) { mhldbg("there is already one RCP in queue, skip this RCP 0x%x\n", eRcpCmd); } if(fPress == TRUE) { if(CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, eRcpCmd) == TRUE) //key press pMidCbus->chState.existRcpInQueue = TRUE; } else { CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, 0x80 | eRcpCmd); //key release } #else if(fPress == TRUE) { CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, eRcpCmd); //key press } else { if(pMidCbus->chState.SrcNotSprtRcpRelease == FALSE) { CbusMidMscMsgSubCmdSend(MHL_MSC_MSG_RCP, 0x80 | eRcpCmd); //key release } } #endif } //------------------------------------------------------------------------------ // Function: MHL_VbusCtrl // Description: Turn on or off VBUS. // Parameters: vbusEn - 1-Enable; 0 - Disable // Returns: TRUE //------------------------------------------------------------------------------ BOOL MHL_VbusCtrl(BOOL vbusEn) { BOOL success = TRUE; sysset_VbusEnable(vbusEn);// 131 do not have Vbus Enable pin , this function have no function ! return(success); } //------------------------------------------------------------------------------ // Function: MHL_VbusToggle // Description: MHL_VbusToggle // Parameters: null // Returns: nuu //------------------------------------------------------------------------------ void MHL_VbusToggle(void) { sysset_VbusToggle(); } //------------------------------------------------------------------------------ // Function: MHL_CD_SENSE_SEL // Description: check CD_SENSE_SEL value // Parameters: // Returns: CD_SENSE_SEL //------------------------------------------------------------------------------ BOOL MHL_CD_SENSE_SEL(void) { return(sysset_Get_CD_SENSE_SEL()); } //------------------------------------------------------------------------------ // Function: MHL_ADOPTER_ID_Check // Description: check if device have MHL_ADOPTER_ID // Parameters: // Returns: TRUE - // FALSE - //------------------------------------------------------------------------------ BOOL MHL_ADOPTER_ID_Check(void) { return(HAVE_MHL_ADOPTER_ID); } //for debug void CbusMidPrintChannelInfo(const UINT8 *bFunc, const UINT32 dLine) { UINT8 bStr[100] = ""; char bTemp[10] = ""; UINT8 i=0,j=0; mhldbg("[%s] caller:%s %d\n", __FUNCTION__,bFunc, dLine); mhldbg("statusFlags:%d isPrevPortMHL:%d", pMidCbus->statusFlags, pMidCbus->isPrevPortMHL); mhldbg("\tconnected:%d state:%d activeIndex:%d dev_cap_regs_ready_bit:%d\n", pMidCbus->chState.connected, pMidCbus->chState.state, pMidCbus->chState.activeIndex, pMidCbus->chState.dev_cap_regs_ready_bit); mhldbg("\ttxReq3D:%d txGrtWrt:%d\n", pMidCbus->chState.srcReq3D, pMidCbus->chState.srcGrtWrt); for(i = 0; i< CBUS_MAX_COMMAND_QUEUE;i++) { mhldbg("req[%d] reqStatus:%d command:0x%x offsetData0x%x length:%d\n", i, pMidCbus->chState.request[i].reqStatus, pMidCbus->chState.request[i].command, pMidCbus->chState.request[i].offsetData, pMidCbus->chState.request[i].length); memset(bStr, 0, 100); for(j = 0; j< MHL_MAX_BUFFER_SIZE;j++) { sprintf(bTemp, "0x%x ", pMidCbus->chState.request[i].msgData[j]); strcat(bStr, bTemp); } mhldbg("msg: %s\n",bStr); } }