#include "drv_types.h" #include // abs(), max() #include #include #include "hdmi.h" #include "hdmi_dbg.h" #include "hdmi_hw.h" #include "hdmi_audio.h" #include "hdmi_cmdq.h" #include "hdmi_notice.h" #include "gpioi2c.h" #include "sysreg.h" #include "drv_audio_internal.h" #include "../audio/drv_audio_common.h" #include "spdif_parser.h" #ifdef INIT_BY_KMF #include #endif //In previous software architecture, we only have multiple PCM channel case in media and HDMI. //In order to reduce memory usage in new architecture, We want to block Multi-pcm case in HDMI driver. //#define CONFIG_HDMI_Support_MULTI_PCM void HDMI_Audio_ChannelLocked(void); typedef enum { HDMI_PATH_LINEAR = 0, HDMI_PATH_PARSE, HDMI_PATH_BYPASS, } HDMI_PATH_T; //use smaller sample nuber to improve AV sync issue #define LINEAR_SAMPLE_NUMBER 768 #define Linear_Buffer_Number 32 //#define LINEAR_SAMPLE_NUMBER 1536 //#define Linear_Buffer_Number 16 #define PARSE_BUFFER_SIZE 4096 #define BYPASS_SAMPLE_NUMBER 1536 #define NonLinear_ByPass_Buffer_Number 16 #define NonLinear_Parse_Buffer_Number 16 typedef struct _WRITEBUF_DESC { union { UINT32 dw1; struct { UINT32 Buffer_Valid: 1; UINT32 Discontinuous: 1; UINT32 Pause_Exist: 1; UINT32 Buffer_Full: 1; UINT32 reserved1: 12; UINT32 b_size: 16; }; }; union { UINT32 dw2; struct { UINT32 b_dlth: 16; UINT32 reserved2: 8; UINT32 b_th: 8; }; }; union { UINT32 dw3; UINT32 PTS; }; union { UINT32 dw4; struct { UINT32 PTS_high: 1; UINT32 reserved3: 15; UINT32 Vbmap: 16; }; }; union { UINT32 dw5; struct { UINT32 reserved4: 4; UINT32 b1_sadd: 27; UINT32 reserved5: 1; }; }; union { UINT32 dw6; struct { UINT32 reserved6: 4; UINT32 b2_sadd: 27; UINT32 reserved7: 1; }; }; union { UINT32 dw7; struct { UINT32 reserved8: 4; UINT32 b3_sadd: 27; UINT32 reserved9: 1; }; }; union { UINT32 dw8; struct { UINT32 reservedA: 4; UINT32 b4_sadd: 27; UINT32 reservedB: 1; }; }; } WRITEBUF_DESC, *WRITEBUF_DESC_PTR; typedef struct _HDMI_PARSER { struct { UINT32 audio_type: 1; //LINEAR/NONLINEAR UINT32 sfreq: 4; UINT32 osfreq: 4; UINT32 wordLen: 4; UINT32 reserved1: 3; UINT32 chcount: 3; UINT32 spkplace: 8; UINT32 downmixinhb: 1; UINT32 lvshVal: 4; }; struct { UINT32 offset_flag: 1; UINT32 bDualChannel: 1; UINT32 TX_path: 3; UINT32 path: 2; // see defined values HDMI_PATH_xxxx UINT32 sp_non_linear_type: 5; UINT32 codingMode: 3; // codingMode // 0:1+1 dual mode, 1:C, 2:L R, 3: L C R, // 4:L R S, 5:L C R S, 6:L R SL SR, 7:L C R SL SR // AC3 - The same with codingMode // MPEG - 0:L R, 1:Joint Stereo, 2:Dual channel, 3:Single channel UINT32 bSupportNotice: 1; UINT32 relock_count: 8; UINT32 reserver2: 8; //~cdlin }; INT32 reset516_count; INT32 audio_stream_type; //AC3 or MPEG UINT32 audio_offset; UINT32 NLdelayCnt; UINT32 sample_number; UINT32 writeBufNum; UINT32 bufSize; UINT8 *writeBuf; UINT8 *writeBufDsp; UINT32 wbuf_index; UINT8 cmdq[32]; UINT32 Freq; UINT32 pPts; } HDMI_PARSER, *HDMI_PARSER_PTR; static HDMI_PARSER g_hp; static UINT8 Reset_Count = 0; volatile BOOL bReset = false; static volatile BOOL audio_active = false; volatile BOOL chLock_flag = false; volatile INT32 menu_path = AUDIO_MENU_INTERNAL; #ifdef CONFIG_HDMI_SUPPORT_MHL extern BOOL MHL_CABLE_IN; extern BOOL MHL_CTS; #endif static UINT32 getDW(UINT8* ptr) { return ((*ptr << 24) | (*(ptr + 1) << 16) | (*(ptr + 2) << 8) | *(ptr + 3)); } #if 0//CONFIG_HDMI_Support_MULTI_PCM static UINT8 getSpeakerPlacement(UINT32 spkplace) { UINT8 chinvalid[32] = { 0xfc, 0xf8, 0xf4, 0xf0, 0xec, 0xe8, 0xe4, 0xe0, 0xcc, 0xc8, 0xc4, 0xc0, 0x8c, 0x88, 0x84, 0x80, 0x0c, 0x08, 0x04, 0x00, 0x3c, 0x38, 0x34, 0x30, 0x2c, 0x28, 0x24, 0x20, 0x0c, 0x08, 0x04, 0x00 }; return chinvalid[spkplace]; } #endif static UINT8 getChannelCount(UINT32 spkplace, UINT32 chcount) { // chcnt. 0 - 2ch, 1- 5.1ch, 2 - 7.1 ch UINT8 chcnt_spk[32] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; static UINT8 chcnt_chn[8] = { 2, 0, 1, 1, 1, 1, 2, 2 }; return (chcnt_spk[spkplace] < chcnt_chn[chcount]) ? chcnt_spk[spkplace] : chcnt_chn[chcount]; } static UINT32 getFreq(UINT32 idx) { UINT32 ofreq_list[16] = { 1, 192000, 12000, 176400, 1 , 96000, 8000, 88200, 16000, 24000, 11025, 22050, 32000, 48000, 1, 44100 }; return ofreq_list[idx]; } static BOOL verifyFreq(HDMI_PARSER_PTR hp, UINT32 pts_dif2) { UINT32 pts_dif1 = (hp->sample_number * 45000) / hp->Freq; if((hp->sp_non_linear_type)== 21) //EAC3 (Dolby Digital Plus) bypass verfy freq. return true; if (abs(pts_dif1 - pts_dif2) > 10) { UINT32 rfreq = 0, sfreq = 0, min_dist = 192000, dist = 0; UINT8 osfreq = 13; //48k INT32 i = 0; rfreq = (45000 * hp->sample_number) / pts_dif2; for (i = 0; i < 16; i++) { sfreq = getFreq(i); dist = (sfreq < rfreq) ? (rfreq - sfreq) : (sfreq - rfreq); if (dist < min_dist) { min_dist = dist; osfreq = i; } } if (osfreq == hp->osfreq) { return true; } hp->osfreq = osfreq; hp->Freq = getFreq(hp->osfreq); if (hp->Freq == 1) { return true; } return false; } return true; } static UINT8 AUDIO_freq(INT32 freq) { static INT32 dsp_freq_list[9] = {24000, 48000, 96000, 192000, 22050, 44100, 88200, 176400, 32000}; UINT8 i = 0; if (freq == 0) { return 15; } for (i = 0; i < sizeof(dsp_freq_list) / sizeof(INT32); i++) { if (freq == dsp_freq_list[i]) { return i; } } return 15; } #define HDMI_AUDIO_PTS_OFFSET 60 // PCM BUFFER NUMBER = 16, 192KHZ FRAME TIME = 4ms,, modify PTS OFFSET = 60ms ( 60/4 = 15 < 16) #define HDMI_AUDIO_PTS_OFFSET_NL 100 static void AUDIO_setDelayTime(HDMI_PARSER_PTR hp) { if (hp->path == HDMI_PATH_LINEAR || hp->path == HDMI_PATH_BYPASS) { #ifdef CONFIG_HDMI_SUPPORT_MHL if((MHL_CTS == TRUE)&&(MHL_CABLE_IN == TRUE)&&( DrvHDMIPortSelectBitsGet() == CONFIG_HDMI_MHL_PORT)) { hp->audio_offset = 250 * 90; // 100 ms } else { hp->audio_offset = HDMI_AUDIO_PTS_OFFSET * 90; // 60 ms } #else hp->audio_offset = HDMI_AUDIO_PTS_OFFSET * 90; // 60 ms #endif hp->NLdelayCnt = 0; } else // hp->path == HDMI_PATH_PARSE { if (hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR || hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_LINEAR ||hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT_PCM) { hp->audio_offset = HDMI_AUDIO_PTS_OFFSET_NL * 90; // 100 ms hp->NLdelayCnt = ((30 * hp->Freq) / 1000) >> 5; } else { hp->audio_offset = HDMI_AUDIO_PTS_OFFSET_NL * 90;// 100 ms hp->NLdelayCnt = 0; } } } static void AUDIO_ResetLock(void) { HDMI_PARSER_PTR hp = &g_hp; HDMI_RegisterWrite(HDMIRX_R_dma_w_enable, 0); HDMI_Interrupt_Disable(INTR_Buffer_Change_Pulse); while (HDMI_RegisterRead(HDMIRX_Buffer_chg_cnt)) { HDMI_RegisterWrite(HDMIRX_R_INTR_Status, INTR_Buffer_Change_Pulse); //clear } memset(hp, 0, sizeof(HDMI_PARSER)); HDMI_AudioResetDecoder(); chLock_flag = false; HDMI_Audio_ChannelLocked(); HDMI_Interrupt_Enable(INTR_Buffer_Change_Pulse); HDMI_RegisterWrite(HDMIRX_R_dma_w_enable, 1); } void DRV_HDMI_AudioEnable(void) { TVFE_Audio_Mute_t MC; hdmidbg("%s\n", __FUNCTION__); #define PRECHARGE_MODE 1 #define BURST_MODE 0 // Default 0:128, 1:256, 2:512 chLock_flag = false; if (audio_active) { hdmidbg("\tdone\n"); return; } if (HDMI_RegisterRead(HDMIRX_R_HDMI_en) == 0) { hdmidbg("\tCan't enable audio in dvi\n"); return; } if (HDMI_RegisterRead(HDMIRX_AS_exist)) { hdmidbg("\tNoraml Audio!\n"); HDMI_RegisterWrite(HDMIRX_R_HBRAS_sel, 0); } else { if (HDMI_RegisterRead(HDMIRX_HBRAS_exist)) { hdmidbg("\tHBRAS Audio!\n"); HDMI_RegisterWrite(HDMIRX_R_HBRAS_sel, 1); } else { hdmidbg("\tNoraml Audio!\n"); HDMI_RegisterWrite(HDMIRX_R_HBRAS_sel, 0); } } sysset_hdmi_stcclk(); HDMI_RegisterWrite(HDMIRX_R_parsing_en, 0); HDMI_RegisterWrite(HDMIRX_R_unlock_th, 0x2); HDMI_RegisterWrite(HDMIRX_R_layout_detect, 1); HDMI_RegisterWrite(HDMIRX_R_layout_th, 0); HDMI_RegisterWrite(HDMIRX_R_mem_ap_en, PRECHARGE_MODE); HDMI_RegisterWrite(HDMIRX_R_as_mem_mode, BURST_MODE); HDMI_Interrupt_Enable(INTR_Channel_Status_Lock_Pulse); HDMI_RegisterWrite(HDMIRX_R_audio_enable, 1); HDMI_RegisterWrite(HDMIRX_R_dma_w_enable, 0); HDMI_Interrupt_Disable(INTR_Buffer_Change_Pulse); audio_active = true; //ADD MUTE PROTECT TO AVOID UNSMOOTH AUDIO OUTPUT MC.Enable = 0; MC.Mute_Delay= 0; MC.Mute_TXSpeed= 0; MC.Mute_Path = TVFE_AUDIO_MUTE_DRV_ALL_PATH; DRV_AUDIO_DC_SetMute(&MC); //~MUTE PROTECT } void DRV_HDMI_AudioDisable(void) { TVFE_Audio_Mute_t MC; hdmidbg("%s\n", __FUNCTION__); chLock_flag = false; if (!audio_active) { hdmidbg("\tdone\n"); return; } //ADD MUTE PROTECT TO AVOID UNSMOOTH AUDIO OUTPUT MC.Enable = 1; MC.Mute_Delay= 0; MC.Mute_TXSpeed= 0; MC.Mute_Path = TVFE_AUDIO_MUTE_DRV_ALL_PATH; DRV_AUDIO_DC_SetMute(&MC); //~MUTE PROTECT HDMI_RegisterWrite(HDMIRX_R_dma_w_enable, 0); HDMI_Interrupt_Disable(INTR_Buffer_Change_Pulse | INTR_Channel_Status_Lock_Pulse | INTR_audio_sample_coming | INTR_HBR_audio_sample_coming | INTR_ACP_packets); HDMI_RegisterWrite(HDMIRX_R_audio_enable, 0); audio_active = false; memset(&g_hp, 0, sizeof(HDMI_PARSER)); } void DRV_HDMI_AudioSetOutputPath(UINT8 menu_select) { BOOL bAudioEnable; bAudioEnable = HDMI_RegisterRead(HDMIRX_R_audio_enable) ? TRUE : FALSE; if (bAudioEnable) { DRV_HDMI_AudioDisable(); } menu_path = menu_select; if (bAudioEnable) { DRV_HDMI_AudioEnable(); } } void DRV_HDMI_AudioRestart(void) { hdmidbg("%s\n", __FUNCTION__); if (HDMI_RegisterRead(HDMIRX_R_audio_enable)) { DRV_HDMI_AudioDisable(); DRV_HDMI_AudioEnable(); } else { if (HDMI_RegisterRead(HDMIRX_R_HDMI_en) == 1) { hdmidbg("%s:input signal changed form dvi to hdmi!\n", __FUNCTION__); DRV_HDMI_AudioDisable(); DRV_HDMI_AudioEnable(); } else { hdmidbg("%s:Skipped! Audio is not enable!\n", __FUNCTION__); } } } void HDMI_Audio_ChannelLocked(void) { HDMI_PARSER_PTR hp = &g_hp; pAUDIO_CMDQ cmdq = (pAUDIO_CMDQ)(hp->cmdq); UINT8 audio_type = (HDMI_RegisterRead(HDMIRX_R_ACS_CSts) & 0x2) >> 1; UINT8 chcount = HDMI_RegisterRead(HDMIRX_R_Ado_CC) & 0x7; UINT8 spkplace = HDMI_RegisterRead(HDMIRX_R_Ado_CA) & 0x1f; UINT8 downmixinhb = HDMI_RegisterRead(HDMIRX_R_Ado_DMInh); UINT8 lvshVal = HDMI_RegisterRead(HDMIRX_R_Ado_LSV); UINT8 osfreq = ~(HDMI_RegisterRead(HDMIRX_R_ACS_Sfeq)) & 0xf; UINT8 sp_non_linear_type = HDMI_RegisterRead(HDMIRX_R_sp_non_linear_type); UINT32 i = 0; if (menu_path == AUDIO_MENU_MUTE) { hp->TX_path = menu_path; return; } if (chLock_flag) { if (hp->osfreq != osfreq || hp->audio_type != audio_type || hp->chcount != chcount || hp->spkplace != spkplace) { hdmidbg("channel status is changed\n"); HDMI_Audio_ChannelUnlocked(); } else { if(hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT) { //PHILIPS DVD player updated audio buffer before ch lock function when switch play DD&DDP file at ARC case //but buffer update fucntion verfies PTS to change sfreq(48k<->192k), ch lock function will show channel status no changed //add check sp_non_linear_type to do error handle. if(hp->sp_non_linear_type != sp_non_linear_type) { hdmidbg("channel status is changed, ori_type=%d, hw_type=%d\n", hp->sp_non_linear_type, sp_non_linear_type); HDMI_Audio_ChannelUnlocked(); } } else { hdmidbg("channel status no changed, return\n"); return; } } } HDMI_RegisterWrite(HDMIRX_R_disc_tout, 0x48000); // 24576000x12ms HDMI_RegisterWrite(HDMIRX_R_as_w_timeout, 0x0); // Reset Audio Decoder bReset = true; // hp initialization hp->offset_flag = false; hp->reset516_count = 0; hp->relock_count = 0; hp->bDualChannel = false; hp->codingMode = 7; //AC3 5.1ch hp->bSupportNotice = false; hp->TX_path = menu_path; //Menu decide the TX path. hp->wbuf_index = 0; // Write buffer Index pointer hp->audio_type = audio_type; hp->wordLen = HDMI_RegisterRead(HDMIRX_R_ACS_Wlen); // hp->osfreq = HDMI_RegisterRead(HDMIRX_R_ACS_OSFeq); // hp->sfreq = HDMI_RegisterRead(HDMIRX_R_ACS_Sfeq); hp->osfreq = osfreq; hp->chcount = chcount; hp->spkplace = spkplace; hp->downmixinhb = downmixinhb; hp->lvshVal = lvshVal; // hp->sp_non_linear_type = HDMI_RegisterRead(HDMIRX_R_sp_non_linear_type); hp->sp_non_linear_type = 1; //Default AC3 Format hp->pPts = 0; hp->Freq = getFreq(hp->osfreq); hdmidbg("%s: %s audio %dK\n", __FUNCTION__, audio_type ? "nonlinear" : "linear", hp->Freq / 1000); /* Initialize audio command queue */ cmdq->CID = AUDIO_CID; cmdq->RxType = AUDIO_RX_TYPE_HDMI; cmdq->sfreq = AUDIO_freq(hp->Freq); cmdq->ZeroStuffLen = 0; if (hp->audio_type) // nonlinear { hp->lvshVal = 0; //we should not take these two variables in account in NonLinear path. hp->downmixinhb = 0; // Set to 0. if (hp->TX_path == AUDIO_MENU_INTERNAL || hp->TX_path == AUDIO_MENU_EXTERNAL) { hp->path = HDMI_PATH_PARSE; cmdq->TxType = AUDIO_TX_TYPE_ONLY_I2S; } else if (hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT) { hp->path = HDMI_PATH_BYPASS; cmdq->TxType = AUDIO_TX_TYPE_ONLY_SPDIF; } else if (hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR) { hp->path = HDMI_PATH_PARSE; cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_NONLINEAR; } else if (hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_LINEAR ||hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT_PCM) { hp->path = HDMI_PATH_PARSE; cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_LINEAR; } } else //linear { hp->path = HDMI_PATH_LINEAR; if (hp->TX_path == AUDIO_MENU_INTERNAL || hp->TX_path == AUDIO_MENU_EXTERNAL) { cmdq->TxType = AUDIO_TX_TYPE_ONLY_I2S; } else if (hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT) { cmdq->TxType = AUDIO_TX_TYPE_ONLY_SPDIF; } else if (hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR || hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_LINEAR ||hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT_PCM) { cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_LINEAR; } } if (hp->path == HDMI_PATH_LINEAR) //linear { hdmidbg("\n"); HDMI_RegisterWrite(HDMIRX_R_parsing_en, 0); #if 0//CONFIG_HDMI_Support_MULTI_PCM HDMI_RegisterWrite(HDMIRX_R_rx_ch_set, 0x2); #else /* Patch: Only stereo pcm input is allowed. */ HDMI_RegisterWrite(HDMIRX_R_rx_ch_set, 0x0); #endif /* Setup write buffer number */ HDMI_RegisterWrite(HDMIRX_R_wbuf_num, Linear_Buffer_Number - 1); hp->bufSize = LINEAR_SAMPLE_NUMBER << 3; //Buffer size (1 group) for linear audio data. hp->writeBufNum = Linear_Buffer_Number; /* Note: Four write buffer group should be in different blank. Blank size is 64 bytes */ hp->writeBufDsp = (UINT8*)AUDIO_RX_HDMI_DESP_BUFF_ADDR; hp->writeBuf = (UINT8*)AUDIO_PCM_BUFF_ADDR; /* Setup write buffer descriptor for hdmi audio rx */ HDMI_RegisterWrite(HDMIRX_R_dma_start_addr, ((UINT32)hp->writeBufDsp & 0x1fffffff) >> 4); for (i = 0; i < hp->writeBufNum; i++) { WRITEBUF_DESC_PTR wbufdsc_ptr = (WRITEBUF_DESC_PTR)(hp->writeBufDsp + i * sizeof(WRITEBUF_DESC)); wbufdsc_ptr->Buffer_Valid = 0; wbufdsc_ptr->b_size = hp->bufSize >> 4; wbufdsc_ptr->dw5 = 0; wbufdsc_ptr->dw6 = 0; wbufdsc_ptr->dw7 = 0; wbufdsc_ptr->dw8 = 0; wbufdsc_ptr->b1_sadd = (((UINT32)(hp->writeBuf + i * (hp->bufSize))) & 0x1fffffff) >> 4; wbufdsc_ptr->b1_sadd = GET_ADDR_FOR_HW(wbufdsc_ptr->b1_sadd); #if 0//CONFIG_HDMI_Support_MULTI_PCM wbufdsc_ptr->b2_sadd = (((UINT32)(hp->writeBuf + i * (hp->bufSize) + 1 * (hp->writeBufNum * hp->bufSize) + 64 * 1)) & 0x1fffffff) >> 4; wbufdsc_ptr->b2_sadd = GET_ADDR_FOR_HW(wbufdsc_ptr->b2_sadd); wbufdsc_ptr->b3_sadd = (((UINT32)(hp->writeBuf + i * (hp->bufSize) + 2 * (hp->writeBufNum * hp->bufSize) + 64 * 2)) & 0x1fffffff) >> 4; wbufdsc_ptr->b3_sadd = GET_ADDR_FOR_HW(wbufdsc_ptr->b3_sadd); wbufdsc_ptr->b4_sadd = (((UINT32)(hp->writeBuf + i * (hp->bufSize) + 3 * (hp->writeBufNum * hp->bufSize) + 64 * 3)) & 0x1fffffff) >> 4; wbufdsc_ptr->b4_sadd = GET_ADDR_FOR_HW(wbufdsc_ptr->b4_sadd); #endif } #if 0//CONFIG_HDMI_Support_MULTI_PCM memset((UINT8*)((((WRITEBUF_DESC_PTR) hp->writeBufDsp)->b2_sadd << 4) | 0xa0000000), 0, hp->bufSize * hp->writeBufNum); memset((UINT8*)((((WRITEBUF_DESC_PTR) hp->writeBufDsp)->b3_sadd << 4) | 0xa0000000), 0, hp->bufSize * hp->writeBufNum); #endif cmdq->flag = AUDIO_FLAG_PCM_OUT; cmdq->inDataType = AUDIO_DATA_TYPE_PCM; cmdq->outDataType = AUDIO_DATA_TYPE_PCM; cmdq->FrameNo = hp->writeBufNum;// write buffer size hp->audio_stream_type = cmdq->inDataType; hp->sample_number = LINEAR_SAMPLE_NUMBER; #if 0//CONFIG_HDMI_Support_MULTI_PCM cmdq->spkplace = getSpeakerPlacement(spkplace); cmdq->chcnt = getChannelCount(spkplace, chcount); #else /* Patch: Only stereo audio is allowed now */ cmdq->spkplace = 0xfc; cmdq->chcnt = 0; #endif cmdq->sp_non_linear_type = 0; cmdq->sample_bit = hp->wordLen; } else if (hp->path == HDMI_PATH_PARSE) // parse mode { hdmidbg("\n"); HDMI_RegisterWrite(HDMIRX_R_parsing_en, 1); HDMI_RegisterWrite(HDMIRX_R_rx_ch_set, 0); // one group in one write buffer HDMI_RegisterWrite(HDMIRX_R_wbuf_num, NonLinear_Parse_Buffer_Number - 1); /* Swap high low bytes in parse mode */ HDMI_RegisterWrite(HDMIRX_R_byte_swap, 0x01); hp->bufSize = PARSE_BUFFER_SIZE; hp->writeBufNum = NonLinear_Parse_Buffer_Number; hp->writeBufDsp = (UINT8*)AUDIO_RX_HDMI_DESP_BUFF_ADDR; hp->writeBuf = (UINT8*)AUDIO_CMD_BUFF_ADDR; /* Setup write buffer descriptor for hdmi audio rx */ HDMI_RegisterWrite(HDMIRX_R_dma_start_addr, ((UINT32)hp->writeBufDsp & 0x1fffffff) >> 4); for (i = 0; i < hp->writeBufNum; i++) { WRITEBUF_DESC_PTR wbufdsc_ptr = (WRITEBUF_DESC_PTR)(hp->writeBufDsp + i * sizeof(WRITEBUF_DESC)); wbufdsc_ptr->Buffer_Valid = 0; wbufdsc_ptr->b_size = hp->bufSize >> 4; wbufdsc_ptr->b_th = 1; //NonLinear, 1 frame in one write buffer wbufdsc_ptr->dw5 = 0; wbufdsc_ptr->b1_sadd = (((UINT32)(hp->writeBuf + i * (hp->bufSize))) & 0x1fffffff) >> 4; wbufdsc_ptr->b1_sadd = GET_ADDR_FOR_HW(wbufdsc_ptr->b1_sadd); } cmdq->flag = AUDIO_FLAG_DECODING; hp->audio_stream_type = cmdq->inDataType = AUDIO_DATA_TYPE_AC3; hp->sample_number = 1536; cmdq->outDataType = AUDIO_DATA_TYPE_PCM; cmdq->FrameNo = 1; //One frame in buffer will be decoded. cmdq->spkplace = 0; cmdq->chcnt = 0; cmdq->sp_non_linear_type = 0; cmdq->sample_bit = 0; } else if (hp->path == HDMI_PATH_BYPASS) { hdmidbg("\n"); HDMI_RegisterWrite(HDMIRX_R_parsing_en, 0); HDMI_RegisterWrite(HDMIRX_R_rx_ch_set, 0); // one group in one write buffer HDMI_RegisterWrite(HDMIRX_R_wbuf_num, NonLinear_ByPass_Buffer_Number - 1); //ByPass mode, 32 write buffer now hp->bufSize = BYPASS_SAMPLE_NUMBER * 8; hp->writeBufNum = NonLinear_ByPass_Buffer_Number; hp->writeBufDsp = (UINT8*)AUDIO_RX_HDMI_DESP_BUFF_ADDR; hp->writeBuf = (UINT8*)AUDIO_PCM_BUFF_ADDR; /* Setup write buffer descriptor for hdmi audio rx */ HDMI_RegisterWrite(HDMIRX_R_dma_start_addr, ((UINT32)hp->writeBufDsp & 0x1fffffff) >> 4); for (i = 0; i < hp->writeBufNum; i++) { WRITEBUF_DESC_PTR wbufdsc_ptr = (WRITEBUF_DESC_PTR)(hp->writeBufDsp + i * sizeof(WRITEBUF_DESC)); wbufdsc_ptr->Buffer_Valid = 0; wbufdsc_ptr->b_size = hp->bufSize >> 4; wbufdsc_ptr->b_th = 1; //NonLinear, 1 frame in one write buffer wbufdsc_ptr->dw5 = 0; wbufdsc_ptr->b1_sadd = (((UINT32)(hp->writeBuf + i * (hp->bufSize))) & 0x1fffffff) >> 4; wbufdsc_ptr->b1_sadd = GET_ADDR_FOR_HW(wbufdsc_ptr->b1_sadd); } cmdq->flag = AUDIO_FLAG_BYPASS; hp->audio_stream_type = 0; cmdq->inDataType = cmdq->outDataType = AUDIO_DATA_TYPE_AC3; //hp->audio_stream_type = cmdq->inDataType = cmdq->outDataType = AUDIO_DATA_TYPE_AC3; hp->sample_number = BYPASS_SAMPLE_NUMBER; cmdq->FrameNo = 1; cmdq->spkplace = 0; cmdq->chcnt = 0; //cmdq->sp_non_linear_type=hp->sp_non_linear_type; cmdq->sample_bit = 0; } /* HDMI Source SPDIF OUT fix at SPDIF_WORD_LENGTH_16_BITS */ //cmdq->sample_bit = 0x2;// SPDIF_WORD_LENGTH_16_BITS = 0x2, hdmidbg(" writeBufDsp 0x%p\n", hp->writeBufDsp); hdmidbg(" writeBuf 0x%p\n", hp->writeBuf); AUDIO_setDelayTime(hp); chLock_flag = true; HDMI_Interrupt_Enable(INTR_Buffer_Change_Pulse); //HDMI_Interrupt_Enable(INTR_ACP_packets); HDMI_RegisterWrite(HDMIRX_R_dma_w_enable, 1); } void HDMI_Audio_ChannelUnlocked(void) { HDMI_PARSER_PTR hp = &g_hp; HDMI_RegisterWrite(HDMIRX_R_dma_w_enable, 0); HDMI_Interrupt_Disable(INTR_Buffer_Change_Pulse); while (HDMI_RegisterRead(HDMIRX_Buffer_chg_cnt)) { HDMI_RegisterWrite(HDMIRX_R_INTR_Status, INTR_Buffer_Change_Pulse); //clear } // set_current_state(TASK_UNINTERRUPTIBLE); // schedule_timeout(1); memset(hp, 0, sizeof(HDMI_PARSER)); HDMI_AudioResetDecoder(); chLock_flag = false; } static UINT32 ddp_get_freq(unsigned char *ptr) { UINT32 sfreq = 0; if (ptr[0] == 0x0b && ptr[1] == 0x77) { UINT32 fscod_tbl[4] = {48000, 44100, 32000, 0}; UINT32 fscod2_tbl[4] = {24000, 22050, 16000, 0}; /* check fscod */ if ((ptr[4] >> 6) != 0x3) { sfreq = fscod_tbl[ptr[4] >> 6]; } else { /* fscod2_numblkscod */ sfreq = fscod2_tbl[(ptr[4] >> 4) & 0x3]; } } return sfreq; } static UINT32 ddp_get_framesize(UINT8 *ptr) { UINT32 fsz = 0; if (ptr[0] == 0x0b && ptr[1] == 0x77) { UINT32 frmsize_tlb[3][38] = { {64, 64, 80, 80, 96, 96, 112, 112, 128, 128, 160, 160, 192, 192, 224, 224, 256, 256, 320, 320, 384, 384, 448, 448, 512, 512, 640, 640, 768, 768, 896, 896, 1024, 1024, 1152, 1152, 1280, 1280}, {69, 70, 87, 88, 104, 105, 121, 122, 139, 140, 174, 175, 208, 209, 243, 244, 278, 279, 348, 349, 417, 418, 487, 488, 557, 558, 696, 697, 835, 836, 975, 976, 1114, 1115, 1253, 1254, 1393, 1394}, {96, 96, 120, 120, 144, 144, 168, 168, 192, 192, 240, 240, 288, 288, 336, 336, 384, 384, 480, 480, 576, 576, 672, 672, 768, 768, 960, 960, 1152, 1152, 1344, 1344, 1536, 1536, 1728, 1728, 1920, 1920} }; UINT8 bsid = ptr[5] >> 3; if (bsid <= 8) { /* frmsizecod < 38 && fscod < 3 */ if ( /*(ptr[4] & 0x1f) < 38 && */ (ptr[4] >> 6) < 3) // (ptr[4] & 0x1f) < 38 is always TRUE { /* dd size = 2 * frmsize_tlb[fscod][frmsizecod] */ fsz = 2 * frmsize_tlb[ptr[4] >> 6][ptr[4] & 0x1f]; } } else if (bsid >= 11 && bsid <= 16) { /* ddp size = 2 * (ec3_frmsize + 1) */ fsz = 2 * ((((ptr[2] & 0x7) << 8) | ptr[3]) + 1); } } return fsz; } static BOOL ddp_substrm_frame(UINT8 *ptr) { if (ptr[0] == 0x0b && ptr[1] == 0x77) { return (ptr[2] & 0xf8); } return FALSE; } #define ALIGN4(sz) ((sz+3) & (~0x3)) void ddp_receive_frames(void *dev, UINT8 *ddp, UINT32 ddpsz, UINT32 pts) { HDMI_PARSER_PTR hp = (HDMI_PARSER_PTR)dev; AUDIO_CMDQ gcmdq, *cmdq = &gcmdq; BOOL validFrame = FALSE; UINT32 frmsz = 0, freq = 0; UINT32 parsed_sz = 0; UINT8 *ptr = NULL; UINT8 ACP_type = 0xff; if (ddp == NULL || ddpsz < 24) { hdmidbg("%s: Invalid IEC61937 buffer\n", __FUNCTION__); return; } memcpy(cmdq, &hp->cmdq, sizeof(AUDIO_CMDQ)); //hdmidbg("%s: ddp 0x%p ddpsz %d pts 0x%08x\n", __FUNCTION__, ddp, ddpsz, pts); /* Parse and validate whole IEC61937 payload */ parsed_sz = 8; ptr = ddp + parsed_sz; for (; parsed_sz < ddpsz; ptr += ALIGN4(frmsz)) { frmsz = ddp_get_framesize(ptr); freq = ddp_get_freq(ptr); validFrame = (frmsz && freq) ? TRUE : FALSE; if (validFrame == FALSE) { break; } /* Patch: Audio Decoder only accept 4 byte aligned pointer, adjust the buffer to meet the requirement. */ parsed_sz += frmsz; if ((ALIGN4(frmsz) != frmsz) && ptr + frmsz < ddp + ddpsz) { memmove(ptr + ALIGN4(frmsz), ptr + frmsz, ddpsz - parsed_sz); } } cmdq->flag = AUDIO_FLAG_DECODING; cmdq->pause = 0; cmdq->discontinue = 0; cmdq->chcnt = 0; cmdq->sfreq = AUDIO_freq(freq); cmdq->inDataType = AUDIO_DATA_TYPE_EAC3; cmdq->outDataType = AUDIO_DATA_TYPE_PCM; cmdq->DataPtr = (UINT32)ddp; cmdq->DataSize = hp->sample_number; cmdq->PTS_High = pts >> 31; cmdq->PTS = pts << 1; cmdq->spdif_channel_status_category_code = HDMI_RegisterRead(HDMIRX_R_ACS_CatC); cmdq->copy_protection = (HDMI_RegisterRead(HDMIRX_R_ACS_CSts) & 0x04) >> 2; //HC Modify ACP_type = HDMI_RegisterRead(HDMIRX_R_ACP_Type); if((ACP_type == ACP_GENERIC_AUDIO) || (ACP_type == ACP_IEC60958_IDENTIFIED)) { cmdq->copy_protection = 0; // ACP TYPE = 0 1, CP bit = 0, L bit =1 cmdq->spdif_channel_status_category_code = cmdq->spdif_channel_status_category_code | 0x80; } //~HC switch (hp->TX_path) { case AUDIO_MENU_INTERNAL: case AUDIO_MENU_EXTERNAL: cmdq->TxType = AUDIO_TX_TYPE_ONLY_I2S; break; case AUDIO_MENU_PARALLEL_SPDIF_LINEAR: case AUDIO_MENU_SPDIF_OUTPUT_PCM: cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_LINEAR; break; case AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR: cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_NONLINEAR; break; default: break; } if (HDMI_RegisterRead(HDMIRX_R_AV_Mute)) { validFrame = FALSE; } if (validFrame) { if (bReset) { bReset = HDMI_AudioResetDecoder() ? FALSE : TRUE; } if (!bReset) { if (!hp->offset_flag) { hp->Freq = freq; AUDIO_setDelayTime(hp); hp->offset_flag = HDMI_AudioSetOffset(hp->audio_offset, hp->NLdelayCnt); } if (hp->offset_flag) { parsed_sz = 8; ptr = ddp + parsed_sz; for (; parsed_sz < ddpsz; parsed_sz += frmsz, ptr += ALIGN4(frmsz), cmdq->DataPtr += ALIGN4(frmsz)) { frmsz = ddp_get_framesize(ptr); if (frmsz == 0) { break; } /* skip substream frame */ if (ddp_substrm_frame(ptr)) { continue; } /* Fire frame */ HDMI_AudioSendCmdq(cmdq); } } } } else { bReset = TRUE; hp->offset_flag = FALSE; } } typedef enum { E_SPDIF_TYPE_UNKNOWN = 0, E_SPDIF_TYPE_DD, E_SPDIF_TYPE_DDP, E_SPDIF_TYPE_OTHERS, } E_SPDIF_TYPE; static E_SPDIF_TYPE check_spdif_type(UINT8 *inbuf, UINT32 inbufsz) { UINT32 i; UINT32 *in = (UINT32*)inbuf; for (i = 0; i < inbufsz / 4 - 1; i += 2) { if ((in[i] >> 16) == 0xf872 && (in[i + 1] >> 16) == 0x4e1f) { UINT8 t = (in[i + 2] >> 16) & 0x1f; if (t == 1) { return E_SPDIF_TYPE_DD; } else if (t == 21) { return E_SPDIF_TYPE_DDP; } else { return E_SPDIF_TYPE_OTHERS; } } } return E_SPDIF_TYPE_UNKNOWN; } void HDMI_Audio_BufferUpdated(void) { HDMI_PARSER_PTR hp = &g_hp; pAUDIO_CMDQ cmdq; WRITEBUF_DESC_PTR wbufdsc; UINT32 cur_wbuf; BOOL validData = false; UINT8 audio_type = (HDMI_RegisterRead(HDMIRX_R_ACS_CSts) & 0x2) >> 1; UINT32 pts_diff; static UINT8 ACP_type_pre = 0xFF; UINT8 ACP_type = 0; AUDIO_IEC61937_HEADER sp_header; UINT8* dataptr; HDMI_RegisterWrite(HDMIRX_R_INTR_Status, INTR_Buffer_Change_Pulse); //clear if (!audio_active) { hdmidbg("%s:hdmi aud is not enable\n", __FUNCTION__); return; } cmdq = (pAUDIO_CMDQ)(&hp->cmdq); wbufdsc = (WRITEBUF_DESC_PTR)(hp->writeBufDsp + hp->wbuf_index * sizeof(WRITEBUF_DESC)); cur_wbuf = wbufdsc->b1_sadd << 4; dataptr = (UINT8*)(cur_wbuf | 0xa0000000); sp_header.dw1 = getDW(dataptr); sp_header.dw2 = getDW(dataptr+4); if (hp->audio_type != audio_type) { if (sp_header.data_type == 21 ||hp->sp_non_linear_type == 21) { hdmidbg("%s:EAC3 skip aud type mismatch case (hp->data:%d, header->datatype=%d\n", __FUNCTION__, hp->sp_non_linear_type, sp_header.data_type); } else { hdmidbg("%s:aud type mismatch(ori:%d, hw_reg=%d\n", __FUNCTION__, hp->audio_type, audio_type); AUDIO_ResetLock(); return; } } if (hp->path == HDMI_PATH_LINEAR) { if (wbufdsc->Buffer_Full && !wbufdsc->Discontinuous) { validData = true; cmdq->DataSize = hp->bufSize; // size of one write buffer group cmdq->DataPtr = cur_wbuf | 0xa0000000; cmdq->pause = wbufdsc->Pause_Exist; cmdq->discontinue = wbufdsc->Discontinuous; } } else if (hp->path == HDMI_PATH_PARSE) { //hdmidbg("%s:hp->data:%d, header->datatype=%d, b_dlth=%d, bufsze=%d\n", __FUNCTION__, hp->sp_non_linear_type, sp_header.data_type, wbufdsc->b_dlth ,hp->bufSize); if ((wbufdsc->b_dlth >= wbufdsc->b_th && !wbufdsc->Discontinuous) ||((wbufdsc->b_dlth == 0) &&(sp_header.data_type == 21 ||hp->sp_non_linear_type == 21))) //if(wbufdsc->b_dlth >= wbufdsc->b_th && !wbufdsc->Discontinuous) { validData = true; if (HDMI_RegisterRead(HDMIRX_R_parsing_en)) { if (hp->sp_non_linear_type != sp_header.data_type) { bReset = true; hp->offset_flag = false; hp->bSupportNotice = false; } hp->sp_non_linear_type = sp_header.data_type; if(hp->sp_non_linear_type == 21) { HDMI_RegisterWrite(HDMIRX_R_parsing_en, 0); HDMI_RegisterWrite(HDMIRX_R_byte_swap, 0); hdmi_spdif_parser_init( hp->writeBuf + NonLinear_Parse_Buffer_Number * PARSE_BUFFER_SIZE, ddp_receive_frames, hp); validData = false; } } else { UINT32 pts; validData = false; hp->sp_non_linear_type = 21; pts = (wbufdsc->PTS_high << 31) | (wbufdsc->PTS >> 1); hdmi_spdif_parser_handler(dataptr, hp->bufSize, pts); } switch (hp->sp_non_linear_type) { case 4: hp->sample_number = 384; cmdq->inDataType = AUDIO_DATA_TYPE_MPEG; break; case 5: hp->sample_number = 1152; cmdq->inDataType = AUDIO_DATA_TYPE_MPEG; break; case 6: hp->sample_number = 1152; cmdq->inDataType = AUDIO_DATA_TYPE_MPEG; break; case 8: hp->sample_number = 768; cmdq->inDataType = AUDIO_DATA_TYPE_MPEG; break; case 9: hp->sample_number = 2304; cmdq->inDataType = AUDIO_DATA_TYPE_MPEG; break; case 10: hp->sample_number = 1152; cmdq->inDataType = AUDIO_DATA_TYPE_MPEG; break; case 1: hp->sample_number = 1536; cmdq->inDataType = AUDIO_DATA_TYPE_AC3; break; case 21: //EAC3 hp->sample_number = 1536; cmdq->inDataType = AUDIO_DATA_TYPE_EAC3; break; case 11: //DTS type I hp->sample_number = 512; cmdq->inDataType = AUDIO_DATA_TYPE_DTS; //Currenttly unspported audio type break; case 12: //DTS type II hp->sample_number = 1024; cmdq->inDataType = AUDIO_DATA_TYPE_DTS; break; case 13: //DTS type III hp->sample_number = 2048; cmdq->inDataType = AUDIO_DATA_TYPE_DTS; break; case 7: //MPEG-2 AAC hp->sample_number = 1024; cmdq->inDataType = AUDIO_DATA_TYPE_UNKNOW; break; case 14: //ATRAC hp->sample_number = 512; cmdq->inDataType = AUDIO_DATA_TYPE_UNKNOW; break; case 15: //ATRAC 2/3 hp->sample_number = 1024; cmdq->inDataType = AUDIO_DATA_TYPE_UNKNOW; break; default: cmdq->inDataType = AUDIO_DATA_TYPE_UNKNOW; hp->sample_number = 1536; break; } cmdq->DataSize = hp->sample_number; cmdq->DataPtr = cur_wbuf | 0xa0000000; cmdq->pause = wbufdsc->Pause_Exist; cmdq->discontinue = wbufdsc->Discontinuous; cmdq->sp_non_linear_type = hp->sp_non_linear_type; if (hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR || hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_LINEAR ||hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT_PCM) { INT32 framesize = ((*(((UINT8*)cmdq->DataPtr) + 6)) << 8 | *(((UINT8*)cmdq->DataPtr) + 7)); cmdq->flag = AUDIO_FLAG_DECODING; cmdq->outDataType = AUDIO_DATA_TYPE_PCM; /* Only clear zero stuffing when input type is not EAC3. */ if(hp->sp_non_linear_type != 21) { framesize /= 8; cmdq->NLsize = ((8 + framesize + 15) & ~15) >> 4; memset(((UINT8*)cmdq->DataPtr) + 8 + framesize, 0x0, cmdq->NLsize * 16 - framesize - 8); } if (cmdq->inDataType == AUDIO_DATA_TYPE_AC3 || cmdq->inDataType == AUDIO_DATA_TYPE_EAC3) { if (hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_LINEAR ||hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT_PCM) { cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_LINEAR; } else { cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_NONLINEAR; } } else if (cmdq->inDataType == AUDIO_DATA_TYPE_MPEG) { cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_LINEAR; } else if (cmdq->inDataType == AUDIO_DATA_TYPE_DTS) { cmdq->TxType = AUDIO_TX_TYPE_I2S_AND_SPDIF_NONLINEAR; cmdq->NLsize = ((8 + framesize + 15) & ~15);//use NLsize send DTS framesize } else //if(cmdq->inDataType == AUDIO_DATA_TYPE_UNKNOW) { if (hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR) { cmdq->flag = AUDIO_FLAG_REPACKAGE; cmdq->outDataType = AUDIO_DATA_TYPE_UNKNOW; cmdq->TxType = AUDIO_TX_TYPE_ONLY_SPDIF; cmdq->DataSize = (8 + framesize + 15)&~15; // size is 16 bytes aligned. cmdq->ZeroStuffLen = (4 * hp->sample_number - cmdq->DataSize) / 16 - 1; } } } else// if(cmdq->TxType==AUDIO_TX_TYPE_ONLY_I2S) { cmdq->NLsize = 0; } } } else if (hp->path == HDMI_PATH_BYPASS) { if (wbufdsc->Buffer_Full && !wbufdsc->Discontinuous) { validData = true; cmdq->DataSize = hp->bufSize; cmdq->DataPtr = cur_wbuf | 0xa0000000; cmdq->pause = wbufdsc->Pause_Exist; cmdq->discontinue = wbufdsc->Discontinuous; } } if (validData && (wbufdsc->PTS == 0 && wbufdsc->PTS_high == 0)) { hdmidbg("%s: PTS is not normal. Skip the buffer\n", __FUNCTION__); validData = false; } pts_diff = ((wbufdsc->PTS_high << 31) | (wbufdsc->PTS >> 1)) - hp->pPts; if (validData && !pts_diff) { hdmidbg("%s: PTS is decreasing. Skip the buffer\n", __FUNCTION__); validData = false; } if (validData && hp->pPts) { if (verifyFreq(hp, pts_diff) == false) { hdmidbg("%s: Change audio freq to %d\n", __FUNCTION__, hp->Freq); #define Max_Reset_Count 100 if ((hp->path == HDMI_PATH_PARSE) && (Reset_Count < Max_Reset_Count) && (cmdq->inDataType == AUDIO_DATA_TYPE_UNKNOW)) { DRV_HDMI_AudioDisable(); } cmdq->sfreq = AUDIO_freq(hp->Freq); AUDIO_setDelayTime(hp); if (hp->offset_flag) { bReset = true; hp->offset_flag = false; } if(HDMI_RegisterRead(HDMIRX_R_audio_enable) == 0) { DRV_HDMI_AudioEnable(); Reset_Count++; hdmidbg("AUDIO_bufChange:Reset_Count=%d\n", Reset_Count); } #define HDMI_RELOCK_TIMEBOUND 0xa if (hp->relock_count++ > HDMI_RELOCK_TIMEBOUND) { AUDIO_ResetLock(); return; } } else { if (hp->Freq == 1) { hdmidbg("Freq is abnormal!!\n"); validData = false; } if ((hp->path == HDMI_PATH_PARSE) && (cmdq->inDataType == AUDIO_DATA_TYPE_UNKNOW)) { Reset_Count = 0; } } } else { validData = false; } cmdq->spdif_channel_status_category_code = HDMI_RegisterRead(HDMIRX_R_ACS_CatC); cmdq->copy_protection = (HDMI_RegisterRead(HDMIRX_R_ACS_CSts) & 0x04) >> 2; cmdq->PTS = wbufdsc->PTS; cmdq->PTS_High = wbufdsc->PTS_high; hp->pPts = (wbufdsc->PTS_high << 31) | (wbufdsc->PTS >> 1); /* Check IEC61937 header in parse mode */ if (validData && hp->path == HDMI_PATH_PARSE) { if (cmdq->inDataType == AUDIO_DATA_TYPE_AC3) { AUDIO_AC3HEADERDATA ac3_header; ac3_header.dw1 = getDW(((UINT8*)cmdq->DataPtr) + 8); ac3_header.dw2 = getDW(((UINT8*)cmdq->DataPtr) + 12); if (ac3_header.syncword != 0x0b77) { validData = false; } else { if (hp->codingMode != ac3_header.acmod) { bReset = true; hp->offset_flag = false; hp->codingMode = ac3_header.acmod; } else { hp->codingMode = ac3_header.acmod; hp->bDualChannel = (hp->codingMode == 0); } } } else if (cmdq->inDataType == AUDIO_DATA_TYPE_MPEG) { AUDIO_MPEGHEADERDATA mpeg_header; mpeg_header.dw = getDW(((UINT8*)cmdq->DataPtr) + 8); if ((mpeg_header.dw & 0xfff40000) != 0xfff40000) { validData = false; } else { UINT8 codMode = ((mpeg_header.mode == 2) ? 0 : ((mpeg_header.mode == 3) ? 1 : 2)); if (hp->codingMode != codMode) { bReset = true; hp->offset_flag = false; hp->codingMode = codMode; } else { hp->codingMode = codMode; hp->bDualChannel = (hp->codingMode == 0); } } } else if (cmdq->inDataType == AUDIO_DATA_TYPE_DTS) { validData = true;//jsut not make valiData false; } else { if (cmdq->flag == AUDIO_FLAG_DECODING) { validData = false; } } } else if (validData && hp->path == HDMI_PATH_LINEAR) { UINT8 chcount = HDMI_RegisterRead(HDMIRX_R_Ado_CC) & 0x7; UINT8 spkplace = HDMI_RegisterRead(HDMIRX_R_Ado_CA) & 0x1f; #if 0//CONFIG_HDMI_Support_MULTI_PCM UINT8 cur_chcnt = getChannelCount(spkplace, chcount); UINT8 old_chcnt = getChannelCount(hp->spkplace, hp->chcount); if (old_chcnt != cur_chcnt) { hp->chcount = chcount; hp->spkplace = spkplace; bReset = true; hp->offset_flag = false; cmdq->spkplace = getSpeakerPlacement(spkplace); cmdq->chcnt = cur_chcnt; } #else /* Patch: Only stereo pcm input is allowed. */ if (getChannelCount(spkplace, chcount)) { //validData = false; } #endif } else if (validData && hp->path == HDMI_PATH_BYPASS) { if (hp->audio_stream_type == 0) { hp->audio_stream_type = check_spdif_type((UINT8*)(cur_wbuf | 0xa0000000), hp->bufSize); //hdmidbg("check_spdif_type %d\n",hp->audio_stream_type); switch (hp->audio_stream_type) { case E_SPDIF_TYPE_UNKNOWN: validData = FALSE; break; case E_SPDIF_TYPE_DDP: cmdq->inDataType = cmdq->outDataType = AUDIO_DATA_TYPE_EAC3; break; case E_SPDIF_TYPE_DD: case E_SPDIF_TYPE_OTHERS: default: break; } } } ACP_type = HDMI_RegisterRead(HDMIRX_R_ACP_Type); /* HDMI Source SPDIF OUT fix at SPDIF_WORD_LENGTH_16_BITS */ //cmdq->sample_bit = 0x2;// SPDIF_WORD_LENGTH_16_BITS = 0x2, //HC Modify if((ACP_type == ACP_GENERIC_AUDIO) || (ACP_type == ACP_IEC60958_IDENTIFIED)) { cmdq->copy_protection = 0; // ACP TYPE = 0 1, CP bit = 0, L bit =1 cmdq->spdif_channel_status_category_code = cmdq->spdif_channel_status_category_code | 0x80; } //~HC if (ACP_type_pre != ACP_type) { HDMI_NoticeAudioACP(HDMI_RegisterRead(HDMIRX_R_ACP_Type)); ACP_type_pre = ACP_type; } /* Check ACP Type */ if ((HDMI_RegisterRead(HDMIRX_R_ACP_Type) != ACP_GENERIC_AUDIO && HDMI_RegisterRead(HDMIRX_R_ACP_Type) != ACP_IEC60958_IDENTIFIED) && (hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT || hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR || hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_LINEAR ||hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT_PCM)) { if (hp->TX_path == AUDIO_MENU_SPDIF_OUTPUT) { validData = false; } else { /* Change audio path: parallel linear/non-linear --> Internal speaker */ hp->TX_path = AUDIO_MENU_INTERNAL; cmdq->TxType = AUDIO_TX_TYPE_ONLY_I2S; } } /* Notice Flow control if we support the audio type */ if (!hp->bSupportNotice) { // BOOL bSupported = (cmdq->inDataType != AUDIO_DATA_TYPE_UNKNOW); /* DTS is supported when SDPIF Out is enable */ /* if (!bSupported && cmdq->inDataType == AUDIO_DATA_TYPE_DTS && hp->TX_path == AUDIO_MENU_PARALLEL_SPDIF_NONLINEAR) { bSupported = 1; } */ // HDMI_NoticeAudioTypeSupport(bSupported); hp->bSupportNotice = true; } /* Audio Mute when current control packet contains av mute flag */ if (HDMI_RegisterRead(HDMIRX_R_AV_Mute)) { validData = false; } if (validData) { if (bReset) { bReset = HDMI_AudioResetDecoder() ? false : true; } if (!bReset) { if (!hp->offset_flag) { hp->offset_flag = HDMI_AudioSetOffset(hp->audio_offset, hp->NLdelayCnt); } if (hp->offset_flag) { HDMI_AudioSendCmdq(cmdq); } } } else { /* Software parsing EAC3 frames, don't reset. */ if (hp->offset_flag && hp->sp_non_linear_type != 21) { bReset = true; hp->offset_flag = false; } } hp->wbuf_index = (hp->wbuf_index + 1) % hp->writeBufNum; wbufdsc->b_size = hp->bufSize >> 4; //wbufdsc->Buffer_Valid=0; //wbufdsc->Discontinuous=0; //wbufdsc->Pause_Exist=0; //wbufdsc->Buffer_Full=0; //wbufdsc->b_dlth=0; //wbufdsc->PTS=0; //wbufdsc->PTS_high=0; }