Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/bridge: dw-hdmi: handle ELD when DRM_BRIDGE_ATTACH_NO_CONNECTOR

The current ELD handling takes the internal connector ELD buffer and
shares it to the I2S and AHB sub-driver.

But with DRM_BRIDGE_ATTACH_NO_CONNECTOR, the connector is created
elsewhere (or not), and an eventual connector is known only
if the bridge chain up to a connector is enabled.

The current dw-hdmi code gets the current connector from
atomic_enable() so use the already stored connector pointer and
replace the buffer pointer with a callback returning the current
connector ELD buffer.

Since a connector is not always available, either pass an empty
ELD to the alsa HDMI driver or don't call snd_pcm_hw_constraint_eld()
in AHB driver.

Reported-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
[narmstrong: fixed typo in commit log]
Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211029135947.3022875-1-narmstrong@baylibre.com

+27 -8
+7 -3
drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
··· 320 320 struct snd_pcm_runtime *runtime = substream->runtime; 321 321 struct snd_dw_hdmi *dw = substream->private_data; 322 322 void __iomem *base = dw->data.base; 323 + u8 *eld; 323 324 int ret; 324 325 325 326 runtime->hw = dw_hdmi_hw; 326 327 327 - ret = snd_pcm_hw_constraint_eld(runtime, dw->data.eld); 328 - if (ret < 0) 329 - return ret; 328 + eld = dw->data.get_eld(dw->data.hdmi); 329 + if (eld) { 330 + ret = snd_pcm_hw_constraint_eld(runtime, eld); 331 + if (ret < 0) 332 + return ret; 333 + } 330 334 331 335 ret = snd_pcm_limit_hw_rates(runtime); 332 336 if (ret < 0)
+2 -2
drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h
··· 9 9 void __iomem *base; 10 10 int irq; 11 11 struct dw_hdmi *hdmi; 12 - u8 *eld; 12 + u8 *(*get_eld)(struct dw_hdmi *hdmi); 13 13 }; 14 14 15 15 struct dw_hdmi_i2s_audio_data { 16 16 struct dw_hdmi *hdmi; 17 - u8 *eld; 18 17 19 18 void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); 20 19 u8 (*read)(struct dw_hdmi *hdmi, int offset); 20 + u8 *(*get_eld)(struct dw_hdmi *hdmi); 21 21 }; 22 22 23 23 #endif
+8 -1
drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
··· 135 135 size_t len) 136 136 { 137 137 struct dw_hdmi_i2s_audio_data *audio = data; 138 + u8 *eld; 138 139 139 - memcpy(buf, audio->eld, min_t(size_t, MAX_ELD_BYTES, len)); 140 + eld = audio->get_eld(audio->hdmi); 141 + if (eld) 142 + memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len)); 143 + else 144 + /* Pass en empty ELD if connector not available */ 145 + memset(buf, 0, len); 146 + 140 147 return 0; 141 148 } 142 149
+10 -2
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
··· 757 757 hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); 758 758 } 759 759 760 + static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi) 761 + { 762 + if (!hdmi->curr_conn) 763 + return NULL; 764 + 765 + return hdmi->curr_conn->eld; 766 + } 767 + 760 768 static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) 761 769 { 762 770 hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); ··· 3440 3432 audio.base = hdmi->regs; 3441 3433 audio.irq = irq; 3442 3434 audio.hdmi = hdmi; 3443 - audio.eld = hdmi->connector.eld; 3435 + audio.get_eld = hdmi_audio_get_eld; 3444 3436 hdmi->enable_audio = dw_hdmi_ahb_audio_enable; 3445 3437 hdmi->disable_audio = dw_hdmi_ahb_audio_disable; 3446 3438 ··· 3453 3445 struct dw_hdmi_i2s_audio_data audio; 3454 3446 3455 3447 audio.hdmi = hdmi; 3456 - audio.eld = hdmi->connector.eld; 3448 + audio.get_eld = hdmi_audio_get_eld; 3457 3449 audio.write = hdmi_writeb; 3458 3450 audio.read = hdmi_readb; 3459 3451 hdmi->enable_audio = dw_hdmi_i2s_audio_enable;