Commit fdbdcc83 authored by Neil Armstrong's avatar Neil Armstrong Committed by Andrzej Hajda

drm/bridge: dw-hdmi: Use automatic CTS generation mode when using non-AHB audio

When using an I2S source using a different clock source (usually the I2S
audio HW uses dedicated PLLs, different from the HDMI PHY PLL), fixed
CTS values will cause some frequent audio drop-out and glitches as
reported on Amlogic, Allwinner and Rockchip SoCs setups.

Setting the CTS in automatic mode will let the HDMI controller generate
automatically the CTS value to match the input audio clock.

The DesignWare DW-HDMI User Guide explains:
  For Automatic CTS generation
  Write "0" on the bit field "CTS_manual", Register 0x3205: AUD_CTS3

The DesignWare DW-HDMI Databook explains :
  If "CTS_manual" bit equals 0b this registers contains "audCTS[19:0]"
  generated by the Cycle time counter according to specified timing.

Cc: Jernej Skrabec <jernej.skrabec@siol.net>
Cc: Maxime Ripard <maxime.ripard@bootlin.com>
Cc: Jonas Karlman <jonas@kwiboo.se>
Cc: Heiko Stuebner <heiko@sntech.de>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
Tested-by: default avatarJernej Skrabec <jernej.skrabec@siol.net>
Reviewed-by: default avatarJernej Skrabec <jernej.skrabec@siol.net>
Tested-by: default avatarDouglas Anderson <dianders@chromium.org>
Signed-off-by: default avatarAndrzej Hajda <a.hajda@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190612085147.26971-1-narmstrong@baylibre.com
parent 52c2197a
...@@ -508,8 +508,14 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, ...@@ -508,8 +508,14 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
/* nshift factor = 0 */ /* nshift factor = 0 */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | /* Use automatic CTS generation mode when CTS is not set */
HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); if (cts)
hdmi_writeb(hdmi, ((cts >> 16) &
HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
HDMI_AUD_CTS3_CTS_MANUAL,
HDMI_AUD_CTS3);
else
hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
...@@ -579,24 +585,33 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, ...@@ -579,24 +585,33 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
{ {
unsigned long ftdms = pixel_clk; unsigned long ftdms = pixel_clk;
unsigned int n, cts; unsigned int n, cts;
u8 config3;
u64 tmp; u64 tmp;
n = hdmi_compute_n(sample_rate, pixel_clk); n = hdmi_compute_n(sample_rate, pixel_clk);
config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
/* Only compute CTS when using internal AHB audio */
if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
/* /*
* Compute the CTS value from the N value. Note that CTS and N * Compute the CTS value from the N value. Note that CTS and N
* can be up to 20 bits in total, so we need 64-bit math. Also * can be up to 20 bits in total, so we need 64-bit math. Also
* note that our TDMS clock is not fully accurate; it is accurate * note that our TDMS clock is not fully accurate; it is
* to kHz. This can introduce an unnecessary remainder in the * accurate to kHz. This can introduce an unnecessary remainder
* calculation below, so we don't try to warn about that. * in the calculation below, so we don't try to warn about that.
*/ */
tmp = (u64)ftdms * n; tmp = (u64)ftdms * n;
do_div(tmp, 128 * sample_rate); do_div(tmp, 128 * sample_rate);
cts = tmp; cts = tmp;
dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
__func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000, __func__, sample_rate,
ftdms / 1000000, (ftdms / 1000) % 1000,
n, cts); n, cts);
} else {
cts = 0;
}
spin_lock_irq(&hdmi->audio_lock); spin_lock_irq(&hdmi->audio_lock);
hdmi->audio_n = n; hdmi->audio_n = n;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment