[alsa-devel] [PATCH] drm: sti: allow audio playback on HDMI even if disabled.
This fix allows to play audio while HDMI is disconnected. When HDMI is disable, audio configuration is stored and samples are dropped (by HDMI IP). When HDMI is enabled, audio HDMI configuration is applied and samples are outputted on HDMI wire.
Signed-off-by: Arnaud Pouliquen arnaud.pouliquen@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 205 ++++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 104 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 376b076..9c0025e 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -788,6 +788,95 @@ static void sti_hdmi_disable(struct drm_bridge *bridge) hdmi->enabled = false; }
+/** + * sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent + * clocks. None-coherent clocks means that audio and TMDS clocks have not the + * same source (drifts between clocks). In this case assumption is that CTS is + * automatically calculated by hardware. + * + * @audio_fs: audio frame clock frequency in Hz + * + * Values computed are based on table described in HDMI specification 1.4b + * + * Returns n value. + */ +static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs) +{ + unsigned int n; + + switch (audio_fs) { + case 32000: + n = 4096; + break; + case 44100: + n = 6272; + break; + case 48000: + n = 6144; + break; + case 88200: + n = 6272 * 2; + break; + case 96000: + n = 6144 * 2; + break; + case 176400: + n = 6272 * 4; + break; + case 192000: + n = 6144 * 4; + break; + default: + /* Not pre-defined, recommended value: 128 * fs / 1000 */ + n = (audio_fs * 128) / 1000; + } + + return n; +} + +static int hdmi_audio_configure(struct sti_hdmi *hdmi) +{ + int audio_cfg, n; + struct hdmi_audio_params *params = &hdmi->audio; + struct hdmi_audio_infoframe *info = ¶ms->cea; + + DRM_DEBUG_DRIVER("\n"); + + if (!hdmi->enabled) + return 0; + + /* update N parameter */ + n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate); + + DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n", + params->sample_rate, hdmi->mode.clock * 1000, n); + hdmi_write(hdmi, n, HDMI_AUDN); + + /* update HDMI registers according to configuration */ + audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID | + HDMI_AUD_CFG_ONE_BIT_INVALID; + + switch (info->channels) { + case 8: + audio_cfg |= HDMI_AUD_CFG_CH78_VALID; + case 6: + audio_cfg |= HDMI_AUD_CFG_CH56_VALID; + case 4: + audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH; + case 2: + audio_cfg |= HDMI_AUD_CFG_CH12_VALID; + break; + default: + DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n", + info->channels); + return -EINVAL; + } + + hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG); + + return hdmi_audio_infoframe_config(hdmi); +} + static void sti_hdmi_pre_enable(struct drm_bridge *bridge) { struct sti_hdmi *hdmi = bridge->driver_private; @@ -826,9 +915,12 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge) if (hdmi_avi_infoframe_config(hdmi)) DRM_ERROR("Unable to configure AVI infoframe\n");
- /* Program AUDIO infoframe */ - if (hdmi_audio_infoframe_config(hdmi)) - DRM_ERROR("Unable to configure AUDIO infoframe\n"); + if (hdmi->audio.enabled) { + if (hdmi_audio_configure(hdmi)) + DRM_ERROR("Unable to configure audio\n"); + } else { + hdmi_audio_infoframe_config(hdmi); + }
/* Program VS infoframe */ if (hdmi_vendor_infoframe_config(hdmi)) @@ -1078,97 +1170,6 @@ static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) return NULL; }
-/** - * sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent - * clocks. None-coherent clocks means that audio and TMDS clocks have not the - * same source (drifts between clocks). In this case assumption is that CTS is - * automatically calculated by hardware. - * - * @audio_fs: audio frame clock frequency in Hz - * - * Values computed are based on table described in HDMI specification 1.4b - * - * Returns n value. - */ -static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs) -{ - unsigned int n; - - switch (audio_fs) { - case 32000: - n = 4096; - break; - case 44100: - n = 6272; - break; - case 48000: - n = 6144; - break; - case 88200: - n = 6272 * 2; - break; - case 96000: - n = 6144 * 2; - break; - case 176400: - n = 6272 * 4; - break; - case 192000: - n = 6144 * 4; - break; - default: - /* Not pre-defined, recommended value: 128 * fs / 1000 */ - n = (audio_fs * 128) / 1000; - } - - return n; -} - -static int hdmi_audio_configure(struct sti_hdmi *hdmi, - struct hdmi_audio_params *params) -{ - int audio_cfg, n; - struct hdmi_audio_infoframe *info = ¶ms->cea; - - DRM_DEBUG_DRIVER("\n"); - - if (!hdmi->enabled) - return 0; - - /* update N parameter */ - n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate); - - DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n", - params->sample_rate, hdmi->mode.clock * 1000, n); - hdmi_write(hdmi, n, HDMI_AUDN); - - /* update HDMI registers according to configuration */ - audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID | - HDMI_AUD_CFG_ONE_BIT_INVALID; - - switch (info->channels) { - case 8: - audio_cfg |= HDMI_AUD_CFG_CH78_VALID; - case 6: - audio_cfg |= HDMI_AUD_CFG_CH56_VALID; - case 4: - audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH; - case 2: - audio_cfg |= HDMI_AUD_CFG_CH12_VALID; - break; - default: - DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n", - info->channels); - return -EINVAL; - } - - hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG); - - hdmi->audio = *params; - - return hdmi_audio_infoframe_config(hdmi); -} - static void hdmi_audio_shutdown(struct device *dev, void *data) { struct sti_hdmi *hdmi = dev_get_drvdata(dev); @@ -1192,17 +1193,9 @@ static int hdmi_audio_hw_params(struct device *dev, { struct sti_hdmi *hdmi = dev_get_drvdata(dev); int ret; - struct hdmi_audio_params audio = { - .sample_width = params->sample_width, - .sample_rate = params->sample_rate, - .cea = params->cea, - };
DRM_DEBUG_DRIVER("\n");
- if (!hdmi->enabled) - return 0; - if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv || daifmt->frame_clk_inv || daifmt->bit_clk_master || daifmt->frame_clk_master) { @@ -1213,9 +1206,13 @@ static int hdmi_audio_hw_params(struct device *dev, return -EINVAL; }
- audio.enabled = true; + hdmi->audio.sample_width = params->sample_width; + hdmi->audio.sample_rate = params->sample_rate; + hdmi->audio.cea = params->cea; + + hdmi->audio.enabled = true;
- ret = hdmi_audio_configure(hdmi, &audio); + ret = hdmi_audio_configure(hdmi); if (ret < 0) return ret;
Acked-by: Vincent Abriou vincent.abriou@st.com
On 09/30/2016 05:17 PM, Arnaud Pouliquen wrote:
This fix allows to play audio while HDMI is disconnected. When HDMI is disable, audio configuration is stored and samples are dropped (by HDMI IP). When HDMI is enabled, audio HDMI configuration is applied and samples are outputted on HDMI wire.
Signed-off-by: Arnaud Pouliquen arnaud.pouliquen@st.com
drivers/gpu/drm/sti/sti_hdmi.c | 205 ++++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 104 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 376b076..9c0025e 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -788,6 +788,95 @@ static void sti_hdmi_disable(struct drm_bridge *bridge) hdmi->enabled = false; }
+/**
- sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent
- clocks. None-coherent clocks means that audio and TMDS clocks have not the
- same source (drifts between clocks). In this case assumption is that CTS is
- automatically calculated by hardware.
- @audio_fs: audio frame clock frequency in Hz
- Values computed are based on table described in HDMI specification 1.4b
- Returns n value.
- */
+static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs) +{
- unsigned int n;
- switch (audio_fs) {
- case 32000:
n = 4096;
break;
- case 44100:
n = 6272;
break;
- case 48000:
n = 6144;
break;
- case 88200:
n = 6272 * 2;
break;
- case 96000:
n = 6144 * 2;
break;
- case 176400:
n = 6272 * 4;
break;
- case 192000:
n = 6144 * 4;
break;
- default:
/* Not pre-defined, recommended value: 128 * fs / 1000 */
n = (audio_fs * 128) / 1000;
- }
- return n;
+}
+static int hdmi_audio_configure(struct sti_hdmi *hdmi) +{
- int audio_cfg, n;
- struct hdmi_audio_params *params = &hdmi->audio;
- struct hdmi_audio_infoframe *info = ¶ms->cea;
- DRM_DEBUG_DRIVER("\n");
- if (!hdmi->enabled)
return 0;
- /* update N parameter */
- n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate);
- DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n",
params->sample_rate, hdmi->mode.clock * 1000, n);
- hdmi_write(hdmi, n, HDMI_AUDN);
- /* update HDMI registers according to configuration */
- audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID |
HDMI_AUD_CFG_ONE_BIT_INVALID;
- switch (info->channels) {
- case 8:
audio_cfg |= HDMI_AUD_CFG_CH78_VALID;
- case 6:
audio_cfg |= HDMI_AUD_CFG_CH56_VALID;
- case 4:
audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH;
- case 2:
audio_cfg |= HDMI_AUD_CFG_CH12_VALID;
break;
- default:
DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n",
info->channels);
return -EINVAL;
- }
- hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
- return hdmi_audio_infoframe_config(hdmi);
+}
static void sti_hdmi_pre_enable(struct drm_bridge *bridge) { struct sti_hdmi *hdmi = bridge->driver_private; @@ -826,9 +915,12 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge) if (hdmi_avi_infoframe_config(hdmi)) DRM_ERROR("Unable to configure AVI infoframe\n");
- /* Program AUDIO infoframe */
- if (hdmi_audio_infoframe_config(hdmi))
DRM_ERROR("Unable to configure AUDIO infoframe\n");
if (hdmi->audio.enabled) {
if (hdmi_audio_configure(hdmi))
DRM_ERROR("Unable to configure audio\n");
} else {
hdmi_audio_infoframe_config(hdmi);
}
/* Program VS infoframe */ if (hdmi_vendor_infoframe_config(hdmi))
@@ -1078,97 +1170,6 @@ static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) return NULL; }
-/**
- sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent
- clocks. None-coherent clocks means that audio and TMDS clocks have not the
- same source (drifts between clocks). In this case assumption is that CTS is
- automatically calculated by hardware.
- @audio_fs: audio frame clock frequency in Hz
- Values computed are based on table described in HDMI specification 1.4b
- Returns n value.
- */
-static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs) -{
- unsigned int n;
- switch (audio_fs) {
- case 32000:
n = 4096;
break;
- case 44100:
n = 6272;
break;
- case 48000:
n = 6144;
break;
- case 88200:
n = 6272 * 2;
break;
- case 96000:
n = 6144 * 2;
break;
- case 176400:
n = 6272 * 4;
break;
- case 192000:
n = 6144 * 4;
break;
- default:
/* Not pre-defined, recommended value: 128 * fs / 1000 */
n = (audio_fs * 128) / 1000;
- }
- return n;
-}
-static int hdmi_audio_configure(struct sti_hdmi *hdmi,
struct hdmi_audio_params *params)
-{
- int audio_cfg, n;
- struct hdmi_audio_infoframe *info = ¶ms->cea;
- DRM_DEBUG_DRIVER("\n");
- if (!hdmi->enabled)
return 0;
- /* update N parameter */
- n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate);
- DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n",
params->sample_rate, hdmi->mode.clock * 1000, n);
- hdmi_write(hdmi, n, HDMI_AUDN);
- /* update HDMI registers according to configuration */
- audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID |
HDMI_AUD_CFG_ONE_BIT_INVALID;
- switch (info->channels) {
- case 8:
audio_cfg |= HDMI_AUD_CFG_CH78_VALID;
- case 6:
audio_cfg |= HDMI_AUD_CFG_CH56_VALID;
- case 4:
audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH;
- case 2:
audio_cfg |= HDMI_AUD_CFG_CH12_VALID;
break;
- default:
DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n",
info->channels);
return -EINVAL;
- }
- hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
- hdmi->audio = *params;
- return hdmi_audio_infoframe_config(hdmi);
-}
static void hdmi_audio_shutdown(struct device *dev, void *data) { struct sti_hdmi *hdmi = dev_get_drvdata(dev); @@ -1192,17 +1193,9 @@ static int hdmi_audio_hw_params(struct device *dev, { struct sti_hdmi *hdmi = dev_get_drvdata(dev); int ret;
struct hdmi_audio_params audio = {
.sample_width = params->sample_width,
.sample_rate = params->sample_rate,
.cea = params->cea,
};
DRM_DEBUG_DRIVER("\n");
if (!hdmi->enabled)
return 0;
if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv || daifmt->frame_clk_inv || daifmt->bit_clk_master || daifmt->frame_clk_master) {
@@ -1213,9 +1206,13 @@ static int hdmi_audio_hw_params(struct device *dev, return -EINVAL; }
- audio.enabled = true;
- hdmi->audio.sample_width = params->sample_width;
- hdmi->audio.sample_rate = params->sample_rate;
- hdmi->audio.cea = params->cea;
- hdmi->audio.enabled = true;
- ret = hdmi_audio_configure(hdmi, &audio);
- ret = hdmi_audio_configure(hdmi); if (ret < 0) return ret;
participants (2)
-
Arnaud Pouliquen
-
Vincent ABRIOU