From 3a18e69dfeefcc123933a692aa02ea62e892eec9 Mon Sep 17 00:00:00 2001 From: Zongdong Jiao Date: Thu, 30 Mar 2023 18:44:00 +0800 Subject: [PATCH] hdmitx: fix a special no audio output case [1/1] PD#SWPL-117332 PD#OTT-39191 BUG=266994705 Problem: The HDMI audio ACR parameter will change when audio format change. In this intermediate state, some TVset like Vizio has audio compliance issue and maybe the error correction or handling mechanism of tvset can not cover such kind of glitch data. It will cause no audio output issue for such kind of tvset Solution: From tx side, optimize the intermediate state. In the beginning of audio format change, stop the ACR package send, continue ACR package sending after finish format changing. Meanwhile, only change the ACR related param when setting is difference compared with previous one from audio module callback Verify: issue Vizio TV and other brand TVset in our hand Change-Id: I739acba93590ba4c02c0b4a3f50319fa16ea42cf Signed-off-by: Zongdong Jiao --- .../vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c | 10 ++++- .../vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c | 37 ++++++++++++------- .../media/vout/hdmi_tx/hdmi_tx_module.h | 5 +++ .../vout/hdmitx_common/hdmitx_hw_common.h | 1 + 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/drivers/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c b/drivers/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c index 48b850fba..f1a060f7d 100644 --- a/drivers/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c +++ b/drivers/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c @@ -5953,15 +5953,19 @@ static int hdmitx_notify_callback_a(struct notifier_block *block, hdev->audio_notify_flag = 0; if (hdmitx_set_i2s_mask(aud_param->chs, aud_param->i2s_ch_mask)) hdev->audio_param_update_flag = 1; - pr_info("%s[%d] type:%d rate:%d size:%d chs:%d fifo_rst:%d aud_src_if:%d\n", - __func__, __LINE__, aud_param->type, aud_param->rate, aud_param->size, + pr_info("%s[%d] type:%lu rate:%d size:%d chs:%d fifo_rst:%d aud_src_if:%d\n", + __func__, __LINE__, cmd, n_rate, n_size, aud_param->chs, aud_param->fifo_rst, aud_param->aud_src_if); if (audio_param->sample_rate != n_rate) { + /* if the audio sample rate or type changes, stop ACR firstly */ + hdev->tx_hw.cntlmisc(&hdev->tx_hw, MISC_AUDIO_ACR_CTRL, 0); audio_param->sample_rate = n_rate; hdev->audio_param_update_flag = 1; } if (audio_param->type != cmd) { + /* if the audio sample rate or type changes, stop ACR firstly */ + hdev->tx_hw.cntlmisc(&hdev->tx_hw, MISC_AUDIO_ACR_CTRL, 0); audio_param->type = cmd; pr_info(AUD "aout notify format %s\n", aud_type_string[audio_param->type & 0xff]); @@ -6003,7 +6007,9 @@ static int hdmitx_notify_callback_a(struct notifier_block *block, hdev->audio_param_update_flag) { /* plug-in & update audio param */ if (hdev->tx_comm.hpd_state == 1) { + hdev->aud_notify_update = 1; hdmitx_set_audio(hdev, &hdev->cur_audio_param); + hdev->aud_notify_update = 0; if (hdev->audio_notify_flag == 1 || hdev->audio_step == 1) { hdev->audio_notify_flag = 0; diff --git a/drivers/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c b/drivers/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c index ae996e686..151111dcd 100644 --- a/drivers/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c +++ b/drivers/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c @@ -2656,12 +2656,13 @@ static void set_aud_info_pkt(struct hdmitx_dev *hdev, hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF3, 0); } -static void set_aud_acr_pkt(struct hdmitx_dev *hdev, +static int set_aud_acr_pkt(struct hdmitx_dev *hdev, struct hdmitx_audpara *audio_param) { unsigned int data32; unsigned int aud_n_para; unsigned int char_rate; + static unsigned int pre_aud_n_para; /* audio packetizer config */ hdmitx_wr_reg(HDMITX_DWC_AUD_INPUTCLKFS, audio_param->aud_src_if ? 4 : 0); @@ -2688,7 +2689,6 @@ static void set_aud_acr_pkt(struct hdmitx_dev *hdev, default: break; } - pr_info(HW "aud_n_para = %d\n", aud_n_para); /* ACR packet configuration */ data32 = 0; @@ -2708,10 +2708,19 @@ static void set_aud_acr_pkt(struct hdmitx_dev *hdev, data32 = 0; data32 |= (1 << 7); /* [ 7] ncts_atomic_write */ data32 |= (((aud_n_para >> 16) & 0xf) << 0); /* [3:0] AudN[19:16] */ + /* if only audio module update and previous n_para is same as current + * value, then skip update audio_n_para + */ + if (hdev->aud_notify_update && pre_aud_n_para == aud_n_para) + return 0; + /* update audio_n_para */ + pre_aud_n_para = aud_n_para; hdmitx_wr_reg(HDMITX_DWC_AUD_N3, data32); hdmitx_wr_reg(HDMITX_DWC_AUD_N2, (aud_n_para >> 8) & 0xff); /* AudN[15:8] */ hdmitx_wr_reg(HDMITX_DWC_AUD_N1, aud_n_para & 0xff); /* AudN[7:0] */ + pr_info("update audio N %d", aud_n_para); + return 1; } static void set_aud_fifo_rst(void) @@ -2815,6 +2824,7 @@ static int hdmitx_set_audmode(struct hdmitx_dev *hdev, struct hdmitx_audpara *audio_param) { unsigned int data32; + int acr_update = 0; if (!hdev) return 0; @@ -2892,7 +2902,7 @@ static int hdmitx_set_audmode(struct hdmitx_dev *hdev, hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIF0, data32); set_aud_info_pkt(hdev, audio_param); - set_aud_acr_pkt(hdev, audio_param); + acr_update = set_aud_acr_pkt(hdev, audio_param); set_aud_samp_pkt(hdev, audio_param); set_aud_chnls(hdev, audio_param); @@ -2911,20 +2921,13 @@ static int hdmitx_set_audmode(struct hdmitx_dev *hdev, /* Wait for 40 us for TX I2S decoder to settle */ msleep(20); } - data32 = hdmitx_rd_reg(HDMITX_DWC_FC_PACKET_TX_EN); - pr_debug(HW "[0x10e3] = 0x%x\n", data32); set_aud_fifo_rst(); usleep_range(9, 11); - hdmitx_wr_reg(HDMITX_DWC_AUD_N1, hdmitx_rd_reg(HDMITX_DWC_AUD_N1)); - /* double confirm that ACR packet is enabled - * simultaneously with audio sample packet - */ - data32 = hdmitx_rd_reg(HDMITX_DWC_FC_PACKET_TX_EN); - if ((data32 & 0x9) == 0x8) { - hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 0, 1); - pr_debug(HW "enable ACR: [0x10e3] = 0x%x\n", data32); - } + if (acr_update) + hdmitx_wr_reg(HDMITX_DWC_AUD_N1, hdmitx_rd_reg(HDMITX_DWC_AUD_N1)); hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 1, 0, 1); + usleep_range(4000, 5000); + hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 0, 1); mutex_unlock(&aud_mutex); return 1; @@ -5940,6 +5943,12 @@ static int hdmitx_cntl_misc(struct hdmitx_hw_common *tx_hw, unsigned int cmd, hd_set_reg_bits(pll_cntl, 0, 30, 1); } break; + case MISC_AUDIO_ACR_CTRL: + if (argv == 0) + hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 0, 0, 1); + if (argv == 1) + hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 0, 1); + break; default: break; } diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h index 694049799..7a7d20ba2 100644 --- a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h @@ -407,6 +407,11 @@ struct hdmitx_dev { enum eotf_type hdmi_current_eotf_type; enum mode_type hdmi_current_tunnel_mode; bool hdmi_current_signal_sdr; + /* if switching from 48k pcm to 48k DD, the ACR/N parameter is same, + * so there is no need to update ACR/N. but for mode change, different + * sample rate, need to update ACR/N. + */ + bool aud_notify_update; unsigned int flag_3dfp:1; unsigned int flag_3dtb:1; unsigned int flag_3dss:1; diff --git a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_hw_common.h b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_hw_common.h index e28314de9..4d2b7b9bd 100644 --- a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_hw_common.h +++ b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_hw_common.h @@ -58,6 +58,7 @@ #define MISC_SUSFLAG (CMD_MISC_OFFSET + 0X15) #define MISC_AUDIO_RESET (CMD_MISC_OFFSET + 0x16) #define MISC_DIS_HPLL (CMD_MISC_OFFSET + 0x17) +#define MISC_AUDIO_ACR_CTRL (CMD_MISC_OFFSET + 0x18) /*********************************************************************** * Get State //getstate