#include "bsettop_hdmi.h" #include "bsettop.h" #include "bsettop_display_priv.h" #include "bstd.h" #include "bkni.h" #include "bkni_multi.h" #include "bhdm.h" #ifdef HDCPLIB #define BHDM_HAS_SECURITY #if (CONFIG_ENABLE_SCM != 1) #include "bhsm.h" #include "bhsm_keyladder.h" #include "bhdcplib_keyloader.h" #endif #include "bhdcplib.h" #endif #include "bhdm_edid.h" #include "bvdc.h" #include "gist.h" #include "bos_task_priorities.h" #if BHDM_CEC_SUPPORT #include "bhdm_cec.h" #endif BDBG_MODULE(bsettop_hdmi); bsettop_hdmi_t s_bsettop_hdmi = NULL; #if BHDM_CEC_SUPPORT /** Summary: HdmiOutput CEC settings **/ typedef struct HdmiOutputCecSettings { bool enabled; /* enable the CEC core */ } HdmiOutputCecSettings; /** Summary: Status returned by HdmiOutput_GetCecStatus **/ typedef struct HdmiOutputCecStatus { uint8_t physicalAddress[2]; uint8_t logicalAddress; /* Until logical address is obtained by Nexus, the CEC Send/Receive functions cannot be used. 0xFF means no address. */ bool messageReceived; /* If true, call HdmiOutput_ReceiveCecMessage to receive a message. */ bool messageSendPending; /* If true, you must wait before calling HdmiOutput_SendCecMessage again. */ } HdmiOutputCecStatus; typedef enum HdmiOutputLogicalAddrSearch { HdmiOutputLogicalAddrSearch_eInit, HdmiOutputLogicalAddrSearch_eNext, HdmiOutputLogicalAddrSearch_eReady } HdmiOutputLogicalAddrSearch; /** Summary: Holds data of CEC message to be transmitted or received message **/ typedef struct HdmiOutputCecMessageData { uint8_t initiatorAddr ; uint8_t destinationAddr ; uint8_t messageBuffer[16] ; uint8_t messageLength ; } HdmiOutputCecMessageData; static uint8_t g_logicalAddrArray[] = { BAVC_HDMI_CEC_StbDevices_eSTB1, BAVC_HDMI_CEC_StbDevices_eSTB2, BAVC_HDMI_CEC_StbDevices_eSTB3, BAVC_HDMI_CEC_StbDevices_eSTB4, BAVC_HDMI_CEC_StbDevices_eFreeUse, BAVC_HDMI_CEC_AllDevices_eUnRegistered }; static HdmiOutputCecSettings g_cecSettings; static HdmiOutputCecStatus g_cecStatus; BERR_Code HdmiOutput_GetCecStatus( bsettop_hdmi_t hdmiOutput, HdmiOutputCecStatus *pStatus ); BERR_Code HdmiOutput_SendCecMessage( bsettop_hdmi_t hdmiOutput, const HdmiOutputCecMessageData *pXmitCecMessage); #endif /* Global Types */ typedef enum HdmiOutputState { HdmiOutputState_eDisconnected, HdmiOutputState_eConnected, HdmiOutputState_ePoweredDown, HdmiOutputState_eMax } HdmiOutputState; #define HDMI_STK_SIZE 1024 struct bsettop_hdmi { bool done; bool bDspFmtValid; bdisplay_t display; BHDM_Handle hHDMI; BAVC_MatrixCoefficients hdmiMatrixCoef; BHDM_Settings hdmiSettings; BKNI_EventHandle hdmEvent; #if BHDM_CEC_SUPPORT BKNI_EventHandle cecEvent; HdmiOutputCecSettings cecSettings; HdmiOutputCecStatus cecStatus; HdmiOutputLogicalAddrSearch searchState; unsigned logAddrSearchIndex; #if 0 unsigned int hdmi_cec_stack[HDMI_STK_SIZE]; #endif bool av_mute; uint8_t initiatorAddr; uint8_t destinationAddr; uint8_t physicalAddress[2]; #endif b_task_t h_hdmi_task; unsigned int hdmi_stack[HDMI_STK_SIZE]; int maxEdidRetries; BI2C_ChannelHandle i2cChannelHandle; BREG_I2C_Handle i2cRegHandle; baudio_decode_t audio_decode; BAVC_Audio_Info audioInfo; HdmiOutputState lastState; HdmiOutputState newState; #ifdef HDCPLIB BHDCPlib_State hdcpState; BHDCPlib_Configuration hdcpConfig; BHDCPlib_Dependencies hdcpDependencies; BHDCPlib_Handle hHDCPlib; #if (CONFIG_ENABLE_SCM!=1) BHSM_Handle hHsm; #endif BKNI_EventHandle hHDCPRiEvent; BKNI_EventHandle hHDCPRjEvent; BHDCPlib_HdcpError hdcpError; #endif bool transmitEncrypted; /* If true, transmission will be encrypted once authenticated */ bool pjCheckEnabled; /* If true, the HDCP Pj key will be checked */ bool checkHDCP; bool hdcpStarted; bool native; /* to use native audio mode for dolby digital bit stream test */ bsettop_hdcp_authentication_cb_t hdcp_authentication_cb; /* hdcp check callback */ }; BFMT_AspectRatio bsettop_hdmi_check_aspect_ratio(bsettop_hdmi_t h_hdmi) { bdisplay_t display; bdisplay_settings display_settings; BDBG_ASSERT(h_hdmi); BDBG_ASSERT(h_hdmi->display); display = h_hdmi->display; bdisplay_get(display,&display_settings); switch (display_settings.format) { case bdisplay_format_auto: case bdisplay_format_720p: case bdisplay_format_1080i: case bdisplay_format_1080p24: case bdisplay_format_1080p30: return BFMT_AspectRatio_e16_9; default: break; } return BFMT_AspectRatio_e4_3; } static BFMT_AspectRatio bsettop_hdmi_auto_aspect_ratio(bsettop_hdmi_t h_hdmi, BFMT_VideoFmt eFmt) { bdisplay_t display; uint8_t native; BDBG_ASSERT(h_hdmi); BDBG_ASSERT(h_hdmi->display); display = h_hdmi->display; switch (eFmt) { case BFMT_VideoFmt_e1080i: case BFMT_VideoFmt_e720p: return BFMT_AspectRatio_e16_9; case BFMT_VideoFmt_eNTSC: if (BERR_SUCCESS == BHDM_EDID_CheckRxHdmiVideoSupport( h_hdmi->hHDMI, 720, 480, BAVC_ScanType_eInterlaced, BAVC_FrameRateCode_e59_94, BFMT_AspectRatio_e16_9, &native)) { return BFMT_AspectRatio_e16_9; } else if (BERR_SUCCESS == BHDM_EDID_CheckRxHdmiVideoSupport( h_hdmi->hHDMI, 720, 480, BAVC_ScanType_eInterlaced, BAVC_FrameRateCode_e60, BFMT_AspectRatio_e16_9, &native)) { return BFMT_AspectRatio_e16_9; } else { return BFMT_AspectRatio_e4_3; } case BFMT_VideoFmt_e480p: if (BERR_SUCCESS == BHDM_EDID_CheckRxHdmiVideoSupport( h_hdmi->hHDMI, 720, 480, BAVC_ScanType_eProgressive, BAVC_FrameRateCode_e59_94, BFMT_AspectRatio_e16_9, &native)) { return BFMT_AspectRatio_e16_9; } else if (BERR_SUCCESS == BHDM_EDID_CheckRxHdmiVideoSupport( h_hdmi->hHDMI, 720, 480, BAVC_ScanType_eProgressive, BAVC_FrameRateCode_e60, BFMT_AspectRatio_e16_9, &native)) { return BFMT_AspectRatio_e16_9; } else { return BFMT_AspectRatio_e4_3; } default: return BFMT_AspectRatio_e16_9; } } static void bsettop_hdmi_set_display_format(bsettop_hdmi_t h_hdmi) { bdisplay_t display; bdisplay_settings display_settings; BFMT_AspectRatio asp_r_480i, asp_r_480p; BDBG_ASSERT(h_hdmi); BDBG_ASSERT(h_hdmi->display); display = h_hdmi->display; asp_r_480i = bsettop_hdmi_auto_aspect_ratio(h_hdmi, BFMT_VideoFmt_eNTSC); asp_r_480p = bsettop_hdmi_auto_aspect_ratio(h_hdmi, BFMT_VideoFmt_e480p); bdisplay_record_hdmi_auto_aspect_ratio(display, (uint32_t) asp_r_480i, (uint32_t) asp_r_480p); if (h_hdmi->bDspFmtValid) { bdisplay_get(display,&display_settings); bdisplay_set(display,&display_settings); } } void bsettop_hdmi_mark_dsp_fmt_valid(bsettop_hdmi_t h_hdmi) { BDBG_ASSERT(h_hdmi); h_hdmi->bDspFmtValid = true; } bool bsettop_hdmi_get_native_audio_mode(void) { if (s_bsettop_hdmi) return s_bsettop_hdmi->native; else { return false; } } BERR_Code bsettop_hdmi_set_native_audio_mode(bool native) { if (s_bsettop_hdmi) { s_bsettop_hdmi->native = native ? true : false; return BERR_SUCCESS; } else { return BERR_NOT_INITIALIZED; } } BERR_Code bsettop_hdmi_p_set_native_audio_mode(bsettop_hdmi_t h_hdmi, bool native) { BERR_Code rc = BERR_SUCCESS; BHDM_Settings st; rc = BHDM_GetDefaultSettings(&st); if (native) { /* overwrite default for using native mode? */ /**** AUDIO Info Frame Structure *****/ h_hdmi->hdmiSettings.stAudioInfoFrame.ChannelCount = BAVC_HDMI_AudioInfoFrame_ChannelCount_eReferToStreamHeader; /* TODO how to overwrite this value? */ //h_hdmi->hdmiSettings.stAudioInfoFrame.SpeakerAllocation = BHDM_ChannelAllocation_eStereo; } else { h_hdmi->hdmiSettings.stAudioInfoFrame.ChannelCount = BAVC_HDMI_AudioInfoFrame_ChannelCount_e2Channels; } return rc; } #if BHDM_CEC_SUPPORT #define CEC_SEND_MSG_DELAY 5000 /* send CEC command */ BERR_Code bsettop_hdmi_cec_cmd(int cecCmd, int destinationAddr) { BERR_Code errCode = BERR_SUCCESS; static HdmiOutputCecMessageData msgData; BDBG_MSG(("%s: cmd=0x%02x", __func__, cecCmd)); bsettop_hdmi_t h_hdmi = s_bsettop_hdmi; if (!h_hdmi) { return BERR_NOT_INITIALIZED; } HdmiOutput_GetCecStatus(h_hdmi, &g_cecStatus); if (0xff == g_cecStatus.logicalAddress ) { return BERR_NOT_INITIALIZED; } /* default for one byte command */ msgData.messageBuffer[0] = cecCmd; msgData.messageLength = 1; msgData.initiatorAddr = destinationAddr; //msgData.destinationAddr = 0xF; /* broadcast */ msgData.destinationAddr = h_hdmi->initiatorAddr; /* target to sender */ switch (cecCmd) { case CEC_CMD_REQUEST_ACTIVE_SOURCE: BDBG_MSG(("send CEC_CMD_REQUEST_ACTIVE_SOURCE cmd")); break; case CEC_CMD_ACTIVE_SOURCE: BDBG_MSG(("send CEC_CMD_ACTIVE_SOURCE cmd")); //msgData.messageBuffer[1] = h_hdmi->cecStatus.physicalAddress[0]; //msgData.messageBuffer[2] = h_hdmi->cecStatus.physicalAddress[1]; msgData.messageBuffer[1] = h_hdmi->physicalAddress[0]; msgData.messageBuffer[2] = h_hdmi->physicalAddress[1]; msgData.messageLength = 3; break; case CEC_CMD_INACTIVE_SOURCE: BDBG_MSG(("send CEC_CMD_INACTIVE_SOURCE cmd")); //msgData.messageBuffer[1] = h_hdmi->cecStatus.physicalAddress[0]; //msgData.messageBuffer[2] = h_hdmi->cecStatus.physicalAddress[1]; msgData.messageBuffer[1] = h_hdmi->physicalAddress[0]; msgData.messageBuffer[2] = h_hdmi->physicalAddress[1]; msgData.messageLength = 3; break; case CEC_CMD_IMAGE_VIEW_ON: BDBG_MSG(("send CEC_CMD_IMAGE_VIEW_ON cmd")); break; case CEC_CMD_TEXT_VIEW_ON: BDBG_MSG(("send CEC_CMD_TEXT_VIEW_ON cmd")); break; case CEC_CMD_STANDBY: BDBG_MSG(("send CEC_CMD_STANDBY cmd")); break; case CEC_CMD_CEC_VERSION: BDBG_MSG(("send CEC_CMD_CEC_VERSION cmd")); msgData.messageBuffer[1] = 0x05; /* 1.4a ? */ msgData.messageLength = 2; break; case CEC_CMD_REPORT_PHYSICAL_ADDRESS: BDBG_MSG(("send CEC_CMD_REPORT_PHYSICAL_ADDRESS cmd")); BHDM_CEC_ReportPhysicalAddress(h_hdmi->hHDMI); return BERR_SUCCESS; case CEC_CMD_GIVE_DEVICE_VENDOR_ID: BDBG_MSG(("send CEC_CMD_GIVE_DEVICE_VENDOR_ID cmd")); break; case CEC_CMD_DEVICE_VENDOR_ID: BDBG_MSG(("send CEC_CMD_DEVICE_VENDOR_ID cmd")); msgData.messageBuffer[1] = 0x1; msgData.messageBuffer[2] = 0x2; msgData.messageLength = 3; break; case CEC_CMD_GIVE_DEVICE_POWER_STATUS: BDBG_MSG(("send CEC_CMD_GIVE_DEVICE_POWER_STATUS cmd")); break; case CEC_CMD_REPORT_POWER_STATUS: BDBG_MSG(("send CEC_CMD_REPORT_POWER_STATUS cmd")); msgData.messageBuffer[1] = 0; /* power on */ msgData.messageLength = 2; break; case CEC_CMD_GIVE_AUDIO_STATUS: BDBG_MSG(("send CEC_CMD_GIVE_AUDIO_STATUS cmd")); break; case CEC_CMD_REPORT_AUDIO_STATUS: BDBG_MSG(("send CEC_CMD_REPORT_AUDIO_STATUS cmd")); msgData.messageBuffer[1] = h_hdmi->av_mute; msgData.messageLength = 2; break; case CEC_CMD_GET_PHYSICAL_ADDRESS: BDBG_MSG(("send CEC_CMD_GET_PHYSICAL_ADDRESS cmd")); break; default: BDBG_WRN(("unsupport CEC cmd %02x", cecCmd)); return BERR_UNKNOWN; } errCode = HdmiOutput_SendCecMessage(h_hdmi, &msgData); BHDM_CEC_EnableReceive(h_hdmi->hHDMI); //bos_sleep(CEC_SEND_MSG_DELAY); return errCode; } /** Summary: HdmiOutput CEC settings **/ static BERR_Code GetCecLogicalAddress(bsettop_hdmi_t hdmiOutput) { BERR_Code rc; uint8_t addr; switch (hdmiOutput->searchState) { default: case HdmiOutputLogicalAddrSearch_eInit: /* ping first Address */ addr = g_logicalAddrArray[hdmiOutput->logAddrSearchIndex]; BDBG_MSG(("Starting search for CEC Logical Addr: %d...", addr)) ; hdmiOutput->logAddrSearchIndex = 0; hdmiOutput->cecStatus.logicalAddress = BHDM_CONFIG_CEC_UNINITIALIZED_LOGICAL_ADDR; rc = BHDM_CEC_PingLogicalAddr(hdmiOutput->hHDMI, addr); if (rc) { BDBG_ERR(("BHDM_CEC_PingLogicalAddr failed")) ; return rc; } break; case HdmiOutputLogicalAddrSearch_eNext: hdmiOutput->logAddrSearchIndex++; addr = g_logicalAddrArray[hdmiOutput->logAddrSearchIndex]; BDBG_MSG(("Continuing search for CEC Logical Addr: %d...", addr)) ; if (hdmiOutput->logAddrSearchIndex == sizeof(g_logicalAddrArray)/sizeof(g_logicalAddrArray[0]) - 1) { BDBG_MSG(("All CEC Addrs used; device unregistered")) ; /* Update state and fall through */ hdmiOutput->searchState = HdmiOutputLogicalAddrSearch_eReady; } else { rc = BHDM_CEC_PingLogicalAddr(hdmiOutput->hHDMI, addr); if (rc) { BDBG_ERR(("BHDM_CEC_PingLogicalAddr failed")) ; } break; } /* pass through */ case HdmiOutputLogicalAddrSearch_eReady: hdmiOutput->cecStatus.logicalAddress = g_logicalAddrArray[hdmiOutput->logAddrSearchIndex]; BDBG_MSG(("Found CEC Logical Addr: %d", hdmiOutput->cecStatus.logicalAddress)) ; rc = BHDM_CEC_SetMyAddr(hdmiOutput->hHDMI, hdmiOutput->cecStatus.logicalAddress); if (rc) { BDBG_ERR(("BHDM_CEC_SetMyAddr failed")) ; break; } rc = BHDM_CEC_GetMyAddrs(hdmiOutput->hHDMI, hdmiOutput->cecStatus.physicalAddress, &hdmiOutput->cecStatus.logicalAddress); if (rc != BERR_NOT_INITIALIZED) { /* BERR_NOT_INITIALIZED is normal for not connected to CEC compatible device */ if (rc) { BDBG_ERR(("BHDM_CEC_GetMyAddr failed")) ; break; } /* Report Physical Address */ rc = BHDM_CEC_ReportPhysicalAddress(hdmiOutput->hHDMI); if (rc) { BDBG_ERR(("BHDM_CEC_ReportPhysicalAddress failed")) ; break; } /* always enable receive after CEC msg is processed */ rc = BHDM_CEC_EnableReceive(hdmiOutput->hHDMI); if (rc) { BDBG_ERR(("BHDM_CEC_EnableReceive failed")) ; break; } BDBG_MSG(("BHDM_CEC_EnableReceive. ready to receive data")) ; } break; } return rc; } /** Summary: Get CEC settings **/ void HdmiOutput_GetCecSettings( bsettop_hdmi_t hdmiOutput, HdmiOutputCecSettings *pSettings ) { *pSettings = hdmiOutput->cecSettings; } /** Summary: Set CEC settings **/ BERR_Code HdmiOutput_SetCecSettings( bsettop_hdmi_t hdmiOutput, HdmiOutputCecSettings *pSettings ) { BERR_Code rc = 0; rc = BHDM_CEC_Enable(hdmiOutput->hHDMI, pSettings->enabled); if (rc) { BDBG_ERR(("BHDM_CEC_Enable failed")); return rc; } if (pSettings->enabled && (hdmiOutput->cecSettings.enabled != pSettings->enabled || hdmiOutput->cecStatus.logicalAddress == BHDM_CONFIG_CEC_UNINITIALIZED_LOGICAL_ADDR)) { hdmiOutput->searchState = HdmiOutputLogicalAddrSearch_eInit; GetCecLogicalAddress(hdmiOutput); } hdmiOutput->cecSettings = *pSettings; return rc; } /** Summary: Get CEC status **/ BERR_Code HdmiOutput_GetCecStatus( bsettop_hdmi_t hdmiOutput, HdmiOutputCecStatus *pStatus ) { *pStatus = hdmiOutput->cecStatus; return BERR_SUCCESS; } /** Summary: CecCallback **/ void HdmiOutput_P_CecCallback(void *pContext) { //HdmiOutputHandle hdmiOutput = (HdmiOutputHandle)pContext; bsettop_hdmi_t hdmiOutput = (bsettop_hdmi_t)pContext; BAVC_HDMI_CEC_IntMessageType messageType; uint8_t messageAck; uint8_t CECMsgLength; uint8_t EOM; BERR_Code rc; rc = BHDM_CEC_GetMsgInfo(hdmiOutput->hHDMI, &messageType, &messageAck, &CECMsgLength, &EOM); if (rc) { BDBG_ERR(("BHDM_CEC_GetMsgInfo failed")); } else { if (messageType == BAVC_HDMI_CEC_IntMessageType_eTransmit) { if (hdmiOutput->searchState < HdmiOutputLogicalAddrSearch_eReady) { if (!messageAck) { hdmiOutput->searchState = HdmiOutputLogicalAddrSearch_eReady; } else { hdmiOutput->searchState = HdmiOutputLogicalAddrSearch_eNext; } GetCecLogicalAddress(hdmiOutput); } else { hdmiOutput->cecStatus.messageSendPending = false; } } else { hdmiOutput->cecStatus.messageReceived = true; } } //TaskCallback_Fire(hdmiOutput->cecCallback); } /** Summary: Send CEC message **/ BERR_Code HdmiOutput_SendCecMessage( bsettop_hdmi_t hdmiOutput, const HdmiOutputCecMessageData *pXmitCecMessage) { BERR_Code rc = BERR_SUCCESS; rc = BHDM_CEC_XmitMsg(hdmiOutput->hHDMI, pXmitCecMessage->destinationAddr, (uint8_t *)pXmitCecMessage->messageBuffer, pXmitCecMessage->messageLength); /* set Pending if message successfuly sent */ if (!rc) hdmiOutput->cecStatus.messageSendPending = true; return rc; } /** Summary: Receive CEC message **/ BERR_Code HdmiOutput_ReceiveCecMessage( bsettop_hdmi_t hdmiOutput, HdmiOutputCecMessageData *pRecvCecMessage ) { BERR_Code rc = BERR_SUCCESS; BAVC_HDMI_CEC_MessageData stMessageData; hdmiOutput->cecStatus.messageReceived = false; rc = BHDM_CEC_GetReceivedMessage(hdmiOutput->hHDMI, &stMessageData); if (rc) { BDBG_ERR(("Error receiving CEC Msg")) ; return rc; } pRecvCecMessage->initiatorAddr = stMessageData.initiatorAddr; pRecvCecMessage->destinationAddr = stMessageData.destinationAddr; pRecvCecMessage->messageLength = stMessageData.messageLength; if (pRecvCecMessage->messageLength > 0) BKNI_Memcpy(&pRecvCecMessage->messageBuffer, &stMessageData.messageBuffer, (sizeof(uint8_t) * stMessageData.messageLength)); /* remember these values for later use */ hdmiOutput->initiatorAddr = stMessageData.initiatorAddr; hdmiOutput->destinationAddr = stMessageData.destinationAddr; return rc; } void bsettop_handle_cec_event(bsettop_hdmi_t h_hdmi) { static HdmiOutputCecMessageData msgData; BERR_Code rc; uint8_t cecOpCode; BDBG_MSG(("CEC Event received")); HdmiOutput_P_CecCallback(h_hdmi); rc = HdmiOutput_GetCecStatus(h_hdmi, &g_cecStatus); if (0 == g_cecStatus.messageReceived) { /* Tx message */ return; } BDBG_MSG(("CEC RX Event received")); if (BHDM_CONFIG_CEC_UNINITIALIZED_LOGICAL_ADDR == g_cecStatus.logicalAddress) { BDBG_MSG(("not got logical address yet")); return; } rc = HdmiOutput_ReceiveCecMessage(h_hdmi, &msgData); if (rc) { BDBG_ERR(("HdmiOutput_ReceiveCecMessage failed, rc=0x%x", rc)); /* do dump recieved data? */ return; } /* looks like the lenght of ping command from QuantumData 882 is 0 */ if (0 == msgData.messageLength) { BDBG_MSG(("Recevied 0 bytes, ping?")); return; } msgData.destinationAddr = h_hdmi->initiatorAddr; cecOpCode = msgData.messageBuffer[0]; BDBG_MSG(("Recevied CEC message of %d bytes, op=0x%2x, initiator=0x%x, destination=0x%x", msgData.messageLength, cecOpCode, h_hdmi->initiatorAddr, h_hdmi->destinationAddr)); switch (cecOpCode) { case CEC_CMD_ABORT: BDBG_MSG(("======CEC feature about, do nothing")); break; case CEC_CMD_STANDBY: BDBG_MSG(("======HDMI standby")); /* to remove input, AvMute */ h_hdmi->av_mute = true; BHDM_SetAvMute(h_hdmi->hHDMI, true); break; case CEC_CMD_IMAGE_VIEW_ON: BDBG_MSG(("======Image view on")); /* to add input */ h_hdmi->av_mute = false; BHDM_SetAvMute(h_hdmi->hHDMI, false); break; case CEC_CMD_TEXT_VIEW_ON: BDBG_MSG(("======Text view on")); /* to add input */ h_hdmi->av_mute = false; BHDM_SetAvMute(h_hdmi->hHDMI, false); break; case CEC_CMD_GET_PHYSICAL_ADDRESS: BDBG_MSG(("======CEC_CMD_GET_PHYSICAL_ADDRESS received")); bsettop_hdmi_cec_cmd(CEC_CMD_REPORT_PHYSICAL_ADDRESS, msgData.destinationAddr); break; case CEC_CMD_REPORT_PHYSICAL_ADDRESS: BDBG_MSG(("======Physical address = %02x%04x", msgData.messageBuffer[1], msgData.messageBuffer[2])); h_hdmi->physicalAddress[0] = msgData.messageBuffer[1]; h_hdmi->physicalAddress[1] = msgData.messageBuffer[2]; break; case CEC_CMD_GET_CEC_VERSION: BDBG_MSG(("======CEC_CMD_GET_CEC_VERSION received")); bsettop_hdmi_cec_cmd(CEC_CMD_CEC_VERSION, msgData.destinationAddr); break; case CEC_CMD_CEC_VERSION: BDBG_MSG(("======CEC version = %02x", msgData.messageBuffer[1])); break; case CEC_CMD_GIVE_DEVICE_VENDOR_ID: bsettop_hdmi_cec_cmd(CEC_CMD_DEVICE_VENDOR_ID, msgData.destinationAddr); break; case CEC_CMD_DEVICE_VENDOR_ID: BDBG_MSG(("======Device vendor ID = %02x%02x%02x", msgData.messageBuffer[1], msgData.messageBuffer[2], msgData.messageBuffer[3])); break; case CEC_CMD_GIVE_DEVICE_POWER_STATUS: BDBG_MSG(("======CEC_CMD_GIVE_DEVICE_POWER_STATUS received")); bsettop_hdmi_cec_cmd(CEC_CMD_REPORT_POWER_STATUS, msgData.destinationAddr); break; case CEC_CMD_REPORT_POWER_STATUS: BDBG_MSG(("======Device power status= %s", 0 == msgData.messageBuffer[1] ? "on" : 1 == msgData.messageBuffer[1] ? "off" : 2 == msgData.messageBuffer[1] ? "standby to on" : "On to standby")); break; case CEC_CMD_GIVE_AUDIO_STATUS: bsettop_hdmi_cec_cmd(CEC_CMD_REPORT_AUDIO_STATUS, msgData.destinationAddr); break; case CEC_CMD_REPORT_AUDIO_STATUS: BDBG_MSG(("======Device power status= %s", 0 == msgData.messageBuffer[1] ? "on" : 1 == msgData.messageBuffer[1] ? "off" : 2 == msgData.messageBuffer[1] ? "standby to on" : "On to standby")); break; case CEC_CMD_REQUEST_ACTIVE_SOURCE: bsettop_hdmi_cec_cmd(CEC_CMD_ACTIVE_SOURCE, msgData.destinationAddr); break; case CEC_CMD_DEVICE_VENDOR_CMD: BDBG_MSG(("======CEC_CMD_DEVICE_VENDOR_CMD received")); break; default: BDBG_WRN(("OpCode %02x not supported", cecOpCode)); msgData.messageBuffer[0] = 0; /* abort */ msgData.messageBuffer[1] = cecOpCode; msgData.messageBuffer[2] = 0; /* unsupported */ msgData.messageLength = 3; rc = HdmiOutput_SendCecMessage(h_hdmi, &msgData); break; } } #else BERR_Code bsettop_hdmi_cec_cmd(int cecCmd, int destinationAddr) { return BERR_SUCCESS; } #endif /** Summary: get hdmi state **/ HdmiOutputState bsettop_hdmi_get_state(bsettop_hdmi_t h_hdmi,bool double_check) { BERR_Code errCode; uint8_t rxSense=0, attached=1; BHDM_RxDeviceAttached(h_hdmi->hHDMI, &attached); if (attached) { #ifdef HDCPLIB /* as long as encryption is enabled; no need to check for receiver sense */ if (h_hdmi->hdcpState == BHDCPlib_State_eEncryptionEnabled) return HdmiOutputState_eConnected; #endif errCode = BHDM_GetReceiverSense(h_hdmi->hHDMI, &rxSense); BDBG_MSG(("BHDM_GetReceiverSense rxSense = 0x%02x",rxSense)); if ( errCode == BERR_SUCCESS ) { if ( rxSense ) { return HdmiOutputState_eConnected; } else if (double_check) { bos_sleep(50); /* Double check the receiver sense */ errCode = BHDM_GetReceiverSense(h_hdmi->hHDMI, &rxSense); BDBG_ERR(("BHDM_GetReceiverSense rxSense = 0x%02x",rxSense)); if ( rxSense ) { return HdmiOutputState_eConnected; } else { return HdmiOutputState_ePoweredDown; } } else { return HdmiOutputState_ePoweredDown; } } } /* device disconnected*/ return HdmiOutputState_eDisconnected; } /** Summary: handle updating hdcp state **/ #ifdef HDCPLIB static void bsettop_update_hdcp_state(bsettop_hdmi_t h_hdmi) { bool ready; BHDCPlib_Status hdcpStatus; BHDCPlib_GetHdcpStatus(h_hdmi->hHDCPlib, &hdcpStatus); ready = BHDCPlib_LinkReadyForEncryption(h_hdmi->hHDCPlib); /* Save last HDCP error */ h_hdmi->hdcpError = hdcpStatus.eHdcpError; BDBG_MSG(("Updating HDCP State from %d -> %d", h_hdmi->hdcpState, hdcpStatus.eAuthenticationState)); if ( hdcpStatus.eAuthenticationState != h_hdmi->hdcpState ) { h_hdmi->hdcpState = hdcpStatus.eAuthenticationState; } if ( ready ) { BDBG_MSG(("Authentication complete")); if ( h_hdmi->transmitEncrypted ) { BERR_Code errCode; BDBG_WRN(("Enabling Encryption")); errCode = BHDCPlib_TransmitEncrypted(h_hdmi->hHDCPlib); if ( errCode ) { errCode = BERR_TRACE(errCode); } if (h_hdmi->hdcp_authentication_cb) { /* tell the application to enable video/audio/CC on HDMI port after authencation successful */ h_hdmi->hdcp_authentication_cb(true); } } } } /** Summary: Restart hdcp **/ static bresult bsettop_hdmi_restart_hdcp(bsettop_hdmi_t h_hdmi) { BERR_Code rc; if (h_hdmi->hdcpStarted) { BHDCPlib_DisableAuthentication(h_hdmi->hHDCPlib); h_hdmi->hdcpStarted = false; } /* Reset Auth State */ rc = BHDCPlib_StartAuthentication(h_hdmi->hHDCPlib); if ( rc ) { return BERR_TRACE(rc); } h_hdmi->hdcpStarted = true; h_hdmi->checkHDCP = true; bsettop_update_hdcp_state(h_hdmi); return BERR_SUCCESS; } #else /* HDCPLIB */ static void bsettop_update_hdcp_state(bsettop_hdmi_t h_hdmi) { } static bresult bsettop_hdmi_restart_hdcp(bsettop_hdmi_t h_hdmi) { return b_ok; } #endif /* HDCPLIB */ static bool g_RGB_verification = false; bool bsettop_hdmi_get_RGB_output(void) { return g_RGB_verification; } /** Summary: set RGB output for HDMI verification sake. **/ bresult bsettop_hdmi_set_RGB_output(bool bRGB) { g_RGB_verification = bRGB; return b_ok; } /** Summary: check if the video format is supported by the TV connected **/ bool bsettop_hdmi_p_is_video_fmt_supported(bsettop_hdmi_t h_hdmi, BFMT_VideoFmt eFmt) { BERR_Code rc; uint8_t supported; rc = BHDM_EDID_VideoFmtSupported(h_hdmi->hHDMI, eFmt, &supported); if (BERR_SUCCESS == rc) return (bool)supported ? true : false; /* if don't get video format, then assume it is available and try and error */ if (BHDM_EDID_VIDEO_FORMATS_UNAVAILABLE == rc) return true; return false; } static BFMT_VideoFmt s_display_formate_to_bfmt[] = { BFMT_VideoFmt_eMaxCount, BFMT_VideoFmt_e1080i, BFMT_VideoFmt_e720p, BFMT_VideoFmt_eNTSC, BFMT_VideoFmt_e480p, BFMT_VideoFmt_e1080p, BFMT_VideoFmt_e1080p_24Hz, BFMT_VideoFmt_e1080p_30Hz }; bool bsettop_hdmi_is_video_fmt_supported(bsettop_display_format_t fmt) { if (fmt == bdisplay_format_auto) return true; if (fmt >= bdisplay_format_max) { BDBG_ERR(("%s: Invalid format",__func__)); return false; } if (s_bsettop_hdmi) return bsettop_hdmi_p_is_video_fmt_supported(s_bsettop_hdmi, s_display_formate_to_bfmt[fmt]); else { BDBG_ERR(("%s: hdmi not initialized",__func__)); return false; } } /** Summary: Handle connect for VDC purposes **/ static bresult bsettop_hdmi_vdc_connect(bsettop_hdmi_t h_hdmi) { BERR_Code rc = 0; #if HAS_HDMI uint8_t ucRxAttached; BFMT_VideoFmt eFmt; bdisplay_t display; BDBG_ASSERT(h_hdmi); BDBG_ASSERT(h_hdmi->display); BHDM_OutputFormat eOutputFormat = BHDM_OutputFormat_eHDMIMode; BHDM_OutputPort eOutputPort = BHDM_OutputPort_eHDMI; static BHDM_EDID_RxVendorSpecificDB RxVSDB; bool bHdmiDevice; BAVC_HDMI_AudioInfoFrame audioInfoFrame; display = h_hdmi->display; /* Verify there is an attached Receiver Device */ rc = BHDM_RxDeviceAttached(h_hdmi->hHDMI, &ucRxAttached); if (ucRxAttached == 0) { BDBG_ERR(("No DVI RX device is attached.")); return berr_not_supported; } BDBG_ERR(("++++++++++++++++++++++++++++++++")); BDBG_ERR(("+ DVI RX device is attached! +")); BDBG_ERR(("++++++++++++++++++++++++++++++++")); BVDC_Display_GetVideoFormat( display->disp[eBDISPLAY_HDMI].hDisplay, &eFmt ); rc = BHDM_EDID_IsRxDeviceHdmi(h_hdmi->hHDMI, &RxVSDB, &bHdmiDevice); if (BERR_SUCCESS != rc) { BDBG_ERR(("%s BHDM_EDID_IsRxDeviceHdmi failed %x",__func__,rc)); } else { if (!bHdmiDevice) { eOutputFormat = BHDM_OutputFormat_eDVIMode; eOutputPort = BHDM_OutputPort_eDVI; } } rc = BHDM_EDID_GetSupportedColorimetry(h_hdmi->hHDMI, eOutputFormat, display->hdmiFmt,&(h_hdmi->hdmiMatrixCoef)); if (rc != BERR_SUCCESS) { BDBG_ERR(("%s:%d BHDM_EDID_GetSupportedColorimetry failed %d",__FUNCTION__,__LINE__,rc)); } //BVDC_Display_GetHdmiConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, BVDC_Hdmi_0, &(h_hdmi->hdmiMatrixCoef)); h_hdmi->hdmiSettings.eInputVideoFmt = eFmt; h_hdmi->hdmiSettings.eOutputPort = eOutputPort; h_hdmi->hdmiSettings.eColorimetry = h_hdmi->hdmiMatrixCoef; BDBG_MSG(("%s: RGB output=%d",__func__, g_RGB_verification)); if (g_RGB_verification) { h_hdmi->hdmiMatrixCoef = BAVC_MatrixCoefficients_eUnknown; BVDC_Display_SetHdmiConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, BVDC_Hdmi_0,h_hdmi->hdmiMatrixCoef); rc = BVDC_ApplyChanges(display->hVdc); h_hdmi->hdmiSettings.eColorimetry = BAVC_MatrixCoefficients_eHdmi_RGB; h_hdmi->hdmiMatrixCoef = BAVC_MatrixCoefficients_eHdmi_RGB; } BVDC_Display_SetHdmiConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, BVDC_Hdmi_0,h_hdmi->hdmiMatrixCoef); rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("%s:%d BVDC_ApplyChanges failed %d",__FUNCTION__,__LINE__,rc)); } /* check if need bypass to use native dolby audio, is there a need to change HDMI PI code also? */ /* test it, but may need test streams */ //h_hdmi->native = true; bsettop_hdmi_p_set_native_audio_mode(h_hdmi, h_hdmi->native); h_hdmi->hdmiSettings.eOutputFormat = eOutputFormat; //h_hdmi->hdmiSettings.eAudioBits = BAVC_AudioBits_e24; //h_hdmi->hdmiSettings.eTimebase = BAVC_Timebase_e0; //h_hdmi->hdmiSettings.stColorDepth.eBitsPerPixel = BAVC_HDMI_BitsPerPixel_e24bit; //h_hdmi->hdmiSettings.eAudioFormat = BAVC_AudioFormat_ePCM;; h_hdmi->hdmiSettings.eAspectRatio = bsettop_hdmi_check_aspect_ratio(h_hdmi); BHDM_EnableDisplay(h_hdmi->hHDMI, &h_hdmi->hdmiSettings); #if 0 rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("%s:%d BVDC_ApplyChanges failed %d",__FUNCTION__,__LINE__,rc)); } #endif /* audio */ rc = BHDM_GetAudioInfoFramePacket(h_hdmi->hHDMI, &audioInfoFrame); if (rc) { BDBG_WRN(("BHDM_GetAudioInfoFramePacket failed %d", rc)); } else { audioInfoFrame.ChannelCount = BAVC_HDMI_AudioInfoFrame_ChannelCount_e2Channels; } audioInfoFrame.SpeakerAllocation = BHDM_ChannelAllocation_eStereo; audioInfoFrame.DownMixInhibit = 0; /* default */ audioInfoFrame.LevelShift = 0; /* default */ rc = BHDM_SetAudioInfoFramePacket(h_hdmi->hHDMI, &audioInfoFrame); if ( rc ) { BDBG_WRN(("BHDM_SetAudioInfoFramePacket failed %d", rc)); } h_hdmi->hdmiSettings.eAudioSamplingRate = BAVC_AudioSamplingRate_e48k; h_hdmi->audioInfo.eAudioSamplingRate = BAVC_AudioSamplingRate_e48k; h_hdmi->hdmiSettings.eAudioBits = BAVC_AudioBits_e24; rc = BHDM_EnableDisplay(h_hdmi->hHDMI, &h_hdmi->hdmiSettings); rc = bsettop_hdmi_restart_hdcp(h_hdmi); if (rc != BERR_SUCCESS) { BDBG_ERR(("%s:%d bsettop_hdmi_restart_hdcp failed %d",__FUNCTION__,__LINE__,rc)); } if (h_hdmi->hdcpStarted && h_hdmi->checkHDCP && h_hdmi->hdcp_authentication_cb) { /* tell the application to disable video/audio/CC on HDMI port */ h_hdmi->hdcp_authentication_cb(false); } h_hdmi->lastState = bsettop_hdmi_get_state(h_hdmi, true); #endif return rc; } /** Summary: Handle hdmi events **/ static void bsettop_handle_hdmi_event(bsettop_hdmi_t h_hdmi) { #if HAS_HDMI BVDC_Display_DvoSettings dvoSettings; BERR_Code rc; BFMT_VideoFmt eFmt; BAVC_MatrixCoefficients hdmiOutputCoef; bdisplay_t display; display = h_hdmi->display; h_hdmi->newState = bsettop_hdmi_get_state(h_hdmi,true); BDBG_WRN(("%s:%d newState = %d, lastState = %d", __FUNCTION__,__LINE__,h_hdmi->newState,h_hdmi->lastState)); if (h_hdmi->newState == h_hdmi->lastState) { BDBG_WRN(("%s:%d newState = %d == lastState = %d", __FUNCTION__,__LINE__,h_hdmi->newState,h_hdmi->lastState)); return; } b_lock_vdc(); /* Check transitions */ if ( h_hdmi->lastState == HdmiOutputState_eConnected ) { BDBG_WRN(("%s:%d Pervious state HdmiOutputState_eConnected", __FUNCTION__,__LINE__)); /* Connected -> disconnected or Connected -> powered down. Disable output and fire callback */ BHDM_DisableDisplay(h_hdmi->hHDMI); #ifdef HDCPLIB if (h_hdmi->hdcpStarted) { BHDCPlib_DisableAuthentication(h_hdmi->hHDCPlib); h_hdmi->hdcpStarted = false; } #endif /* HDCPLIB */ BVDC_Display_GetVideoFormat(display->disp[eBDISPLAY_HDMI].hDisplay, &eFmt ); if (BHDM_EDID_GetSupportedColorimetry(h_hdmi->hHDMI, BHDM_OutputFormat_eHDMIMode, display->hdmiFmt,&(hdmiOutputCoef)) == BERR_SUCCESS) { BDBG_WRN(("%s:%d", __FUNCTION__,__LINE__)); hdmiOutputCoef = BAVC_MatrixCoefficients_eUnknown; BVDC_Display_SetHdmiConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, BVDC_Hdmi_0,hdmiOutputCoef); dvoSettings.stSpreadSpectrum.bEnable = false; BVDC_Display_GetDvoConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, &dvoSettings); rc = BVDC_Display_SetDvoConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, &dvoSettings); //BHDM_DisableDisplay(h_hdmi->hHDMI); rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_WRN(("%s:%d BVDC_ApplyChanges failed %d", __FUNCTION__,__LINE__,rc)); } } #if BHDM_CEC_SUPPORT h_hdmi->cecStatus.physicalAddress[0] = 0xFF; h_hdmi->cecStatus.physicalAddress[1] = 0xFF; h_hdmi->cecStatus.logicalAddress = BHDM_CONFIG_CEC_UNINITIALIZED_LOGICAL_ADDR; HdmiOutput_GetCecSettings(h_hdmi, &g_cecSettings); g_cecSettings.enabled = false; rc = HdmiOutput_SetCecSettings(h_hdmi, &g_cecSettings); /* clear any pending event */ BKNI_ResetEvent(h_hdmi->cecEvent); #endif } if ( h_hdmi->newState == HdmiOutputState_eConnected ) { unsigned i=0; /* Disconnected -> Connected or Powered down -> connected. Read EDID */ BDBG_WRN(("%s:%d", __FUNCTION__,__LINE__)); do { rc = BHDM_EDID_Initialize(h_hdmi->hHDMI); } while ( rc != BERR_SUCCESS && rc != BHDM_NO_RX_DEVICE && i++ < h_hdmi->maxEdidRetries ); if ( rc == BHDM_NO_RX_DEVICE ) { /* Device was disconnected during retries. Abort */ h_hdmi->lastState = HdmiOutputState_eDisconnected; b_unlock_vdc(); return; } else if ( i >= h_hdmi->maxEdidRetries ) { BDBG_ERR(("Unable to read EDID after %d attempts", i)); /* TODO: Bail out here or continue? -- currently continuing. */ } #if 1 bsettop_hdmi_set_display_format(h_hdmi); bsettop_hdmi_vdc_connect(h_hdmi); #else BHDM_OutputFormat eOutputFormat = BHDM_OutputFormat_eHDMIMode; BHDM_OutputPort eOutputPort = BHDM_OutputPort_eHDMI; static BHDM_EDID_RxVendorSpecificDB RxVSDB; bool bHdmiDevice; rc = BHDM_EDID_IsRxDeviceHdmi(h_hdmi->hHDMI, &RxVSDB, &bHdmiDevice); if (BERR_SUCCESS != rc) { BDBG_ERR(("%s BHDM_EDID_IsRxDeviceHdmi failed %x",__func__,rc)); } else { /* should not support it */ if (!bHdmiDevice) { eOutputFormat = BHDM_OutputFormat_eDVIMode; eOutputPort = BHDM_OutputPort_eDVI; } } BVDC_Display_GetVideoFormat(display->disp[eBDISPLAY_HDMI].hDisplay, &eFmt ); if (BHDM_EDID_GetSupportedColorimetry(h_hdmi->hHDMI, eOutputFormat, display->hdmiFmt,&(hdmiOutputCoef)) == BERR_SUCCESS) { BDBG_WRN(("%s:%d", __FUNCTION__,__LINE__)); BVDC_Display_SetHdmiConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, BVDC_Hdmi_0,hdmiOutputCoef); #if 0 rc = BHDM_EDID_GetSupportedColorimetry(h_hdmi->hHDMI, BHDM_OutputFormat_eHDMIMode, display->hdmiFmt,&(h_hdmi->hdmiMatrixCoef)); if (rc != BERR_SUCCESS) { BDBG_WRN(("%s:%d BHDM_EDID_GetSupportedColorimetry failed %d", __FUNCTION__,__LINE__,rc)); } BVDC_Display_GetHdmiConfiguration(display->disp[eBDISPLAY_HDMI].hDisplay, BVDC_Hdmi_0, &(h_hdmi->hdmiMatrixCoef)); #endif rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_WRN(("%s:%d BVDC_ApplyChanges failed %d", __FUNCTION__,__LINE__,rc)); } } BHDM_GetHdmiSettings(h_hdmi->hHDMI, &(h_hdmi->hdmiSettings)); h_hdmi->hdmiSettings.eInputVideoFmt = eFmt; h_hdmi->hdmiSettings.eOutputPort = eOutputPort; h_hdmi->hdmiSettings.eColorimetry = h_hdmi->hdmiMatrixCoef; h_hdmi->hdmiSettings.eOutputFormat = eOutputFormat; h_hdmi->hdmiSettings.eAspectRatio = bsettop_hdmi_check_aspect_ratio(h_hdmi); rc = BHDM_EnableDisplay(h_hdmi->hHDMI,&(h_hdmi->hdmiSettings)); if (rc != BERR_SUCCESS) { BDBG_WRN(("%s:%d BHDM_EnableDisplay failed %d", __FUNCTION__,__LINE__,rc)); } #endif #if BHDM_CEC_SUPPORT /* clear any pending event */ BKNI_ResetEvent(h_hdmi->cecEvent); HdmiOutput_GetCecSettings(h_hdmi, &g_cecSettings); g_cecSettings.enabled = true; rc = HdmiOutput_SetCecSettings(h_hdmi, &g_cecSettings); if ( rc ) BDBG_ERR(("Unable to enable CEC core")); else { BDBG_WRN(("CEC enabled!")); } //HdmiOutput_P_CecCallback(h_hdmi); #endif #if 0 rc = bsettop_hdmi_restart_hdcp(h_hdmi); if ( rc ) { BDBG_ERR(("Unable to restart HDCP")); } else { BDBG_WRN(("HDCP restarted")); } #endif } else if ( h_hdmi->newState == HdmiOutputState_ePoweredDown ) { /* Disconnected -> powered down - treat as no event */ BDBG_WRN(("Receiver powered down, no hotplug event.")); } b_unlock_vdc(); h_hdmi->lastState = h_hdmi->newState; #endif } /** Summary: check hdcp state **/ #ifdef HDCPLIB static void bsettop_hdcp_cb(bsettop_hdmi_t h_hdmi) { BHDCPlib_Status hdcpStatus; BERR_Code errCode; BDBG_MSG(("HDCP State Machine Timer")); errCode = BHDCPlib_ProcessAuthentication(h_hdmi->hHDCPlib, &hdcpStatus); if ( errCode ) { /* All failures will eventually wind up here */ errCode = BERR_TRACE(errCode); BDBG_ERR(("HDCP error occurred, aborting authentication")); bsettop_update_hdcp_state(h_hdmi); bsettop_hdmi_restart_hdcp(h_hdmi); return; } bsettop_update_hdcp_state(h_hdmi); if ( hdcpStatus.msRecommendedWaitTime > 0 ) { BDBG_MSG(("Continue check HDCP state - %d\n",hdcpStatus.msRecommendedWaitTime)); } else { BDBG_WRN(("HDCP state machine will stop now.\n")); h_hdmi->checkHDCP = false; } } #else /* HDCPLIB */ static void bsettop_hdcp_cb(bsettop_hdmi_t h_hdmi) { } #endif /* HDCPLIB */ /** Summary: hdmi task **/ void bsettop_hdmi_task(void *data) { bsettop_hdmi_t h_hdmi = (bsettop_hdmi_t)data; h_hdmi->lastState = HdmiOutputState_eMax; while (!h_hdmi->done) { if (BKNI_WaitForEvent(h_hdmi->hdmEvent, 5) == BERR_SUCCESS) { bsettop_handle_hdmi_event(h_hdmi); } #if BHDM_CEC_SUPPORT if (BKNI_WaitForEvent(h_hdmi->cecEvent, 5) == BERR_SUCCESS) { bsettop_handle_cec_event(h_hdmi); } #endif #ifdef HDCPLIB if (BKNI_WaitForEvent(h_hdmi->hHDCPRiEvent, 5) == BERR_SUCCESS) { BHDCPlib_Event event = {BHDM_EventHDCPRiValue}; BHDCPlib_ProcessEvent(h_hdmi->hHDCPlib, &event); bsettop_update_hdcp_state(h_hdmi); } if (BKNI_WaitForEvent(h_hdmi->hHDCPRjEvent, 5) == BERR_SUCCESS) { BHDCPlib_Event event = {BHDM_EventHDCPPjValue}; BHDCPlib_ProcessEvent(h_hdmi->hHDCPlib, &event); bsettop_update_hdcp_state(h_hdmi); } if (h_hdmi->checkHDCP) { bsettop_hdcp_cb(h_hdmi); } #endif /* HDCPLIB */ } } /** Summary: Display rate changed callback. **/ void bsettop_display_rate_change_cb(bdisplay_t display, /* display contect handle */ void *data_ptr, /* rate_change_data* */ void *cbData /* BAVC_VdcDisplay_Info* */ ) { bsettop_hdmi_t h_hdmi = (bsettop_hdmi_t)data_ptr; BAVC_VdcDisplay_Info *pDisplayInfo = (BAVC_VdcDisplay_Info*)cbData; BDBG_ASSERT(display); if (pDisplayInfo) { BDBG_WRN(("%s: refreshrate=%d, clkrate=%d.\n", __func__, pDisplayInfo->ulVertRefreshRate, pDisplayInfo->ulPixelClkRate)); BHDM_AudioVideoRateChangeCB_isr(h_hdmi->hHDMI,BHDM_Callback_Type_eVideoChange,pDisplayInfo); } else { BHDM_SetAvMute(h_hdmi->hHDMI, true); BHDM_DisableDisplay(h_hdmi->hHDMI); bos_sleep(100); bsettop_hdmi_vdc_connect(h_hdmi); BHDM_SetAvMute(h_hdmi->hHDMI, false); } } static BAVC_AudioSamplingRate bsettop_audio_get_sr(unsigned sampleRate) { switch (sampleRate) { case 32000: return BAVC_AudioSamplingRate_e32k; /* 32K Sample rate */ case 44100: return BAVC_AudioSamplingRate_e44_1k; /* 44.1K Sample rate */ case 48000: return BAVC_AudioSamplingRate_e48k; /* 48K Sample rate */ case 96000: return BAVC_AudioSamplingRate_e96k; /* 96K Sample rate */ case 16000: return BAVC_AudioSamplingRate_e16k; /* 16K Sample rate */ case 22050: return BAVC_AudioSamplingRate_e22_05k; /* 22.05K Sample rate */ case 24000: return BAVC_AudioSamplingRate_e24k; /* 24K Sample rate */ case 64000: return BAVC_AudioSamplingRate_e64k; /* 64K Sample rate */ case 88200: return BAVC_AudioSamplingRate_e88_2k; /* 88.2K Sample rate */ case 128000: return BAVC_AudioSamplingRate_e128k; /* 128K Sample rate */ case 176400: return BAVC_AudioSamplingRate_e176_4k; /* 176.4K Sample rate */ case 192000: return BAVC_AudioSamplingRate_e192k; /* 192K Sample rate */ case 8000: return BAVC_AudioSamplingRate_e8k; /* 8K Sample rate */ case 12000: return BAVC_AudioSamplingRate_e12k; /* 12K Sample rate */ case 11025: return BAVC_AudioSamplingRate_e11_025k; /* 11.025K Sample rate */ default: return BAVC_AudioSamplingRate_e48k; } } /** Summary: Audio rate changed callback. **/ void bsettop_audio_rate_change_cb (baudio_decode_t audio, /* audio decode contect handle */ void *data_ptr, /* rate_change_data */ void *cbData /* BRAP_DSPCHN_SampleRateChangeInfo* */ ) { bsettop_hdmi_t h_hdmi = (bsettop_hdmi_t)data_ptr; BSTD_UNUSED(h_hdmi); BAVC_AudioSamplingRate sr = bsettop_audio_get_sr((unsigned)cbData); BDBG_WRN(("%s, new rate=%d, old rate=%d",__func__, sr, h_hdmi->audioInfo.eAudioSamplingRate)); if (h_hdmi->audioInfo.eAudioSamplingRate != sr) { h_hdmi->audioInfo.eAudioSamplingRate = sr; BHDM_AudioVideoRateChangeCB_isr(h_hdmi->hHDMI,BHDM_Callback_Type_eAudioChange,&(h_hdmi->audioInfo)); } BDBG_ERR(("%s",__func__)); } /** Summary: Allocate and initialize hdmi resources. **/ bresult bsettop_hdmi_open(bsettop_hdmi_t *h_hdmi, bdisplay_t display, /* display on which the graphics are displayed */ baudio_decode_t audio_decode, bsettop_hdcp_authentication_cb_t hdcp_authentication_cb /* pointer to a callback function to let hdcp ahthentication to call the app */ ) { BERR_Code rc = 0; #if HAS_HDMI b_task_params task_params; BI2C_ChannelSettings defChnSettings; //BHDM_ColorDepth_Settings colorDepthSettings; bdisplay_settings display_settings; baudio_decode_config audio_config; #ifdef HDCPLIB BHDCPlib_Dependencies *pDefaultDependencies; BHDCPlib_Configuration *pHdcpConfiguration; #if (CONFIG_ENABLE_SCM != 1) BHSM_Settings hsmSettings; #endif #endif BAVC_VdcDisplay_Info DisplayInfo; unsigned int flags; BDBG_ASSERT(display); BDBG_ASSERT(audio_decode); *h_hdmi = (bsettop_hdmi_t)BKNI_Malloc(sizeof(struct bsettop_hdmi)); if (!(*h_hdmi)) return berr_out_of_memory; #if 0 BDBG_SetModuleLevel("BHDM_CEC", BDBG_eMsg); BDBG_SetModuleLevel("BHDM_CEC_PRIV", BDBG_eMsg); BDBG_SetModuleLevel("BHDM_EDID", BDBG_eMsg); BDBG_SetModuleLevel("BHSM",BDBG_eTrace); BDBG_SetModuleLevel("BHDM",BDBG_eTrace); BDBG_SetModuleLevel("BHDM_HDCP",BDBG_eTrace); BDBG_SetModuleLevel("BHDM_EDID",BDBG_eMsg); #endif BKNI_Memset(*h_hdmi,0,sizeof(struct bsettop_hdmi)); #if BHDM_CEC_SUPPORT BKNI_Memset(&g_cecSettings,0,sizeof(g_cecSettings)); BKNI_Memset(&g_cecStatus,0,sizeof(g_cecStatus)); #endif (*h_hdmi)->audio_decode = audio_decode; (*h_hdmi)->display = display; (*h_hdmi)->maxEdidRetries = 3; BI2C_GetChannelDefaultSettings( GetI2C(), 0, &defChnSettings ); defChnSettings.clkRate = BI2C_Clk_eClk100Khz; BI2C_OpenChannel( GetI2C(), &((*h_hdmi)->i2cChannelHandle), 0, &defChnSettings ); BDBG_ASSERT((*h_hdmi)->i2cChannelHandle); BI2C_CreateI2cRegHandle ((*h_hdmi)->i2cChannelHandle, &((*h_hdmi)->i2cRegHandle)); BDBG_ASSERT((*h_hdmi)->i2cRegHandle); BHDM_GetDefaultSettings(&((*h_hdmi)->hdmiSettings)); (*h_hdmi)->hdmiSettings.eOutputFormat = BHDM_OutputFormat_eHDMIMode; (*h_hdmi)->hdmiSettings.eAudioBits = BAVC_AudioBits_e24; (*h_hdmi)->hdmiSettings.eTimebase = BAVC_Timebase_e0; (*h_hdmi)->hdmiSettings.stColorDepth.eBitsPerPixel = BAVC_HDMI_BitsPerPixel_e24bit; (*h_hdmi)->hdmiSettings.eAudioFormat = BAVC_AudioFormat_ePCM;; /*RLQ, new HDMI code requires the timer handler */ //(*h_hdmi)->hdmiSettings.hTMR = GetTMR(); rc = BHDM_Open(&((*h_hdmi)->hHDMI), GetCHP(), GetREG(), GetINT(), (*h_hdmi)->i2cRegHandle, &((*h_hdmi)->hdmiSettings)); BDBG_ASSERT(rc == BERR_SUCCESS); /* get Hot Plug Event Handle */ rc = BHDM_GetEventHandle((*h_hdmi)->hHDMI, BHDM_EventHotPlug, &((*h_hdmi)->hdmEvent)); BDBG_ASSERT(rc == BERR_SUCCESS); #if BHDM_CEC_SUPPORT /* get cec event handle */ rc = BHDM_GetEventHandle((*h_hdmi)->hHDMI, BHDM_EventCEC, &((*h_hdmi)->cecEvent)); BDBG_ASSERT(rc == BERR_SUCCESS); (*h_hdmi)->cecStatus.physicalAddress[0] = 0xFF; (*h_hdmi)->cecStatus.physicalAddress[1] = 0xFF; (*h_hdmi)->cecStatus.logicalAddress = BHDM_CONFIG_CEC_UNINITIALIZED_LOGICAL_ADDR; #endif /* set initial fresh rate and pixel clock in case on a turn on channel is audio only channel and no default info from EDID */ DisplayInfo.ulVertRefreshRate = 5994; DisplayInfo.ulPixelClkRate = 16; flags = bos_enter_critical(); BHDM_AudioVideoRateChangeCB_isr((*h_hdmi)->hHDMI,BHDM_Callback_Type_eVideoChange,&DisplayInfo); bos_exit_critical(flags); task_params.name="HDMI"; task_params.priority = HDMI_PRIORITY; task_params.stack_size = HDMI_STK_SIZE; task_params.stack = (*h_hdmi)->hdmi_stack; bos_start_task(&((*h_hdmi)->h_hdmi_task), &task_params, bsettop_hdmi_task,(*h_hdmi)); BVDC_Display_SetHdmiConfiguration( display->disp[eBDISPLAY_HDMI].hDisplay, BVDC_Hdmi_0, BAVC_MatrixCoefficients_eItu_R_BT_709); /* the changes in BDM module fixed BHDM_SetAvMute */ //colorDepthSettings.eBitsPerPixel = BAVC_HDMI_BitsPerPixel_e24bit; //rc = BHDM_SetColorDepth((*h_hdmi)->hHDMI, &colorDepthSettings); //BDBG_ASSERT(rc == BERR_SUCCESS); rc = BVDC_ApplyChanges(display->hVdc); BDBG_ASSERT(rc == BERR_SUCCESS); #ifdef HDCPLIB #if (CONFIG_ENABLE_SCM != 1) BHSM_GetDefaultSettings(&hsmSettings, GetCHP()); hsmSettings.eCustMode = BHSM_CustMode_eGeneric; rc = BHSM_Open(&((*h_hdmi)->hHsm), GetREG(), GetCHP() , &hsmSettings); BDBG_ASSERT(rc == BERR_SUCCESS); #endif pHdcpConfiguration = &((*h_hdmi)->hdcpConfig); pDefaultDependencies = &((*h_hdmi)->hdcpDependencies); BHDCPlib_GetDefaultConfiguration(pHdcpConfiguration); BHDCPlib_GetDefaultDependencies(pDefaultDependencies); pDefaultDependencies->hHdm = (*h_hdmi)->hHDMI; #if (CONFIG_ENABLE_SCM != 1) pDefaultDependencies->hHsm = (*h_hdmi)->hHsm; #endif pDefaultDependencies->hTmr = GetTMR(); #ifdef BHDM_HAS_SECURITY (*h_hdmi)->transmitEncrypted = true; #endif rc = BHDCPlib_Open(&((*h_hdmi)->hHDCPlib), pDefaultDependencies); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BHDCPlib_GetKeySet(pHdcpConfiguration->TxKeySet.TxAksv, pHdcpConfiguration->TxKeySet.TxKeyStructure); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BHDCPlib_SetConfiguration((*h_hdmi)->hHDCPlib, pHdcpConfiguration); BDBG_ASSERT(rc == BERR_SUCCESS); /* get HDCP Ri Event Handle */ rc = BHDM_GetEventHandle((*h_hdmi)->hHDMI, BHDM_EventHDCPRiValue,&((*h_hdmi)->hHDCPRiEvent)); BDBG_ASSERT(rc == BERR_SUCCESS); /* get HDCP Pj Event Handle */ rc = BHDM_GetEventHandle((*h_hdmi)->hHDMI, BHDM_EventHDCPPjValue, &((*h_hdmi)->hHDCPRjEvent)); BDBG_ASSERT(rc == BERR_SUCCESS); #endif /* HDCPLIB */ /* initialize here first so that we can get EDID information */ BHDM_EDID_Initialize((*h_hdmi)->hHDMI); s_bsettop_hdmi = *h_hdmi; bsettop_hdmi_vdc_connect(*h_hdmi); bdisplay_get(display,&display_settings); display_settings.rate_change_cb = bsettop_display_rate_change_cb; display_settings.rate_change_data = (void*)(*h_hdmi); rc = bdisplay_set(display,&display_settings); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_set failed %d.",rc)); } baudio_decode_get_config(audio_decode,&audio_config); audio_config.rate_change_cb = bsettop_audio_rate_change_cb; audio_config.rate_change_data = (void*)(*h_hdmi); rc = baudio_decode_set_config(audio_decode,&audio_config); if (rc != BERR_SUCCESS) { BDBG_ERR(("baudio_decode_set_config failed %d.",rc)); } s_bsettop_hdmi->hdcp_authentication_cb = hdcp_authentication_cb; (*h_hdmi)->lastState = HdmiOutputState_eDisconnected; bsettop_handle_hdmi_event((*h_hdmi)); #if BHDM_CEC_SUPPORT HdmiOutput_GetCecSettings(*h_hdmi, &g_cecSettings); g_cecSettings.enabled = true; rc = HdmiOutput_SetCecSettings(*h_hdmi, &g_cecSettings); HdmiOutput_P_CecCallback(*h_hdmi); #endif #endif return b_ok; } /** Summary: Release hdmi resources. **/ void bsettop_hdmi_close(bsettop_hdmi_t h_hdmi) { BDBG_ASSERT(h_hdmi); BDBG_ASSERT(h_hdmi->hHDMI); #ifdef HDCPLIB BDBG_ASSERT(h_hdmi->hHDCPlib); #if (CONFIG_ENABLE_SCM!=1) BDBG_ASSERT(h_hdmi->hHsm); #endif BHDCPlib_Close(h_hdmi->hHDCPlib); #if (CONFIG_ENABLE_SCM!=1) BHSM_Close(h_hdmi->hHsm); #endif #endif /* HDCPLIB */ BHDM_Close(h_hdmi->hHDMI); BKNI_Free(h_hdmi); } bresult boutput_hdmi_get_status(bsettop_hdmi_t h_hdmi, boutput_hdmi_status *status /* [out] */ ) { HdmiOutputState hdmi_state; BERR_Code rc; BHDM_EDID_RxVendorSpecificDB RxVSDB; BFMT_VideoFmt magnumFormat; BHDM_EDID_DetailTiming detailedTiming; unsigned int detailTimingNum = 1; bool bHdmiDevice = false; BDBG_ASSERT(h_hdmi); BDBG_ASSERT(status); BKNI_Memset(status, 0, sizeof(boutput_hdmi_status)); hdmi_state = bsettop_hdmi_get_state(h_hdmi,false); if (hdmi_state == HdmiOutputState_eConnected) { status->connected = true; rc = BHDM_EDID_IsRxDeviceHdmi(h_hdmi->hHDMI, &RxVSDB, &bHdmiDevice); if ((rc == BERR_SUCCESS) && bHdmiDevice) { status->is_hdmi = true; } /* retrieve the preferred */ status->preferred = bvideo_format_count; magnumFormat = BFMT_VideoFmt_eDVI_640x480p; /* default to safe mode */ while (1) { rc = BHDM_EDID_GetDetailTiming(h_hdmi->hHDMI, detailTimingNum, &detailedTiming, &magnumFormat); if (rc == BERR_SUCCESS) { detailTimingNum++; if (!BFMT_SUPPORT_HDMI(magnumFormat)) { continue; } if (magnumFormat == BFMT_VideoFmt_e720p) { status->preferred = bvideo_format_720p; break; } else if (magnumFormat == BFMT_VideoFmt_e1080i) { status->preferred = bvideo_format_1080i; break; } else if (magnumFormat == BFMT_VideoFmt_eNTSC) { status->preferred = bvideo_format_ntsc; break; } else if (magnumFormat == BFMT_VideoFmt_e480p) { status->preferred = bvideo_format_480p; break; } else { continue; } } else { break; } } /* HDCP status */ #ifdef HDCPLIB if (h_hdmi->hdcpState == BHDCPlib_State_eEncryptionEnabled) status->hdcp_state = boutput_hdmi_hdcp_state_enabled; else #endif status->hdcp_state = boutput_hdmi_hdcp_state_internal_err; } else { status->connected = false; } return b_ok; } /** Summary: check if HDCP authentication is successful or not **/ bool bsettop_hdmi_check_hdcp_authentication_status(bsettop_hdmi_t h_hdmi) { #ifdef HDCPLIB BDBG_ASSERT(h_hdmi); return (BHDCPlib_State_eEncryptionEnabled == h_hdmi->hdcpState); #else return true; #endif } /* * Summary: * power management for HDM block */ void bsettop_hdmi_standby(bsettop_hdmi_t h_hdmi, bool standby) { if (standby) { BHDM_Standby(h_hdmi->hHDMI, NULL); } else { BHDM_Resume(h_hdmi->hHDMI); } }