summaryrefslogtreecommitdiff
path: root/sound/pci/hda/hda_eld.c
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2012-02-08 18:15:50 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2012-03-23 16:07:21 -0700
commit9edeef15b102327c272b90944ec0c8f917abdd40 (patch)
treeb83e84a13206d98fc7fa2a3e88241ef71292bc59 /sound/pci/hda/hda_eld.c
parentf91785d38741e47d90fb0b31da65dfef90349d2b (diff)
ALSA: HDA: Prevent delay in opening hdmi pcm
When monitor is plugged in instead of reading the complete ELD buffer only read the relavant bytes required to update pcm info. Go through the complete ELD buffer once LPCM sad ELD information is updated in ELD structure. This is required to reduce the delay in getting a valid PCM information which in turn delays opening of HDMI PCM stream. Also if a valid LPCM SAD ELD information is not available when hdmi_pcm_open is called then instead of looping inside hdmi_pcm_open return error to unblock other operations. User space should retry to open HDA PCM device after some time. Bug 931930 Bug 913739 Bug 906076 Change-Id: Iaaef3f0e361ae406c92605b056bd4dff9c2b7856 Signed-off-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-on: http://git-master/r/83143 Reviewed-by: Scott Peterson <speterson@nvidia.com> Rebase-Id: Rd6426e5a92645033f7091d3aa02dfaecfec9f560
Diffstat (limited to 'sound/pci/hda/hda_eld.c')
-rw-r--r--sound/pci/hda/hda_eld.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 9c78d83d8e95..2602633f5dcf 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -157,6 +157,22 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
return val;
}
+static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+ int byte_index)
+{
+ unsigned int val;
+
+ val = hdmi_get_eld_data(codec, nid, byte_index);
+
+ if ((val & AC_ELDD_ELD_VALID) == 0) {
+ snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
+ byte_index);
+ val = 0;
+ }
+
+ return val & AC_ELDD_ELD_DATA;
+}
+
#define GRAB_BITS(buf, byte, lowbit, bits) \
({ \
BUILD_BUG_ON(lowbit > 7); \
@@ -312,6 +328,79 @@ out_fail:
return -EINVAL;
}
+#define GET_BITS(val, lowbit, bits) \
+({ \
+ BUILD_BUG_ON(lowbit > 7); \
+ BUILD_BUG_ON(bits > 8); \
+ BUILD_BUG_ON(bits <= 0); \
+ \
+ (val >> (lowbit)) & ((1 << (bits)) - 1); \
+})
+
+/* update ELD information relevant for getting PCM info */
+static int hdmi_update_lpcm_sad_eld (struct hda_codec *codec, hda_nid_t nid,
+ struct hdmi_eld *e, int size)
+{
+ int i, j;
+ u32 val, sad_base;
+ struct cea_sad *a;
+
+ val = hdmi_get_eld_byte(codec, nid, 0);
+ e->eld_ver = GET_BITS(val, 3, 5);
+ if (e->eld_ver != ELD_VER_CEA_861D &&
+ e->eld_ver != ELD_VER_PARTIAL) {
+ snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n",
+ e->eld_ver);
+ goto out_fail;
+ }
+
+ val = hdmi_get_eld_byte(codec, nid, 4);
+ sad_base = GET_BITS(val, 0, 5);
+ sad_base += ELD_FIXED_BYTES;
+
+ val = hdmi_get_eld_byte(codec, nid, 5);
+ e->sad_count = GET_BITS(val, 4, 4);
+
+ for (i = 0; i < e->sad_count; i++, sad_base += 3) {
+ if ((sad_base + 3) > size) {
+ snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i);
+ goto out_fail;
+ }
+ a = &e->sad[i];
+
+ val = hdmi_get_eld_byte(codec, nid, sad_base);
+ a->format = GET_BITS(val, 3, 4);
+ a->channels = GET_BITS(val, 0, 3);
+ a->channels++;
+
+ a->rates = 0;
+ a->sample_bits = 0;
+ a->max_bitrate = 0;
+
+ if (a->format != AUDIO_CODING_TYPE_LPCM)
+ continue;
+
+ val = hdmi_get_eld_byte(codec, nid, sad_base + 1);
+ val = GET_BITS(val, 0, 7);
+ for (j = 0; j < 7; j++)
+ if (val & (1 << j))
+ a->rates |= cea_sampling_frequencies[j + 1];
+
+ val = hdmi_get_eld_byte(codec, nid, sad_base + 2);
+ val = GET_BITS(val, 0, 3);
+ for (j = 0; j < 3; j++)
+ if (val & (1 << j))
+ a->sample_bits |= cea_sample_sizes[j + 1];
+ }
+
+ e->lpcm_sad_ready = 1;
+ return 0;
+
+out_fail:
+ e->eld_ver = 0;
+ return -EINVAL;
+}
+
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
@@ -342,6 +431,9 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
return -ERANGE;
}
+ if (!eld->lpcm_sad_ready)
+ hdmi_update_lpcm_sad_eld(codec, nid, eld, size);
+
/* set ELD buffer */
buf = eld->eld_buffer;