aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSubhransu S. Prusty <subhransu.s.prusty@intel.com>2016-04-14 00:37:30 -0400
committerMark Brown <broonie@kernel.org>2016-04-28 13:49:24 -0400
commitbcced704788312360c0413d13b11611ae00a91c8 (patch)
treea9bea7d9bd5bdf539707cbcf4da2f8c17e7d8f5d
parentb7756edeb7d03b675e10b4862dccc8deb4b0ca17 (diff)
ASoC: hdac_hdmi: Add multichannel support
To support multichannel hdac hdmi driver registers with HDA channel map framework. Channel count and channel slot verbs are programmed by using the chmap helpers/ops. The channel allocation is then programmed in the audio infoframe as per CEA spec. Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/hdac_hdmi.c50
1 files changed, 41 insertions, 9 deletions
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 64ffe93b0f7b..034593bf2cd6 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -29,6 +29,7 @@
29#include <sound/hdaudio_ext.h> 29#include <sound/hdaudio_ext.h>
30#include <sound/hda_i915.h> 30#include <sound/hda_i915.h>
31#include <sound/pcm_drm_eld.h> 31#include <sound/pcm_drm_eld.h>
32#include <sound/hda_chmap.h>
32#include "../../hda/local.h" 33#include "../../hda/local.h"
33#include "hdac_hdmi.h" 34#include "hdac_hdmi.h"
34 35
@@ -82,6 +83,10 @@ struct hdac_hdmi_pin {
82 struct hdac_ext_device *edev; 83 struct hdac_ext_device *edev;
83 int repoll_count; 84 int repoll_count;
84 struct delayed_work work; 85 struct delayed_work work;
86 struct mutex lock;
87 bool chmap_set;
88 unsigned char chmap[8]; /* ALSA API channel-map */
89 int channels; /* current number of channels */
85}; 90};
86 91
87struct hdac_hdmi_pcm { 92struct hdac_hdmi_pcm {
@@ -106,6 +111,7 @@ struct hdac_hdmi_priv {
106 int num_pin; 111 int num_pin;
107 int num_cvt; 112 int num_cvt;
108 struct mutex pin_mutex; 113 struct mutex pin_mutex;
114 struct hdac_chmap chmap;
109}; 115};
110 116
111static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 117static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
@@ -284,26 +290,31 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
284 int i; 290 int i;
285 const u8 *eld_buf; 291 const u8 *eld_buf;
286 u8 conn_type; 292 u8 conn_type;
287 int channels = 2; 293 int channels, ca;
288 294
289 list_for_each_entry(pin, &hdmi->pin_list, head) { 295 list_for_each_entry(pin, &hdmi->pin_list, head) {
290 if (pin->nid == pin_nid) 296 if (pin->nid == pin_nid)
291 break; 297 break;
292 } 298 }
293 299
300 ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc,
301 pin->channels, pin->chmap_set, true, pin->chmap);
302
303 channels = snd_hdac_get_active_channels(ca);
304 hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels);
305
306 snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
307 pin->channels, pin->chmap, pin->chmap_set);
308
294 eld_buf = pin->eld.eld_buffer; 309 eld_buf = pin->eld.eld_buffer;
295 conn_type = drm_eld_get_conn_type(eld_buf); 310 conn_type = drm_eld_get_conn_type(eld_buf);
296 311
297 /* setup channel count */
298 snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
299 AC_VERB_SET_CVT_CHAN_COUNT, channels - 1);
300
301 switch (conn_type) { 312 switch (conn_type) {
302 case DRM_ELD_CONN_TYPE_HDMI: 313 case DRM_ELD_CONN_TYPE_HDMI:
303 hdmi_audio_infoframe_init(&frame); 314 hdmi_audio_infoframe_init(&frame);
304 315
305 /* Default stereo for now */
306 frame.channels = channels; 316 frame.channels = channels;
317 frame.channel_allocation = ca;
307 318
308 ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); 319 ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
309 if (ret < 0) 320 if (ret < 0)
@@ -317,7 +328,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
317 dp_ai.len = 0x1b; 328 dp_ai.len = 0x1b;
318 dp_ai.ver = 0x11 << 2; 329 dp_ai.ver = 0x11 << 2;
319 dp_ai.CC02_CT47 = channels - 1; 330 dp_ai.CC02_CT47 = channels - 1;
320 dp_ai.CA = 0; 331 dp_ai.CA = ca;
321 332
322 dip = (u8 *)&dp_ai; 333 dip = (u8 *)&dp_ai;
323 break; 334 break;
@@ -376,17 +387,23 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
376 struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 387 struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
377 struct hdac_hdmi_priv *hdmi = hdac->private_data; 388 struct hdac_hdmi_priv *hdmi = hdac->private_data;
378 struct hdac_hdmi_dai_pin_map *dai_map; 389 struct hdac_hdmi_dai_pin_map *dai_map;
390 struct hdac_hdmi_pin *pin;
379 struct hdac_ext_dma_params *dd; 391 struct hdac_ext_dma_params *dd;
380 int ret; 392 int ret;
381 393
382 dai_map = &hdmi->dai_map[dai->id]; 394 dai_map = &hdmi->dai_map[dai->id];
395 pin = dai_map->pin;
383 396
384 dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 397 dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
385 dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", 398 dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
386 dd->stream_tag, dd->format); 399 dd->stream_tag, dd->format);
387 400
401 mutex_lock(&pin->lock);
402 pin->channels = substream->runtime->channels;
403
388 ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, 404 ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
389 dai_map->pin->nid); 405 dai_map->pin->nid);
406 mutex_unlock(&pin->lock);
390 if (ret < 0) 407 if (ret < 0)
391 return ret; 408 return ret;
392 409
@@ -646,6 +663,10 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
646 snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, 663 snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
647 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 664 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
648 665
666 mutex_lock(&dai_map->pin->lock);
667 dai_map->pin->channels = 0;
668 mutex_unlock(&dai_map->pin->lock);
669
649 dai_map->pin = NULL; 670 dai_map->pin = NULL;
650 } 671 }
651} 672}
@@ -653,10 +674,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
653static int 674static int
654hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) 675hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
655{ 676{
677 unsigned int chans;
678 struct hdac_ext_device *edev = to_ehdac_device(hdac);
679 struct hdac_hdmi_priv *hdmi = edev->private_data;
656 int err; 680 int err;
657 681
658 /* Only stereo supported as of now */ 682 chans = get_wcaps(hdac, cvt->nid);
659 cvt->params.channels_min = cvt->params.channels_max = 2; 683 chans = get_wcaps_channels(chans);
684
685 cvt->params.channels_min = 2;
686
687 cvt->params.channels_max = chans;
688 if (chans > hdmi->chmap.channels_max)
689 hdmi->chmap.channels_max = chans;
660 690
661 err = snd_hdac_query_supported_pcm(hdac, cvt->nid, 691 err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
662 &cvt->params.rates, 692 &cvt->params.rates,
@@ -1136,6 +1166,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
1136 hdmi->num_pin++; 1166 hdmi->num_pin++;
1137 1167
1138 pin->edev = edev; 1168 pin->edev = edev;
1169 mutex_init(&pin->lock);
1139 INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); 1170 INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
1140 1171
1141 return 0; 1172 return 0;
@@ -1506,6 +1537,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
1506 return -ENOMEM; 1537 return -ENOMEM;
1507 1538
1508 edev->private_data = hdmi_priv; 1539 edev->private_data = hdmi_priv;
1540 snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
1509 1541
1510 dev_set_drvdata(&codec->dev, edev); 1542 dev_set_drvdata(&codec->dev, edev);
1511 1543