diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-i2s-audio.c index 1e069f68695e..82d2d5a1cb60 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp-i2s-audio.c @@ -69,6 +69,11 @@ static int dw_hdmi_qp_i2s_hw_params(struct device *dev, void *data, /* Reset the audio data path of the AVP */ hdmi_write(audio, AVP_DATAPATH_PACKET_AUDIO_SWINIT_P, GLOBAL_SWRESET_REQUEST); + /* Disable AUDS, ACR, AUDI */ + hdmi_mod(audio, 0, + PKTSCHED_ACR_TX_EN | PKTSCHED_AUDS_TX_EN | PKTSCHED_AUDI_TX_EN, + PKTSCHED_PKT_EN); + /* Clear the audio FIFO */ hdmi_write(audio, AUDIO_FIFO_CLR_P, AUDIO_INTERFACE_CONTROL0); @@ -141,12 +146,22 @@ static int dw_hdmi_qp_i2s_audio_startup(struct device *dev, void *data) static void dw_hdmi_qp_i2s_audio_shutdown(struct device *dev, void *data) { struct dw_hdmi_qp_i2s_audio_data *audio = data; - struct dw_hdmi_qp *hdmi = audio->hdmi; if (is_dw_hdmi_qp_clk_off(audio)) return; - dw_hdmi_qp_audio_disable(hdmi); + /* + * Keep ACR, AUDI, AUDS packet always on to make SINK device + * active for better compatibility and user experience. + * + * This also fix POP sound on some SINK devices which wakeup + * from suspend to active. + */ + hdmi_mod(audio, I2S_BPCUV_RCV_DIS, I2S_BPCUV_RCV_MSK, + AUDIO_INTERFACE_CONFIG0); + hdmi_mod(audio, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, + AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK, + AUDPKT_CONTROL0); } static int dw_hdmi_qp_i2s_get_eld(struct device *dev, void *data, uint8_t *buf, diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 1c4f4419325a..4fd1868f3ee9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -471,9 +471,38 @@ void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi, return; } - /* Set channel status */ - hdmi_writel(hdmi, channel_status[3] | (channel_status[4] << 8), - AUDPKT_CHSTATUS_OVR1); + /* + * AUDPKT_CHSTATUS_OVR0: { RSV, RSV, CS1, CS0 } + * AUDPKT_CHSTATUS_OVR1: { CS6, CS5, CS4, CS3 } + * + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * CS0: | Mode | d | c | b | a | + * CS1: | Category Code | + * CS2: | Channel Number | Source Number | + * CS3: | Clock Accuracy | Sample Freq | + * CS4: | Ori Sample Freq | Word Length | + * CS5: | | CGMS-A | + * CS6~CS23: Reserved + * + * a: use of channel status block + * b: linear PCM identification: 0 for lpcm, 1 for nlpcm + * c: copyright information + * d: additional format information + */ + + if (ref2stream) + channel_status[0] |= IEC958_AES0_NONAUDIO; + + if ((hdmi_readl(hdmi, AUDIO_INTERFACE_CONFIG0) & GENMASK(25, 24)) == AUD_HBR) { + /* fixup cs for HBR */ + channel_status[3] = (channel_status[3] & 0xf0) | IEC958_AES3_CON_FS_768000; + channel_status[4] = (channel_status[4] & 0x0f) | IEC958_AES4_CON_ORIGFS_NOTID; + } + + hdmi_writel(hdmi, channel_status[0] | (channel_status[1] << 8), + AUDPKT_CHSTATUS_OVR0); + + regmap_bulk_write(hdmi->regm, AUDPKT_CHSTATUS_OVR1, &channel_status[3], 1); if (ref2stream) hdmi_modb(hdmi, 0,