summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNeil Armstrong <narmstrong@baylibre.com>2019-06-12 10:51:47 +0200
committerAndrzej Hajda <a.hajda@samsung.com>2019-07-01 12:33:19 +0200
commitfdbdcc83ffd7d00265a531e71f1d166566c09d66 (patch)
tree26399225c5740d4cbbd01a0a92d1425ebb2ef086 /drivers
parent52c2197aae1b9809830d59bc8f5fa95f7372b0c7 (diff)
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: Neil Armstrong <narmstrong@baylibre.com> Tested-by: Jernej Skrabec <jernej.skrabec@siol.net> Reviewed-by: Jernej Skrabec <jernej.skrabec@siol.net> Tested-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190612085147.26971-1-narmstrong@baylibre.com
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.c45
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index c6490949d9db..218a7b2308f7 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -508,8 +508,14 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
/* nshift factor = 0 */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+ /* Use automatic CTS generation mode when CTS is not set */
+ 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 & 0xff, HDMI_AUD_CTS1);
@@ -579,24 +585,33 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
{
unsigned long ftdms = pixel_clk;
unsigned int n, cts;
+ u8 config3;
u64 tmp;
n = hdmi_compute_n(sample_rate, pixel_clk);
- /*
- * 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
- * note that our TDMS clock is not fully accurate; it is accurate
- * to kHz. This can introduce an unnecessary remainder in the
- * calculation below, so we don't try to warn about that.
- */
- tmp = (u64)ftdms * n;
- do_div(tmp, 128 * sample_rate);
- cts = tmp;
+ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
- dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
- __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000,
- n, cts);
+ /* 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
+ * 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 to kHz. This can introduce an unnecessary remainder
+ * in the calculation below, so we don't try to warn about that.
+ */
+ tmp = (u64)ftdms * n;
+ do_div(tmp, 128 * sample_rate);
+ cts = tmp;
+
+ dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
+ __func__, sample_rate,
+ ftdms / 1000000, (ftdms / 1000) % 1000,
+ n, cts);
+ } else {
+ cts = 0;
+ }
spin_lock_irq(&hdmi->audio_lock);
hdmi->audio_n = n;