[alsa-devel] [PATCH 00/11] ASoC: hdac_hdmi: Add multichannel support
This series parses ELD to identify multichannel capability of the sync, and uses HDA framework to programs codec's channel map registers.
Channel map controls are registered in patch 8, with which user can specify a specific channel order. chmap controls are registered inside jack_init callback. As PCMs need to be registered before registering chmap controls, jack_init call in the machine driver is moved to late_probe instead of init callback.
Skylake driver is modified and buffer size calculation is fixed for multichannel support.
Please note, patch 2 and 4 adds small macros to read speaker allocation from ELD and channel counts from cap bits respectively in DRM and HDA headers. We have CCed DRM folks here. Please ack patch 1, so that we can have this series merged through sound trees. Patch 3 needs Takashi's ack, so that it can be merged through ASoC.
Patch 9 has dependency on commit#44fde3b ("ALSA: hda - Update chmap tlv to report sink's capability) which is merged in Takashi's tree.
So this may be merged in ASoC with Takashi's Ack and pulling in changes from Takashi's tree or alternatively it can be directly merged in Takashi's with Mark's Ack
Takashi/Mark, please decide how you guys want this to be merged.
Cc: Jani Nikula jani.nikula@intel.com Cc: David Airlie airlied@linux.ie Cc: dri-devel@lists.freedesktop.org Cc: Daniel Vetter daniel.vetter@intel.com
Subhransu S. Prusty (11): ASoC: Intel: Skylake: Fix ibs/obs calc for non-integral sampling rates drm/edid: Add API to get speaker allocation ASoC: hdac_hdmi: parse eld for channel map capability ALSA: hda - add helper to get channels from cap bits ASoC: hdac_hdmi: Add multichannel support ASoC: skl_rt286: Fix to support hdmi channel map support ASoC: Intel: boards: Update skl_nau88l25_max98357a driver to support chmap ASoC: Intel: boards: Update skl_nau88l25_ssm4567 driver to support chmap ASoC: hdac_hdmi: Register chmap controls and ops ASoC: Intel: Skylake: Add multichannel support for HDMI ASoC: Intel: Skylake: Update channel map based on runtime params
include/drm/drm_edid.h | 9 ++ sound/hda/local.h | 10 ++ sound/soc/codecs/hdac_hdmi.c | 165 ++++++++++++++++++++++-- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 74 ++++++++++- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 73 ++++++++++- sound/soc/intel/boards/skl_rt286.c | 48 ++++++- sound/soc/intel/skylake/skl-pcm.c | 14 +- sound/soc/intel/skylake/skl-topology.c | 49 +++++-- 8 files changed, 409 insertions(+), 33 deletions(-)
FW expects sampling rate rounded up to next higher integer value when calculating ibs/obs. For example for 44.1k, it should be rounded up to 45 to calculate ibs/obs.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-topology.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 5a85f3a..cdb78b7 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -239,6 +239,7 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, { int multiplier = 1; struct skl_module_fmt *in_fmt, *out_fmt; + int in_rate, out_rate;
/* Since fixups is applied to pin 0 only, ibs, obs needs @@ -249,15 +250,24 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) multiplier = 5; - mcfg->ibs = (in_fmt->s_freq / 1000) * - (mcfg->in_fmt->channels) * - (mcfg->in_fmt->bit_depth >> 3) * - multiplier; - - mcfg->obs = (mcfg->out_fmt->s_freq / 1000) * - (mcfg->out_fmt->channels) * - (mcfg->out_fmt->bit_depth >> 3) * - multiplier; + + if (in_fmt->s_freq % 1000) + in_rate = (in_fmt->s_freq / 1000) + 1; + else + in_rate = (in_fmt->s_freq / 1000); + + mcfg->ibs = in_rate * (mcfg->in_fmt->channels) * + (mcfg->in_fmt->bit_depth >> 3) * + multiplier; + + if (mcfg->out_fmt->s_freq % 1000) + out_rate = (mcfg->out_fmt->s_freq / 1000) + 1; + else + out_rate = (mcfg->out_fmt->s_freq / 1000); + + mcfg->obs = out_rate * (mcfg->out_fmt->channels) * + (mcfg->out_fmt->bit_depth >> 3) * + multiplier; }
static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
The patch
ASoC: Intel: Skylake: Fix ibs/obs calc for non-integral sampling rates
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From f0c8e1d9c4f473dfc771a613b602f1841afe8f8b Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com Date: Tue, 12 Apr 2016 10:31:23 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Fix ibs/obs calc for non-integral sampling rates
FW expects sampling rate rounded up to next higher integer value when calculating ibs/obs. For example for 44.1k, it should be rounded up to 45 to calculate ibs/obs.
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 --- sound/soc/intel/skylake/skl-topology.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 5a85f3a4699b..cdb78b7e5a14 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -239,6 +239,7 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, { int multiplier = 1; struct skl_module_fmt *in_fmt, *out_fmt; + int in_rate, out_rate;
/* Since fixups is applied to pin 0 only, ibs, obs needs @@ -249,15 +250,24 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) multiplier = 5; - mcfg->ibs = (in_fmt->s_freq / 1000) * - (mcfg->in_fmt->channels) * - (mcfg->in_fmt->bit_depth >> 3) * - multiplier; - - mcfg->obs = (mcfg->out_fmt->s_freq / 1000) * - (mcfg->out_fmt->channels) * - (mcfg->out_fmt->bit_depth >> 3) * - multiplier; + + if (in_fmt->s_freq % 1000) + in_rate = (in_fmt->s_freq / 1000) + 1; + else + in_rate = (in_fmt->s_freq / 1000); + + mcfg->ibs = in_rate * (mcfg->in_fmt->channels) * + (mcfg->in_fmt->bit_depth >> 3) * + multiplier; + + if (mcfg->out_fmt->s_freq % 1000) + out_rate = (mcfg->out_fmt->s_freq / 1000) + 1; + else + out_rate = (mcfg->out_fmt->s_freq / 1000); + + mcfg->obs = out_rate * (mcfg->out_fmt->channels) * + (mcfg->out_fmt->bit_depth >> 3) * + multiplier; }
static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Cc: Jani Nikula jani.nikula@intel.com Cc: David Airlie airlied@linux.ie Cc: dri-devel@lists.freedesktop.org Cc: Daniel Vetter daniel.vetter@intel.com --- include/drm/drm_edid.h | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index dec6221..99142d1 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -415,6 +415,15 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; }
+/** + * drm_eld_get_spk_alloc - Get ELD speaker allocation + * @eld: pointer to an eld memory structure + */ +static inline const u8 drm_eld_get_spk_alloc(const uint8_t *eld) +{ + return eld[DRM_ELD_SPEAKER]; +} + struct edid *drm_do_get_edid(struct drm_connector *connector, int (*get_edid_block)(void *data, u8 *buf, unsigned int block, size_t len),
This patch parses ELD speaker allocation data block to find sink's chmap capability.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/codecs/hdac_hdmi.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index aaa038f..9d3b33b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -60,11 +60,17 @@ struct hdac_hdmi_cvt { struct hdac_hdmi_cvt_params params; };
+/* Currently only spk_alloc, more to be added */ +struct hdac_hdmi_parsed_eld { + u8 spk_alloc; +}; + struct hdac_hdmi_eld { bool monitor_present; bool eld_valid; int eld_size; char eld_buffer[ELD_MAX_SIZE]; + struct hdac_hdmi_parsed_eld info; };
struct hdac_hdmi_pin { @@ -1008,6 +1014,12 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); }
+static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev, + struct hdac_hdmi_pin *pin) +{ + pin->eld.info.spk_alloc = drm_eld_get_spk_alloc(pin->eld.eld_buffer); +} + static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) { struct hdac_ext_device *edev = pin->edev; @@ -1065,6 +1077,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
snd_jack_report(pcm->jack, SND_JACK_AVOUT); } + hdac_hdmi_parse_eld(edev, pin);
print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, pin->eld.eld_buffer, pin->eld.eld_size);
This helper is copied from legacy hda driver.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/hda/local.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/sound/hda/local.h b/sound/hda/local.h index d692f41..57f07d7 100644 --- a/sound/hda/local.h +++ b/sound/hda/local.h @@ -16,6 +16,16 @@ static inline int get_wcaps_type(unsigned int wcaps) return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; }
+static inline unsigned int get_wcaps_channels(u32 wcaps) +{ + unsigned int chans; + + chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13; + chans = ((chans << 1) | 1) + 1; + + return chans; +} + extern const struct attribute_group *hdac_dev_attr_groups[]; int hda_widget_sysfs_init(struct hdac_device *codec); void hda_widget_sysfs_exit(struct hdac_device *codec);
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 --- sound/soc/codecs/hdac_hdmi.c | 52 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 9d3b33b..a2f949c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -29,6 +29,7 @@ #include <sound/hdaudio_ext.h> #include <sound/hda_i915.h> #include <sound/pcm_drm_eld.h> +#include <sound/hda_chmap.h> #include "../../hda/local.h" #include "hdac_hdmi.h"
@@ -82,6 +83,10 @@ struct hdac_hdmi_pin { struct hdac_ext_device *edev; int repoll_count; struct delayed_work work; + struct mutex lock; + bool chmap_set; + unsigned char chmap[8]; /* ALSA API channel-map */ + int channels; /* current number of channels */ };
struct hdac_hdmi_pcm { @@ -106,6 +111,7 @@ struct hdac_hdmi_priv { int num_pin; int num_cvt; struct mutex pin_mutex; + struct hdac_chmap chmap; };
static 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, int i; const u8 *eld_buf; u8 conn_type; - int channels = 2; + int channels, ca;
list_for_each_entry(pin, &hdmi->pin_list, head) { if (pin->nid == pin_nid) break; }
+ ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, + pin->channels, pin->chmap_set, true, pin->chmap); + + channels = snd_hdac_get_active_channels(ca); + hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels); + + snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, + pin->channels, pin->chmap, pin->chmap_set); + eld_buf = pin->eld.eld_buffer; conn_type = drm_eld_get_conn_type(eld_buf);
- /* setup channel count */ - snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, channels - 1); - switch (conn_type) { case DRM_ELD_CONN_TYPE_HDMI: hdmi_audio_infoframe_init(&frame);
- /* Default stereo for now */ frame.channels = channels; + frame.channel_allocation = ca;
ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); if (ret < 0) @@ -317,7 +328,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, dp_ai.len = 0x1b; dp_ai.ver = 0x11 << 2; dp_ai.CC02_CT47 = channels - 1; - dp_ai.CA = 0; + dp_ai.CA = ca;
dip = (u8 *)&dp_ai; break; @@ -376,17 +387,23 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_pin *pin; struct hdac_ext_dma_params *dd; int ret;
dai_map = &hdmi->dai_map[dai->id]; + pin = dai_map->pin;
dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", dd->stream_tag, dd->format);
+ mutex_lock(&pin->lock); + pin->channels = substream->runtime->channels; + ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, dai_map->pin->nid); + mutex_unlock(&pin->lock); if (ret < 0) return ret;
@@ -646,6 +663,10 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ mutex_lock(&dai_map->pin->lock); + dai_map->pin->channels = 0; + mutex_unlock(&dai_map->pin->lock); + dai_map->pin = NULL; } } @@ -653,10 +674,21 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, static int hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) { + unsigned int chans; + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; int err;
- /* Only stereo supported as of now */ - cvt->params.channels_min = cvt->params.channels_max = 2; + chans = get_wcaps(hdac, cvt->nid); + chans = get_wcaps_channels(chans); + + cvt->params.channels_min = 2; + + if (chans <= 16) { + cvt->params.channels_max = chans; + if (chans > hdmi->chmap.channels_max) + hdmi->chmap.channels_max = chans; + }
err = snd_hdac_query_supported_pcm(hdac, cvt->nid, &cvt->params.rates, @@ -1136,6 +1168,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) hdmi->num_pin++;
pin->edev = edev; + mutex_init(&pin->lock); INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
return 0; @@ -1501,6 +1534,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) return -ENOMEM;
edev->private_data = hdmi_priv; + snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
dev_set_drvdata(&codec->dev, edev);
- /* Only stereo supported as of now */ - cvt->params.channels_min = cvt->params.channels_max = 2; + chans = get_wcaps(hdac, cvt->nid); + chans = get_wcaps_channels(chans); + + cvt->params.channels_min = 2; + + if (chans <= 16) { + cvt->params.channels_max = chans; + if (chans > hdmi->chmap.channels_max) + hdmi->chmap.channels_max = chans; + }t
Are you sure about this? HDMI can only handle 8 channels in Layout 2. There's no support for 16 ch.
On Tue, Apr 12, 2016 at 07:25:33AM -0500, Pierre-Louis Bossart wrote:
- /* Only stereo supported as of now */
- cvt->params.channels_min = cvt->params.channels_max = 2;
- chans = get_wcaps(hdac, cvt->nid);
- chans = get_wcaps_channels(chans);
- cvt->params.channels_min = 2;
- if (chans <= 16) {
cvt->params.channels_max = chans;
if (chans > hdmi->chmap.channels_max)
hdmi->chmap.channels_max = chans;
- }t
Are you sure about this? HDMI can only handle 8 channels in Layout 2. There's no support for 16 ch.
I copied this change form patch_hdmi.c. From the git history I couldn't find why it is 16 ch. May be Takashi/Mengdong/Libin can confirm on this?
Regards, Subhransu
--
On Tue, 12 Apr 2016 15:36:33 +0200, Subhransu S. Prusty wrote:
On Tue, Apr 12, 2016 at 07:25:33AM -0500, Pierre-Louis Bossart wrote:
- /* Only stereo supported as of now */
- cvt->params.channels_min = cvt->params.channels_max = 2;
- chans = get_wcaps(hdac, cvt->nid);
- chans = get_wcaps_channels(chans);
- cvt->params.channels_min = 2;
- if (chans <= 16) {
cvt->params.channels_max = chans;
if (chans > hdmi->chmap.channels_max)
hdmi->chmap.channels_max = chans;
- }t
Are you sure about this? HDMI can only handle 8 channels in Layout 2. There's no support for 16 ch.
I copied this change form patch_hdmi.c. From the git history I couldn't find why it is 16 ch. May be Takashi/Mengdong/Libin can confirm on this?
It's the max value the HD-audio widget capability bits may give. We don't check about the actual device limit there, only about the codec chip capabilities.
Actually, with the recent code, the check is mostly useless, as it can't be over 16. You can apply it unconditionally.
Takashi
HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler.
The patch following the machine driver changes adds the channel map control in the hdac_hdmi codec driver.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/boards/skl_rt286.c | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 2016397..1e13542 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -30,6 +30,16 @@
static struct snd_soc_jack skylake_headset;
+struct skl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct skl_rt286_private { + struct list_head hdmi_pcm_list; +}; + enum { SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_CP, @@ -142,9 +152,20 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct skl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB + dai->id); + pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static unsigned int rates[] = { @@ -438,6 +459,21 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { }, };
+int skylake_card_late_probe(struct snd_soc_card *card) +{ + struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); + struct skl_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + /* skylake audio machine driver for SPT + RT286S */ static struct snd_soc_card skylake_rt286 = { .name = "skylake-rt286", @@ -451,11 +487,21 @@ static struct snd_soc_card skylake_rt286 = { .dapm_routes = skylake_rt286_map, .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), .fully_routed = true, + .late_probe = skylake_card_late_probe, };
static int skylake_audio_probe(struct platform_device *pdev) { + struct skl_rt286_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + skylake_rt286.dev = &pdev->dev; + snd_soc_card_set_drvdata(&skylake_rt286, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); }
HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 74 ++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 72176b7..9dd3ac6 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -30,6 +30,16 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card;
+struct skl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct skl_nau8825_private { + struct list_head hdmi_pcm_list; +}; + enum { SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_CP, @@ -192,23 +202,56 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) { + struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct skl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; + pcm->codec_dai = dai;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) { + struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct skl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); + pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) { + struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct skl_hdmi_pcm *pcm;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) @@ -534,6 +577,21 @@ static struct snd_soc_dai_link skylake_dais[] = { }, };
+int skylake_card_late_probe(struct snd_soc_card *card) +{ + struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); + struct skl_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + /* skylake audio machine driver for SPT + NAU88L25 */ static struct snd_soc_card skylake_audio_card = { .name = "sklnau8825max", @@ -547,11 +605,21 @@ static struct snd_soc_card skylake_audio_card = { .dapm_routes = skylake_map, .num_dapm_routes = ARRAY_SIZE(skylake_map), .fully_routed = true, + .late_probe = skylake_card_late_probe, };
static int skylake_audio_probe(struct platform_device *pdev) { + struct skl_nau8825_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + skylake_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); }
HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 73 +++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 5f1ca99..968fc74 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -34,6 +34,15 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card;
+struct skl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct skl_nau88125_private { + struct list_head hdmi_pcm_list; +}; enum { SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_CP, @@ -222,24 +231,57 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) { + struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct skl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); + return 0; }
static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) { + struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct skl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; + pcm->codec_dai = dai;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) { + struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct skl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); + pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) @@ -585,6 +627,21 @@ static struct snd_soc_dai_link skylake_dais[] = { }, };
+int skylake_card_late_probe(struct snd_soc_card *card) +{ + struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); + struct skl_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + /* skylake audio machine driver for SPT + NAU88L25 */ static struct snd_soc_card skylake_audio_card = { .name = "sklnau8825adi", @@ -600,11 +657,21 @@ static struct snd_soc_card skylake_audio_card = { .codec_conf = ssm4567_codec_conf, .num_configs = ARRAY_SIZE(ssm4567_codec_conf), .fully_routed = true, + .late_probe = skylake_card_late_probe, };
static int skylake_audio_probe(struct platform_device *pdev) { + struct skl_nau88125_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + skylake_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); }
patches 6,7,8 use the same code to add HDMI to the machine driver. Can this be factored instead of copy/pasted?
On 04/12/2016 12:01 AM, Subhransu S. Prusty wrote:
HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com
sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 73 +++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 5f1ca99..968fc74 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -34,6 +34,15 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card;
+struct skl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
+};
+struct skl_nau88125_private {
- struct list_head hdmi_pcm_list;
+}; enum { SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_CP, @@ -222,24 +231,57 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) {
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai;
- struct skl_hdmi_pcm *pcm;
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
return -ENOMEM;
- pcm->device = SKL_DPCM_AUDIO_HDMI1_PB;
- pcm->codec_dai = dai;
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB);
return 0; }
static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) {
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = SKL_DPCM_AUDIO_HDMI2_PB;
pcm->codec_dai = dai;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB);
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0; }
static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) {
struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai;
struct skl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB);
pcm->device = SKL_DPCM_AUDIO_HDMI3_PB;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0; }
static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
@@ -585,6 +627,21 @@ static struct snd_soc_dai_link skylake_dais[] = { }, };
+int skylake_card_late_probe(struct snd_soc_card *card) +{
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
- struct skl_hdmi_pcm *pcm;
- int err;
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
if (err < 0)
return err;
- }
- return 0;
+}
- /* skylake audio machine driver for SPT + NAU88L25 */ static struct snd_soc_card skylake_audio_card = { .name = "sklnau8825adi",
@@ -600,11 +657,21 @@ static struct snd_soc_card skylake_audio_card = { .codec_conf = ssm4567_codec_conf, .num_configs = ARRAY_SIZE(ssm4567_codec_conf), .fully_routed = true,
.late_probe = skylake_card_late_probe, };
static int skylake_audio_probe(struct platform_device *pdev) {
struct skl_nau88125_private *ctx;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); }
On Tue, Apr 12, 2016 at 07:32:35AM -0500, Pierre-Louis Bossart wrote:
patches 6,7,8 use the same code to add HDMI to the machine driver. Can this be factored instead of copy/pasted?
Agree. This can be factored into a common file. It's not only HDMI which is common to these three files, there are some more code which are common as well. After the multichannel series is merged, I will submit a patch to factor these into a common file.
On 04/12/2016 12:01 AM, Subhransu S. Prusty wrote:
HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com
sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 73 +++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 5f1ca99..968fc74 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -34,6 +34,15 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; +struct skl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
+};
+struct skl_nau88125_private {
- struct list_head hdmi_pcm_list;
+}; enum { SKL_DPCM_AUDIO_PB = 0, SKL_DPCM_AUDIO_CP, @@ -222,24 +231,57 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) {
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai;
- struct skl_hdmi_pcm *pcm;
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
return -ENOMEM;
- pcm->device = SKL_DPCM_AUDIO_HDMI1_PB;
- pcm->codec_dai = dai;
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB);
- return 0;
} static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) {
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai;
- struct skl_hdmi_pcm *pcm;
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
return -ENOMEM;
- pcm->device = SKL_DPCM_AUDIO_HDMI2_PB;
- pcm->codec_dai = dai;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB);
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
- return 0;
} static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) {
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai;
- struct skl_hdmi_pcm *pcm;
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
return -ENOMEM;
- return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB);
- pcm->device = SKL_DPCM_AUDIO_HDMI3_PB;
- pcm->codec_dai = dai;
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
- return 0;
} static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) @@ -585,6 +627,21 @@ static struct snd_soc_dai_link skylake_dais[] = { }, }; +int skylake_card_late_probe(struct snd_soc_card *card) +{
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
- struct skl_hdmi_pcm *pcm;
- int err;
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device);
if (err < 0)
return err;
- }
- return 0;
+}
/* skylake audio machine driver for SPT + NAU88L25 */ static struct snd_soc_card skylake_audio_card = { .name = "sklnau8825adi", @@ -600,11 +657,21 @@ static struct snd_soc_card skylake_audio_card = { .codec_conf = ssm4567_codec_conf, .num_configs = ARRAY_SIZE(ssm4567_codec_conf), .fully_routed = true,
- .late_probe = skylake_card_late_probe,
}; static int skylake_audio_probe(struct platform_device *pdev) {
- struct skl_nau88125_private *ctx;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
- if (!ctx)
return -ENOMEM;
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
- skylake_audio_card.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&skylake_audio_card, ctx); return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
}
--
With this patch, chmap controls are created and user space can set the channel map.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/codecs/hdac_hdmi.c | 100 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index a2f949c..b7c1125 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -114,6 +114,19 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; };
+static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, + int pcm_idx) +{ + struct hdac_hdmi_pcm *pcm; + + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->pcm_id == pcm_idx) + return pcm; + } + + return NULL; +} + static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) { struct hdac_device *hdac = dev_to_hdac_dev(dev); @@ -664,6 +677,8 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
mutex_lock(&dai_map->pin->lock); + dai_map->pin->chmap_set = false; + memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); dai_map->pin->channels = 0; mutex_unlock(&dai_map->pin->lock);
@@ -1388,6 +1403,19 @@ static struct i915_audio_component_audio_ops aops = { .pin_eld_notify = hdac_hdmi_eld_notify_cb, };
+static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, + int device) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->pcm && (rtd->pcm->device == device)) + return rtd->pcm; + } + + return NULL; +} + int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) { char jack_name[NAME_SIZE]; @@ -1397,6 +1425,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; + struct snd_pcm *snd_pcm; + int err;
/* * this is a new PCM device, create new pcm and @@ -1408,6 +1438,18 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt;
+ snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); + if (snd_pcm) { + err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); + if (err < 0) { + dev_err(&edev->hdac.dev, + "chmap control add failed with err: %d for pcm: %d\n", + err, device); + kfree(pcm); + return err; + } + } + list_add_tail(&pcm->head, &hdmi->pcm_list);
sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); @@ -1521,6 +1563,60 @@ static struct snd_soc_codec_driver hdmi_hda_codec = { .idle_bias_off = true, };
+static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + /* chmap is already set to 0 in caller */ + if (!pin) + return; + + memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); +} + +static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap, int prepared) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + mutex_lock(&pin->lock); + pin->chmap_set = true; + memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); + if (prepared) + hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); + mutex_unlock(&pin->lock); +} + +static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + return pin ? true:false; +} + +static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + if (!pin && !pin->eld.eld_valid) + return 0; + + return pin->eld.info.spk_alloc; +} + static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) { struct hdac_device *codec = &edev->hdac; @@ -1535,6 +1631,10 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
edev->private_data = hdmi_priv; snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap); + hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; + hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap; + hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; + hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
dev_set_drvdata(&codec->dev, edev);
The patch
ASoC: hdac_hdmi: Register chmap controls and ops
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 2889099eb8cd0811dc2986643d46c0b62b90eeb4 Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com Date: Thu, 14 Apr 2016 10:07:34 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Register chmap controls and ops
With this patch, chmap controls are created and user space can set the channel map.
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 --- sound/soc/codecs/hdac_hdmi.c | 100 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 034593bf2cd6..0ed39753c871 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -114,6 +114,19 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; };
+static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, + int pcm_idx) +{ + struct hdac_hdmi_pcm *pcm; + + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->pcm_id == pcm_idx) + return pcm; + } + + return NULL; +} + static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) { struct hdac_device *hdac = dev_to_hdac_dev(dev); @@ -664,6 +677,8 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
mutex_lock(&dai_map->pin->lock); + dai_map->pin->chmap_set = false; + memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); dai_map->pin->channels = 0; mutex_unlock(&dai_map->pin->lock);
@@ -1386,6 +1401,19 @@ static struct i915_audio_component_audio_ops aops = { .pin_eld_notify = hdac_hdmi_eld_notify_cb, };
+static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, + int device) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->pcm && (rtd->pcm->device == device)) + return rtd->pcm; + } + + return NULL; +} + int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) { char jack_name[NAME_SIZE]; @@ -1395,6 +1423,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; + struct snd_pcm *snd_pcm; + int err;
/* * this is a new PCM device, create new pcm and @@ -1406,6 +1436,18 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt;
+ snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); + if (snd_pcm) { + err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); + if (err < 0) { + dev_err(&edev->hdac.dev, + "chmap control add failed with err: %d for pcm: %d\n", + err, device); + kfree(pcm); + return err; + } + } + list_add_tail(&pcm->head, &hdmi->pcm_list);
sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); @@ -1524,6 +1566,60 @@ static struct snd_soc_codec_driver hdmi_hda_codec = { .idle_bias_off = true, };
+static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + /* chmap is already set to 0 in caller */ + if (!pin) + return; + + memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); +} + +static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap, int prepared) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + mutex_lock(&pin->lock); + pin->chmap_set = true; + memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); + if (prepared) + hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); + mutex_unlock(&pin->lock); +} + +static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + return pin ? true:false; +} + +static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) +{ + struct hdac_ext_device *edev = to_ehdac_device(hdac); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); + struct hdac_hdmi_pin *pin = pcm->pin; + + if (!pin && !pin->eld.eld_valid) + return 0; + + return pin->eld.info.spk_alloc; +} + static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) { struct hdac_device *codec = &edev->hdac; @@ -1538,6 +1634,10 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
edev->private_data = hdmi_priv; snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap); + hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; + hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap; + hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; + hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
dev_set_drvdata(&codec->dev, edev);
Channel max is changed to 8 from stereo to support multichannel capability for HDMI devices.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-pcm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index dab0900..8de9212 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -51,7 +51,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { .rate_min = 8000, .rate_max = 48000, .channels_min = 1, - .channels_max = HDA_QUAD, + .channels_max = 8, .buffer_bytes_max = AZX_MAX_BUF_SIZE, .period_bytes_min = 128, .period_bytes_max = AZX_MAX_BUF_SIZE / 2, @@ -682,7 +682,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "HDMI1 Playback", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | @@ -697,7 +697,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "HDMI2 Playback", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | @@ -712,7 +712,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "HDMI3 Playback", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | @@ -765,7 +765,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "iDisp1 Tx", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE, @@ -777,7 +777,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "iDisp2 Tx", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | @@ -790,7 +790,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "iDisp3 Tx", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
The patch
ASoC: Intel: Skylake: Add multichannel support for HDMI
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 7e12dc87ac59963cf1765fb8272412db19004987 Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com Date: Thu, 14 Apr 2016 10:07:35 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add multichannel support for HDMI
Channel max is changed to 8 from stereo to support multichannel capability for HDMI devices.
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 --- sound/soc/intel/skylake/skl-pcm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index dab0900eef26..8de921272f71 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -51,7 +51,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { .rate_min = 8000, .rate_max = 48000, .channels_min = 1, - .channels_max = HDA_QUAD, + .channels_max = 8, .buffer_bytes_max = AZX_MAX_BUF_SIZE, .period_bytes_min = 128, .period_bytes_max = AZX_MAX_BUF_SIZE / 2, @@ -682,7 +682,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "HDMI1 Playback", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | @@ -697,7 +697,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "HDMI2 Playback", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | @@ -712,7 +712,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "HDMI3 Playback", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | @@ -765,7 +765,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "iDisp1 Tx", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE, @@ -777,7 +777,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "iDisp2 Tx", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | @@ -790,7 +790,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .playback = { .stream_name = "iDisp3 Tx", .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
Default channel map is set for 2 channels. Fix the channel map based on runtime params to support multichannel.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-topology.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index cdb78b7..1f4fe0e 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -154,13 +154,32 @@ static void skl_dump_mconfig(struct skl_sst *ctx, dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); }
+static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) +{ + int slot_map = 0xFFFFFFFF; + int start_slot = 0; + int i; + + for (i = 0; i < chs; i++) { + /* + * For 2 channels with starting slot as 0, slot map will + * look like 0xFFFFFF10. + */ + slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); + start_slot++; + } + fmt->ch_map = slot_map; +} + static void skl_tplg_update_params(struct skl_module_fmt *fmt, struct skl_pipe_params *params, int fixup) { if (fixup & SKL_RATE_FIXUP_MASK) fmt->s_freq = params->s_freq; - if (fixup & SKL_CH_FIXUP_MASK) + if (fixup & SKL_CH_FIXUP_MASK) { fmt->channels = params->ch; + skl_tplg_update_chmap(fmt, fmt->channels); + } if (fixup & SKL_FMT_FIXUP_MASK) { fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
The patch
ASoC: Intel: Skylake: Update channel map based on runtime params
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From ea5a137d0fe263854ae6267a0fa208c544d83452 Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com Date: Thu, 14 Apr 2016 10:07:36 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Update channel map based on runtime params
Default channel map is set for 2 channels. Fix the channel map based on runtime params to support multichannel.
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 --- sound/soc/intel/skylake/skl-topology.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 545b4e77b8aa..8fceb7a04147 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -154,13 +154,32 @@ static void skl_dump_mconfig(struct skl_sst *ctx, dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); }
+static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) +{ + int slot_map = 0xFFFFFFFF; + int start_slot = 0; + int i; + + for (i = 0; i < chs; i++) { + /* + * For 2 channels with starting slot as 0, slot map will + * look like 0xFFFFFF10. + */ + slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); + start_slot++; + } + fmt->ch_map = slot_map; +} + static void skl_tplg_update_params(struct skl_module_fmt *fmt, struct skl_pipe_params *params, int fixup) { if (fixup & SKL_RATE_FIXUP_MASK) fmt->s_freq = params->s_freq; - if (fixup & SKL_CH_FIXUP_MASK) + if (fixup & SKL_CH_FIXUP_MASK) { fmt->channels = params->ch; + skl_tplg_update_chmap(fmt, fmt->channels); + } if (fixup & SKL_FMT_FIXUP_MASK) { fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
On Tue, 12 Apr 2016 07:01:22 +0200, Subhransu S. Prusty wrote:
This series parses ELD to identify multichannel capability of the sync, and uses HDA framework to programs codec's channel map registers.
Channel map controls are registered in patch 8, with which user can specify a specific channel order. chmap controls are registered inside jack_init callback. As PCMs need to be registered before registering chmap controls, jack_init call in the machine driver is moved to late_probe instead of init callback.
Skylake driver is modified and buffer size calculation is fixed for multichannel support.
Please note, patch 2 and 4 adds small macros to read speaker allocation from ELD and channel counts from cap bits respectively in DRM and HDA headers. We have CCed DRM folks here. Please ack patch 1, so that we can have this series merged through sound trees. Patch 3 needs Takashi's ack, so that it can be merged through ASoC.
Patch 9 has dependency on commit#44fde3b ("ALSA: hda - Update chmap tlv to report sink's capability) which is merged in Takashi's tree.
So this may be merged in ASoC with Takashi's Ack and pulling in changes from Takashi's tree or alternatively it can be directly merged in Takashi's with Mark's Ack
Takashi/Mark, please decide how you guys want this to be merged.
Mark needs to pull my for-next branch beforehand. Or, Mark needs to send a pull request so that I pull Mark's tree, then sync both before applying yours.
But the problem is more complicated because you're changing drm stuff, too. This is usually managed in drm tree. So this cross over three different trees.
And, the change in drm is only this:
--- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -415,6 +415,15 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; }
+/**
- drm_eld_get_spk_alloc - Get ELD speaker allocation
- @eld: pointer to an eld memory structure
- */
+static inline const u8 drm_eld_get_spk_alloc(const uint8_t *eld) +{
- return eld[DRM_ELD_SPEAKER];
+}
Do we really need this? Even the direct reference is pretty much obvious. e.g. I see no big difference between two lines below: spk_alloc = drm_eld_get_spk_alloc(some_eld); spk_alloc = some_eld[DRM_ELD_SPAEKER];
thanks,
Takashi
On Tue, Apr 12, 2016 at 07:43:59AM +0200, Takashi Iwai wrote:
But the problem is more complicated because you're changing drm stuff, too. This is usually managed in drm tree. So this cross over three different trees.
The DRM folks tend to leave this up to us, or at least review on any of these crossover patches has been extremely light.
Do we really need this? Even the direct reference is pretty much obvious. e.g. I see no big difference between two lines below: spk_alloc = drm_eld_get_spk_alloc(some_eld); spk_alloc = some_eld[DRM_ELD_SPAEKER];
That'd make things even easier of course.
On Tue, Apr 12, 2016 at 06:54:35AM +0100, Mark Brown wrote:
On Tue, Apr 12, 2016 at 07:43:59AM +0200, Takashi Iwai wrote:
But the problem is more complicated because you're changing drm stuff, too. This is usually managed in drm tree. So this cross over three different trees.
The DRM folks tend to leave this up to us, or at least review on any of these crossover patches has been extremely light.
Do we really need this? Even the direct reference is pretty much obvious. e.g. I see no big difference between two lines below: spk_alloc = drm_eld_get_spk_alloc(some_eld); spk_alloc = some_eld[DRM_ELD_SPAEKER];
That'd make things even easier of course.
Takashi/Mark, Thanks for the review. Agree, accomodating in the driver is easier and the inline function doesn't make much difference. I will accomodate the change in the driver itself.
Shall I repost the series with these changes, which can be reviewed further or wait for more review comments before reposting?
Regards, Subhransu
--
On Tue, Apr 12, 2016 at 11:56:11AM +0530, Subhransu S. Prusty wrote:
Shall I repost the series with these changes, which can be reviewed further or wait for more review comments before reposting?
I don't mind. I did already apply the first patch as a fix.
participants (4)
-
Mark Brown
-
Pierre-Louis Bossart
-
Subhransu S. Prusty
-
Takashi Iwai