[alsa-devel] [RFC 00/16] ASoC: hdac_hdmi: Add Support to Enable MST Audio
From: Jeeja KP jeeja.kp@intel.com
Display port 1.2 introduces new capability Multi-stream transport (MST) which will allow multiple stream to route to single display port where multiple monitors are connected. Multiple monitors will be connected by a MST Hub or a monitor capable of daisy-chaining.
With MST support, a pin can support multiple ports and on each port a monitor can be connected.
This patch series enables DP MST Audio by extending the current design from pin to port. 1. With MST, Pin mux for CVT selection will be used to select CVT for Pin-port instead of Pin. So create the pin muxes accordingly. 2. Pin is marked as MST capable when connect event reports pipe as valid. if pipe is -1, then pin is not MST capable and default to port 0. if pipe is valid, then pin is MST capable and port = pipe. 3. For MST capable pin, select the device entry before configuring the pin widget verbs controlling the sink device operations. 4. Add support to handle multiple Port mapped to same converter by enabling all the ports and configuring the port when stream is prepared. 5. i915 acomp APIs are now used to read the ELD info and support is extended for MST port as well
Notes: 1. When Mutiple ports are mapped to same PCM, currenlty stream constrains will applied based on first port mapped.
Jeeja KP (15): ASoC: hdac_hdmi: Begin to add support for DP Multi-stream Audio ASoC: Intel: Skylake: Add route change to rt286 machine ASoC: Intel: Skylake: Add route change to nau88l25_max98357a machine ASoC: Intel: Skylake: Add route change to nau88l25_ssm4567 machine ASoC: Intel: Skylake: Add route change to rt298 machine ASoC: Intel: Skylake: Add route change to da7219_max98357a machine ASoC: hdac_hdmi: Add support to handle MST capable pin ASoC: hdac_hdmi: Add MST verb support ASoc: hdac_hdmi: Configure pin verbs for MST ASoC: hdac_hdmi: Add support to handle Multiple Port to same PCM ASoC: Intel: Skylake: To support MST, add HDMI routes rt286 machine ASoC: Intel: Skylake: To support MST, add HDMI routes nau_max machine ASoC: Intel: Skylake: To support MST, add HDMI routes nau_ssm machine ASoC: Intel: Skylake: To support MST, add HDMI routes rt298 machine ASoC: Intel: Skylake: To support MST, add HDMI routes da7219_max machine
Sandeep Tayal (1): ASoC: hdac_hdmi: use audio component framework to read ELD
sound/soc/codecs/hdac_hdmi.c | 919 ++++++++++++++---------- sound/soc/intel/boards/bxt_da7219_max98357a.c | 10 +- sound/soc/intel/boards/bxt_rt298.c | 11 +- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 12 +- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 13 +- sound/soc/intel/boards/skl_rt286.c | 10 +- 6 files changed, 597 insertions(+), 378 deletions(-)
From: Sandeep Tayal sandeepx.tayal@intel.com
With codec read sometimes the pin_sense shows invalid monitor present and eld_valid. Currently driver polls for few times to get the valid ELD data.
To avoid the latency, Instead of reading ELD from codec, read it directly from the display driver using audio component framework.
Removed the direct codec helper functions.
Signed-off-by: Sandeep Tayal sandeepx.tayal@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 201 ++++++++++++------------------------------- 1 file changed, 56 insertions(+), 145 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index dc0129b..c504e98 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -46,6 +46,10 @@ #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20
+#define ELD_VER_CEA_861D 2 +#define ELD_VER_PARTIAL 31 +#define ELD_MAX_MNL 16 + struct hdac_hdmi_cvt_params { unsigned int channels_min; unsigned int channels_max; @@ -81,8 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; 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 */ @@ -173,80 +175,6 @@ format_constraint:
}
- /* HDMI ELD routines */ -static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, - hda_nid_t nid, int byte_index) -{ - unsigned int val; - - val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, - byte_index); - - dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", - byte_index, val); - - return val; -} - -static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) -{ - return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - -/* - * This function queries the ELD size and ELD data and fills in the buffer - * passed by user - */ -static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) -{ - int i, size, ret = 0; - - /* - * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned. - */ - - size = hdac_hdmi_get_eld_size(codec, nid); - if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { - dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); - return -ERANGE; - } - - /* set ELD buffer */ - for (i = 0; i < size; i++) { - unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); - /* - * Graphics driver might be writing to ELD buffer right now. - * Just abort. The caller will repoll after a while. - */ - if (!(val & AC_ELDD_ELD_VALID)) { - dev_err(&codec->dev, - "HDMI: invalid ELD data byte %d\n", i); - ret = -EINVAL; - goto error; - } - val &= AC_ELDD_ELD_DATA; - /* - * The first byte cannot be zero. This can happen on some DVI - * connections. Some Intel chips may also need some 250ms delay - * to return non-zero ELD data, even when the graphics driver - * correctly writes ELD content before setting ELD_valid bit. - */ - if (!val && !i) { - dev_err(&codec->dev, "HDMI: 0 ELD data\n"); - ret = -EINVAL; - goto error; - } - buf[i] = val; - } - - *eld_size = size; -error: - return ret; -} - static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format) @@ -1059,32 +987,59 @@ 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, +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin) { + unsigned int ver, mnl; + + ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + >> DRM_ELD_VER_SHIFT; + + if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { + dev_dbg(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); + return -EINVAL; + } + + mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; + + if (mnl > ELD_MAX_MNL) { + dev_dbg(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); + return -EINVAL; + } + pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + + return 0; }
-static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int val; - - pin->repoll_count = repoll; + int size;
- pm_runtime_get_sync(&edev->hdac.dev); - val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + mutex_lock(&hdmi->pin_mutex); + pin->eld.monitor_present = false;
- dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", - val, pin->nid); + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + &pin->eld.monitor_present, pin->eld.eld_buffer, + ELD_MAX_SIZE);
+ if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(edev, pin) < 0) + size = -EINVAL; + }
- mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); - pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + if (size > 0) { + pin->eld.eld_valid = true; + pin->eld.eld_size = size; + } else { + pin->eld.eld_valid = false; + pin->eld.eld_size = 0; + }
pcm = hdac_hdmi_get_pcm(edev, pin);
@@ -1106,66 +1061,23 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) }
mutex_unlock(&hdmi->pin_mutex); - goto put_hdac_device; + return; }
if (pin->eld.monitor_present && pin->eld.eld_valid) { - /* TODO: use i915 component for reading ELD later */ - if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, - pin->eld.eld_buffer, - &pin->eld.eld_size) == 0) { - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } - hdac_hdmi_parse_eld(edev, pin); - - print_hex_dump_debug("ELD: ", - DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, - true); - } else { - pin->eld.monitor_present = false; - pin->eld.eld_valid = false; - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id);
- snd_jack_report(pcm->jack, 0); - } + snd_jack_report(pcm->jack, SND_JACK_AVOUT); } + + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + pin->eld.eld_buffer, pin->eld.eld_size, false); }
mutex_unlock(&hdmi->pin_mutex); - - /* - * Sometimes the pin_sense may present invalid monitor - * present and eld_valid. If ELD data is not valid, loop few - * more times to get correct pin sense and valid ELD. - */ - if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) - schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); - -put_hdac_device: - pm_runtime_put_sync(&edev->hdac.dev); -} - -static void hdac_hdmi_repoll_eld(struct work_struct *work) -{ - struct hdac_hdmi_pin *pin = - container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); - - /* picked from legacy HDA driver */ - if (pin->repoll_count++ > 6) - pin->repoll_count = 0; - - hdac_hdmi_present_sense(pin, pin->repoll_count); }
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) @@ -1184,7 +1096,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
pin->edev = edev; mutex_init(&pin->lock); - INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
return 0; } @@ -1395,7 +1306,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
list_for_each_entry(pin, &hdmi->pin_list, head) { if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); } }
@@ -1496,7 +1407,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) }
list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
/* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1561,7 +1472,7 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
pm_runtime_put_sync(&edev->hdac.dev); }
The patch
ASoC: hdac_hdmi: use audio component framework to read ELD
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 fe27f4e0545d3fc1b0518fafb4fe0460d757651d Mon Sep 17 00:00:00 2001
From: Sandeep Tayal sandeepx.tayal@intel.com Date: Tue, 20 Sep 2016 19:16:05 +0530 Subject: [PATCH] ASoC: hdac_hdmi: use audio component framework to read ELD
With codec read sometimes the pin_sense shows invalid monitor present and eld_valid. Currently driver polls for few times to get the valid ELD data.
To avoid the latency, Instead of reading ELD from codec, read it directly from the display driver using audio component framework.
Removed the direct codec helper functions.
Signed-off-by: Sandeep Tayal sandeepx.tayal@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 201 ++++++++++++------------------------------- 1 file changed, 56 insertions(+), 145 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 4e181b270d95..537f61aa27fa 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -46,6 +46,10 @@ #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20
+#define ELD_VER_CEA_861D 2 +#define ELD_VER_PARTIAL 31 +#define ELD_MAX_MNL 16 + struct hdac_hdmi_cvt_params { unsigned int channels_min; unsigned int channels_max; @@ -81,8 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; 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 */ @@ -173,80 +175,6 @@ format_constraint:
}
- /* HDMI ELD routines */ -static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, - hda_nid_t nid, int byte_index) -{ - unsigned int val; - - val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, - byte_index); - - dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", - byte_index, val); - - return val; -} - -static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) -{ - return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - -/* - * This function queries the ELD size and ELD data and fills in the buffer - * passed by user - */ -static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) -{ - int i, size, ret = 0; - - /* - * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned. - */ - - size = hdac_hdmi_get_eld_size(codec, nid); - if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { - dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); - return -ERANGE; - } - - /* set ELD buffer */ - for (i = 0; i < size; i++) { - unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); - /* - * Graphics driver might be writing to ELD buffer right now. - * Just abort. The caller will repoll after a while. - */ - if (!(val & AC_ELDD_ELD_VALID)) { - dev_err(&codec->dev, - "HDMI: invalid ELD data byte %d\n", i); - ret = -EINVAL; - goto error; - } - val &= AC_ELDD_ELD_DATA; - /* - * The first byte cannot be zero. This can happen on some DVI - * connections. Some Intel chips may also need some 250ms delay - * to return non-zero ELD data, even when the graphics driver - * correctly writes ELD content before setting ELD_valid bit. - */ - if (!val && !i) { - dev_err(&codec->dev, "HDMI: 0 ELD data\n"); - ret = -EINVAL; - goto error; - } - buf[i] = val; - } - - *eld_size = size; -error: - return ret; -} - static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format) @@ -1059,32 +987,59 @@ 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, +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin) { + unsigned int ver, mnl; + + ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + >> DRM_ELD_VER_SHIFT; + + if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { + dev_dbg(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); + return -EINVAL; + } + + mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; + + if (mnl > ELD_MAX_MNL) { + dev_dbg(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); + return -EINVAL; + } + pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + + return 0; }
-static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int val; - - pin->repoll_count = repoll; + int size;
- pm_runtime_get_sync(&edev->hdac.dev); - val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + mutex_lock(&hdmi->pin_mutex); + pin->eld.monitor_present = false;
- dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", - val, pin->nid); + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + &pin->eld.monitor_present, pin->eld.eld_buffer, + ELD_MAX_SIZE);
+ if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(edev, pin) < 0) + size = -EINVAL; + }
- mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); - pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + if (size > 0) { + pin->eld.eld_valid = true; + pin->eld.eld_size = size; + } else { + pin->eld.eld_valid = false; + pin->eld.eld_size = 0; + }
pcm = hdac_hdmi_get_pcm(edev, pin);
@@ -1106,66 +1061,23 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) }
mutex_unlock(&hdmi->pin_mutex); - goto put_hdac_device; + return; }
if (pin->eld.monitor_present && pin->eld.eld_valid) { - /* TODO: use i915 component for reading ELD later */ - if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, - pin->eld.eld_buffer, - &pin->eld.eld_size) == 0) { - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } - hdac_hdmi_parse_eld(edev, pin); - - print_hex_dump_debug("ELD: ", - DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, - true); - } else { - pin->eld.monitor_present = false; - pin->eld.eld_valid = false; - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id);
- snd_jack_report(pcm->jack, 0); - } + snd_jack_report(pcm->jack, SND_JACK_AVOUT); } + + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + pin->eld.eld_buffer, pin->eld.eld_size, false); }
mutex_unlock(&hdmi->pin_mutex); - - /* - * Sometimes the pin_sense may present invalid monitor - * present and eld_valid. If ELD data is not valid, loop few - * more times to get correct pin sense and valid ELD. - */ - if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) - schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); - -put_hdac_device: - pm_runtime_put_sync(&edev->hdac.dev); -} - -static void hdac_hdmi_repoll_eld(struct work_struct *work) -{ - struct hdac_hdmi_pin *pin = - container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); - - /* picked from legacy HDA driver */ - if (pin->repoll_count++ > 6) - pin->repoll_count = 0; - - hdac_hdmi_present_sense(pin, pin->repoll_count); }
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) @@ -1184,7 +1096,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
pin->edev = edev; mutex_init(&pin->lock); - INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
return 0; } @@ -1395,7 +1306,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
list_for_each_entry(pin, &hdmi->pin_list, head) { if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); } }
@@ -1496,7 +1407,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) }
list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
/* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1561,7 +1472,7 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
pm_runtime_put_sync(&edev->hdac.dev); }
From: Jeeja KP jeeja.kp@intel.com
With MST each pin contains several ports to which device can be connected.
As a preparatory work to support DP MST this patch adds below changes: 1. Defines the port structure and moves all stream related information like ELD, converter list, chmap to port. 2. Creates ports for each pin based on the max_ports support. 3. Based on Pin-Port combination creates DAPM Mux widget instead of Pin to allow user to select a converter. 4. Port zero is the default port when pin does not support MST.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 454 +++++++++++++++++++++++++------------------ 1 file changed, 270 insertions(+), 184 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c504e98..88d6dae 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -81,10 +81,17 @@ struct hdac_hdmi_eld { struct hdac_hdmi_pin { struct list_head head; hda_nid_t nid; + struct hdac_hdmi_port *ports; + int num_ports; + struct hdac_ext_device *edev; +}; + +struct hdac_hdmi_port { + int id; + struct hdac_hdmi_pin *pin; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; - struct hdac_ext_device *edev; struct mutex lock; bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ @@ -94,28 +101,35 @@ struct hdac_hdmi_pin { struct hdac_hdmi_pcm { struct list_head head; int pcm_id; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; };
-struct hdac_hdmi_dai_pin_map { +struct hdac_hdmi_dai_port_map { int dai_id; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; struct hdac_hdmi_cvt *cvt; };
struct hdac_hdmi_priv { - struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; + struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS]; struct list_head pin_list; struct list_head cvt_list; struct list_head pcm_list; int num_pin; int num_cvt; + int num_ports; struct mutex pin_mutex; struct hdac_chmap chmap; };
+static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_port_map *dai_map); + +static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, + struct hdac_hdmi_dai_port_map *dai_map); + static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) { @@ -219,13 +233,14 @@ struct dp_audio_infoframe { };
static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, - hda_nid_t cvt_nid, hda_nid_t pin_nid) + hda_nid_t cvt_nid, hda_nid_t pin_nid, + struct hdac_hdmi_port *port) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; + struct hdac_hdmi_pin *pin; struct dp_audio_infoframe dp_ai; struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_pin *pin; u8 *dip; int ret; int i; @@ -238,16 +253,16 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, break; }
- ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, - pin->channels, pin->chmap_set, true, pin->chmap); + ca = snd_hdac_channel_allocation(&hdac->hdac, port->eld.info.spk_alloc, + port->channels, port->chmap_set, true, port->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); + port->channels, port->chmap, port->chmap_set);
- eld_buf = pin->eld.eld_buffer; + eld_buf = port->eld.eld_buffer; conn_type = drm_eld_get_conn_type(eld_buf);
switch (conn_type) { @@ -307,12 +322,14 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, }
static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) + struct hdac_hdmi_dai_port_map *dai_map, unsigned int pwr_state) { + struct hdac_hdmi_pin *pin = dai_map->port->pin; + /* Power up pin widget */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, + if (!snd_hdac_check_power_state(&edev->hdac, pin->nid, pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, AC_VERB_SET_POWER_STATE, pwr_state);
/* Power up converter */ @@ -327,29 +344,34 @@ 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_hdmi_dai_port_map *dai_map; + struct hdac_hdmi_port *port; struct hdac_ext_dma_params *dd; int ret;
dai_map = &hdmi->dai_map[dai->id]; - pin = dai_map->pin; + port = dai_map->port;
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; + hdac_hdmi_enable_cvt(hdac, dai_map); + ret = hdac_hdmi_enable_pin(hdac, dai_map); + if (ret < 0) + return ret; + + mutex_lock(&port->lock); + port->channels = substream->runtime->channels;
ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, - dai_map->pin->nid); - mutex_unlock(&pin->lock); + port->pin->nid, port); + mutex_unlock(&port->lock); if (ret < 0) return ret;
return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, - dai_map->pin->nid, dd->stream_tag, dd->format); + port->pin->nid, dd->stream_tag, dd->format); }
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, @@ -357,19 +379,20 @@ static int hdac_hdmi_set_hw_params(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_hdmi_dai_port_map *dai_map; + struct hdac_hdmi_port *port; struct hdac_ext_dma_params *dd;
dai_map = &hdmi->dai_map[dai->id]; - pin = dai_map->pin; + port = dai_map->port;
- if (!pin) + if (!port) return -ENODEV;
- if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { - dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n", - pin->nid); + if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { + dev_err(&hdac->hdac.dev, + "device is not configured for this pin:port%d:%d\n", + port->pin->nid, port->id); return -ENODEV; }
@@ -395,7 +418,7 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); struct hdac_ext_dma_params *dd; struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map;
dai_map = &hdmi->dai_map[dai->id];
@@ -410,7 +433,7 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, }
static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map) + struct hdac_hdmi_dai_port_map *dai_map) { /* Enable transmission */ snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, @@ -422,36 +445,37 @@ static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, }
static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, - struct hdac_hdmi_dai_pin_map *dai_map) + struct hdac_hdmi_dai_port_map *dai_map) { int mux_idx; - struct hdac_hdmi_pin *pin = dai_map->pin; + struct hdac_hdmi_port *port = dai_map->port;
- for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) { - if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) { - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + for (mux_idx = 0; mux_idx < port->num_mux_nids; mux_idx++) { + if (port->mux_nids[mux_idx] == dai_map->cvt->nid) { + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, mux_idx); break; } }
- if (mux_idx == pin->num_mux_nids) + if (mux_idx == port->num_mux_nids) return -EIO;
/* Enable out path for this pin widget */ - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
return 0; }
-static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, + struct hdac_hdmi_pin *pin, + struct hdac_hdmi_port *port) { if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { dev_warn(&hdac->hdac.dev, @@ -460,51 +484,52 @@ static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, return -EINVAL; }
- pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, - pin->mux_nids, HDA_MAX_CONNECTIONS); - if (pin->num_mux_nids == 0) - dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", - pin->nid); + port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, + port->mux_nids, HDA_MAX_CONNECTIONS); + if (port->num_mux_nids == 0) + dev_warn(&hdac->hdac.dev, + "No connections found for pin:port %d:%d\n", + pin->nid, port->id);
- dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", - pin->num_mux_nids, pin->nid); + dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n", + port->num_mux_nids, pin->nid, port->id);
- return pin->num_mux_nids; + return port->num_mux_nids; }
/* - * Query pcm list and return pin widget to which stream is routed. + * Query pcm list and return port to which stream is routed. * - * Also query connection list of the pin, to validate the cvt to pin map. + * Also query connection list of the pin, to validate the cvt to port map. * - * Same stream rendering to multiple pins simultaneously can be done - * possibly, but not supported for now in driver. So return the first pin + * Same stream rendering to multiple ports simultaneously can be done + * possibly, but not supported for now in driver. So return the first port * connected. */ -static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( +static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( struct hdac_ext_device *edev, struct hdac_hdmi_priv *hdmi, struct hdac_hdmi_cvt *cvt) { struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_pin *pin = NULL; + struct hdac_hdmi_port *port = NULL; int ret, i;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) { - pin = pcm->pin; + port = pcm->port; break; } }
- if (pin) { - ret = hdac_hdmi_query_pin_connlist(edev, pin); + if (port) { + ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); if (ret < 0) return NULL;
- for (i = 0; i < pin->num_mux_nids; i++) { - if (pin->mux_nids[i] == cvt->nid) - return pin; + for (i = 0; i < port->num_mux_nids; i++) { + if (port->mux_nids[i] == cvt->nid) + return port; } }
@@ -521,53 +546,49 @@ static int hdac_hdmi_pcm_open(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_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; int ret;
dai_map = &hdmi->dai_map[dai->id];
cvt = dai_map->cvt; - pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); + port = hdac_hdmi_get_port_from_cvt(hdac, hdmi, cvt);
/* * To make PA and other userland happy. * userland scans devices so returning error does not help. */ - if (!pin) + if (!port) return 0;
- if ((!pin->eld.monitor_present) || - (!pin->eld.eld_valid)) { + if ((!port->eld.monitor_present) || + (!port->eld.eld_valid)) {
dev_warn(&hdac->hdac.dev, - "Failed: montior present? %d ELD valid?: %d for pin: %d\n", - pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); + "Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n", + port->eld.monitor_present, port->eld.eld_valid, + port->pin->nid, port->id);
return 0; }
- dai_map->pin = pin; - - hdac_hdmi_enable_cvt(hdac, dai_map); - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; + dai_map->port = port;
ret = hdac_hdmi_eld_limit_formats(substream->runtime, - pin->eld.eld_buffer); + port->eld.eld_buffer); if (ret < 0) return ret;
return snd_pcm_hw_constraint_eld(substream->runtime, - pin->eld.eld_buffer); + port->eld.eld_buffer); }
static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; int ret; @@ -589,11 +610,11 @@ static void hdac_hdmi_pcm_close(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_dai_port_map *dai_map;
dai_map = &hdmi->dai_map[dai->id];
- if (dai_map->pin) { + if (dai_map->port) { snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, @@ -601,16 +622,16 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
- snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, + snd_hdac_codec_write(&hdac->hdac, dai_map->port->pin->nid, 0, 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); + mutex_lock(&dai_map->port->lock); + dai_map->port->chmap_set = false; + memset(dai_map->port->chmap, 0, sizeof(dai_map->port->chmap)); + dai_map->port->channels = 0; + mutex_unlock(&dai_map->port->lock);
- dai_map->pin = NULL; + dai_map->port = NULL; } }
@@ -676,13 +697,16 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, }
static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin) + struct hdac_hdmi_port *port) { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (pcm->pin == pin) + if (!pcm->port) + continue; + + if (pcm->port == port) return pcm; }
@@ -692,14 +716,14 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, /* * Based on user selection, map the PINs with the PCMs. */ -static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, +static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_dapm_context *dapm = w->dapm; - struct hdac_hdmi_pin *pin = w->priv; + struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; @@ -709,18 +733,22 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, if (ret < 0) return ret;
+ if (port == NULL) + return -EINVAL; + mutex_lock(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (pcm->pin == pin) - pcm->pin = NULL; + if (!pcm->port && pcm->port == port && + pcm->port->id == port->id) + pcm->port = NULL;
/* * Jack status is not reported during device probe as the * PCMs are not registered by then. So report it here. */ - if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { - pcm->pin = pin; - if (pin->eld.monitor_present && pin->eld.eld_valid) { + if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { + pcm->port = port; + if (port->eld.monitor_present && port->eld.eld_valid) { dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", pcm->pcm_id); @@ -745,12 +773,13 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, * care of selecting the right one and leaving all other inputs selected to * "NONE" */ -static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin, +static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev, + struct hdac_hdmi_port *port, struct snd_soc_dapm_widget *widget, const char *widget_name) { struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin = port->pin; struct snd_kcontrol_new *kc; struct hdac_hdmi_cvt *cvt; struct soc_enum *se; @@ -769,7 +798,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, if (!se) return -ENOMEM;
- sprintf(kc_name, "Pin %d Input", pin->nid); + sprintf(kc_name, "Pin %d port %d Input", pin->nid, port->id); kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); if (!kc->name) return -ENOMEM; @@ -778,7 +807,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc->access = 0; kc->info = snd_soc_info_enum_double; - kc->put = hdac_hdmi_set_pin_mux; + kc->put = hdac_hdmi_set_pin_port_mux; kc->get = snd_soc_dapm_get_enum_double;
se->reg = SND_SOC_NOPM; @@ -806,7 +835,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, return -ENOMEM;
return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, - snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1); + snd_soc_dapm_mux, port, widget_name, NULL, kc, 1); }
/* Add cvt <- input <- mux route map */ @@ -817,10 +846,10 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, struct hdac_hdmi_priv *hdmi = edev->private_data; const struct snd_kcontrol_new *kc; struct soc_enum *se; - int mux_index = hdmi->num_cvt + hdmi->num_pin; + int mux_index = hdmi->num_cvt + hdmi->num_ports; int i, j;
- for (i = 0; i < hdmi->num_pin; i++) { + for (i = 0; i < hdmi->num_ports; i++) { kc = widgets[mux_index].kcontrol_news; se = (struct soc_enum *)kc->private_value; for (j = 0; j < hdmi->num_cvt; j++) { @@ -839,17 +868,18 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, /* * Widgets are added in the below sequence * Converter widgets for num converters enumerated - * Pin widgets for num pins enumerated - * Pin mux widgets to represent connenction list of pin widget + * Pin-port widgets for num ports for Pins enumerated + * Pin-port mux widgets to represent connenction list of pin widget * - * Total widgets elements = num_cvt + num_pin + num_pin; + * For each port, one Mux and One output widget is added + * Total widgets elements = num_cvt + (num_ports * 2); * * Routes are added as below: - * pin mux -> pin (based on num_pins) - * cvt -> "Input sel control" -> pin_mux + * pin-port mux -> pin (based on num_ports) + * cvt -> "Input sel control" -> pin-port_mux * * Total route elements: - * num_pins + (pin_muxes * num_cvt) + * num_ports + (pin_muxes * num_cvt) */ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) { @@ -861,13 +891,13 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) char widget_name[NAME_SIZE]; struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_pin *pin; - int ret, i = 0, num_routes = 0; + int ret, i = 0, num_routes = 0, j;
if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) return -EINVAL;
widgets = devm_kzalloc(dapm->dev, - (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)), + (sizeof(*widgets) * ((2 * hdmi->num_ports) + hdmi->num_cvt)), GFP_KERNEL);
if (!widgets) @@ -885,31 +915,37 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) }
list_for_each_entry(pin, &hdmi->pin_list, head) { - sprintf(widget_name, "hif%d Output", pin->nid); - ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_output, &pin->nid, - widget_name, NULL, NULL, 0); - if (ret < 0) - return ret; - i++; + for (j = 0; j < pin->num_ports; j++) { + sprintf(widget_name, "hif%d-%d Output", + pin->nid, pin->ports[j].id); + ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], + snd_soc_dapm_output, &pin->ports[j].id, + widget_name, NULL, NULL, 0); + if (ret < 0) + return ret; + i++; + } }
/* DAPM widgets to represent the connection list to pin widget */ list_for_each_entry(pin, &hdmi->pin_list, head) { - sprintf(widget_name, "Pin %d Mux", pin->nid); - ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i], - widget_name); - if (ret < 0) - return ret; - i++; + for (j = 0; j < pin->num_ports; j++) { + sprintf(widget_name, "Pin%d-Port%d Mux", + pin->nid, pin->ports[j].id); + ret = hdac_hdmi_create_pin_port_muxs(edev, + &pin->ports[j], &widgets[i], + widget_name); + if (ret < 0) + return ret; + i++;
- /* For cvt to pin_mux mapping */ - num_routes += hdmi->num_cvt; + /* For cvt to pin_mux mapping */ + num_routes += hdmi->num_cvt;
- /* For pin_mux to pin mapping */ - num_routes++; + /* For pin_mux to pin mapping */ + num_routes++; + } } - route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes), GFP_KERNEL); if (!route) @@ -918,20 +954,21 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) i = 0; /* Add pin <- NULL <- mux route map */ list_for_each_entry(pin, &hdmi->pin_list, head) { - int sink_index = i + hdmi->num_cvt; - int src_index = sink_index + hdmi->num_pin; + for (j = 0; j < pin->num_ports; j++) { + int sink_index = i + hdmi->num_cvt; + int src_index = sink_index + pin->num_ports;
- hdac_hdmi_fill_route(&route[i], + hdac_hdmi_fill_route(&route[i], widgets[sink_index].name, NULL, widgets[src_index].name, NULL); - i++; - + i++; + } }
hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
snd_soc_dapm_new_controls(dapm, widgets, - ((2 * hdmi->num_pin) + hdmi->num_cvt)); + ((2 * hdmi->num_ports) + hdmi->num_cvt));
snd_soc_dapm_add_routes(dapm, route, num_routes); snd_soc_dapm_new_widgets(dapm->card); @@ -943,7 +980,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; int dai_id = 0;
@@ -987,12 +1024,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 int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, + struct hdac_hdmi_port *port) { unsigned int ver, mnl;
- ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + ver = (port->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT;
if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { @@ -1000,7 +1037,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, return -EINVAL; }
- mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + mnl = (port->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
if (mnl > ELD_MAX_MNL) { @@ -1008,45 +1045,49 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, return -EINVAL; }
- pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + port->eld.info.spk_alloc = port->eld.eld_buffer[DRM_ELD_SPEAKER];
return 0; }
-static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, + struct hdac_hdmi_port *port) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int size; + int size = 0; + + if (!hdmi) + return;
mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = false; + port->eld.monitor_present = false;
size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, - &pin->eld.monitor_present, pin->eld.eld_buffer, + &port->eld.monitor_present, port->eld.eld_buffer, ELD_MAX_SIZE);
if (size > 0) { size = min(size, ELD_MAX_SIZE); - if (hdac_hdmi_parse_eld(edev, pin) < 0) + if (hdac_hdmi_parse_eld(edev, port) < 0) size = -EINVAL; }
if (size > 0) { - pin->eld.eld_valid = true; - pin->eld.eld_size = size; + port->eld.eld_valid = true; + port->eld.eld_size = size; } else { - pin->eld.eld_valid = false; - pin->eld.eld_size = 0; + port->eld.eld_valid = false; + port->eld.eld_size = 0; }
- pcm = hdac_hdmi_get_pcm(edev, pin); + pcm = hdac_hdmi_get_pcm(edev, port);
- if (!pin->eld.monitor_present || !pin->eld.eld_valid) { + if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", - __func__, pin->nid); + dev_dbg(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", + __func__, pin->nid, port->id);
/* * PCMs are not registered during device probe, so don't @@ -1064,7 +1105,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) return; }
- if (pin->eld.monitor_present && pin->eld.eld_valid) { + if (port->eld.monitor_present && port->eld.eld_valid) { if (pcm) { dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", @@ -1074,28 +1115,53 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) }
print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, false); - } + port->eld.eld_buffer, port->eld.eld_size, false);
+ } mutex_unlock(&hdmi->pin_mutex); }
+static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, + struct hdac_hdmi_pin *pin) +{ + struct hdac_hdmi_port *ports; + int max_ports = 3; /* FIXME this will read from i915 acomp API*/ + int i; + + /*get max ports supported from i915 acomp interface */ + ports = kzalloc(max_ports * sizeof(*ports), GFP_KERNEL); + if (!ports) + return -ENOMEM; + + for (i=0; i < max_ports; i++) { + ports[i].id = i + 1; + ports[i].pin = pin; + mutex_init(&ports[i].lock); + } + pin->ports = ports; + pin->num_ports = max_ports; + return 0; +} + static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pin *pin; + int ret;
pin = kzalloc(sizeof(*pin), GFP_KERNEL); if (!pin) return -ENOMEM;
pin->nid = nid; + pin->edev = edev; + ret = hdac_hdmi_add_ports(hdmi, pin); + if (ret < 0) + return ret;
list_add_tail(&pin->head, &hdmi->pin_list); hdmi->num_pin++; - - pin->edev = edev; - mutex_init(&pin->lock); + hdmi->num_ports += pin->num_ports;
return 0; } @@ -1279,17 +1345,19 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, return hdac_hdmi_init_dai_map(edev); }
-static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) +static void hdac_hdmi_eld_notify_cb(void *aptr, int dport, int pipe) { struct hdac_ext_device *edev = aptr; struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_pin *pin = NULL; + struct hdac_hdmi_port *port = NULL; struct snd_soc_codec *codec = edev->scodec;
/* Don't know how this mapping is derived */ - hda_nid_t pin_nid = port + 0x04; + hda_nid_t pin_nid = dport + 0x04;
- dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); + dev_dbg(&edev->hdac.dev, "%s: for pin:%d port=%d\n", __func__, + pin_nid, pipe);
/* * skip notification during system suspend (but not in runtime PM); @@ -1305,9 +1373,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) return;
list_for_each_entry(pin, &hdmi->pin_list, head) { - if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin); + if (pin->nid != pin_nid) + continue; + + if (pipe == -1) { + /* if not MST, default is port[0] */ + port = &pin->ports[0]; + break; + } } + + if (port) + hdac_hdmi_present_sense(pin, port); }
static struct i915_audio_component_audio_ops aops = { @@ -1378,7 +1455,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; - int ret; + int ret, i;
edev->scodec = codec;
@@ -1407,7 +1484,8 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) }
list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin); + for (i = 0; i < pin->num_ports; i++) + hdac_hdmi_present_sense(pin, &pin->ports[i]);
/* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1458,6 +1536,7 @@ static void hdmi_codec_complete(struct device *dev) struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pin *pin; struct hdac_device *hdac = &edev->hdac; + int i;
/* Power up afg */ snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, @@ -1472,7 +1551,8 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin); + for (i = 0; i < pin->num_ports; i++) + hdac_hdmi_present_sense(pin, &pin->ports[i]);
pm_runtime_put_sync(&edev->hdac.dev); } @@ -1493,13 +1573,13 @@ static void hdac_hdmi_get_chmap(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; + struct hdac_hdmi_port *port = pcm->port;
/* chmap is already set to 0 in caller */ - if (!pin) + if (!port) return;
- memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); + memcpy(chmap, port->chmap, ARRAY_SIZE(port->chmap)); }
static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, @@ -1508,14 +1588,16 @@ static void hdac_hdmi_set_chmap(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; + struct hdac_hdmi_port *port = pcm->port; + struct hdac_hdmi_pin *pin = port->pin;
- mutex_lock(&pin->lock); - pin->chmap_set = true; - memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); + mutex_lock(&port->lock); + port->chmap_set = true; + memcpy(port->chmap, chmap, ARRAY_SIZE(port->chmap)); if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); - mutex_unlock(&pin->lock); + hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, + pin->nid, port); + mutex_unlock(&port->lock); }
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) @@ -1523,9 +1605,9 @@ 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; + struct hdac_hdmi_port *port = pcm->port;
- return pin ? true:false; + return port ? true:false; }
static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) @@ -1533,12 +1615,12 @@ 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; + struct hdac_hdmi_port *port = pcm->port;
- if (!pin || !pin->eld.eld_valid) + if (!port || !port->eld.eld_valid) return 0;
- return pin->eld.info.spk_alloc; + return port->eld.info.spk_alloc; }
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) @@ -1611,12 +1693,13 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; + int i;
snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; - pcm->pin = NULL; + pcm->port = NULL; list_del(&pcm->head); kfree(pcm); } @@ -1628,6 +1711,9 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) }
list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { + for (i =0; i < pin->num_ports; i++) + pin->ports[i].pin = NULL; + kfree(pin->ports); list_del(&pin->head); kfree(pin); }
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in skl_rt286 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_rt286.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 88c61e8..367fc36 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -94,9 +94,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"},
The patch
ASoC: Intel: Skylake: Add route change to rt286 machine
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 111c2ae1fb46f66e1acd8b077377919954d6aa64 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 24 Jan 2017 21:49:09 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add route change to rt286 machine
To support MST moved pin to port, this changes the routes based on port. So change the route in skl_rt286 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_rt286.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index dc5c3611a6ff..5e56af3a6ee3 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -94,9 +94,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"},
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 25db5be..9da1b64 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -111,8 +111,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -130,8 +130,8 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" },
- {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"},
/* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" },
The patch
ASoC: Intel: Skylake: Add route change to nau88l25_max98357a machine
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 b0aad231bd1edd297a3e60acf26f9dceff1937a7 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Mon, 6 Feb 2017 12:09:15 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add route change to nau88l25_max98357a machine
To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index fddd1cd12f13..bb4196867752 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -111,8 +111,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -130,8 +130,8 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" },
- {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"},
/* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" },
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_ssm4567 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 69c5d5d..d1f843b 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -115,8 +115,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -135,8 +135,9 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"}, + /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"},
The patch
ASoC: Intel: Skylake: Add route change to nau88l25_ssm4567 machine
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 8d13640f6b9f1f99035d7078b3cd4002e9af5d9c Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Mon, 6 Feb 2017 12:09:16 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add route change to nau88l25_ssm4567 machine
To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_ssm4567 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 8ab865ee0cad..41117bc51450 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -115,8 +115,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -135,8 +135,9 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"}, + /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"},
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_rt298 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_rt298.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 253d7bf..3052797 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -82,9 +82,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp5 Tx"},
The patch
ASoC: Intel: bxt: Add route change to rt298 machine
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 eaba31035aa925b04d7d63120283e40a0e96e4a8 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Mon, 6 Feb 2017 12:09:17 +0530 Subject: [PATCH] ASoC: Intel: bxt: Add route change to rt298 machine
To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_rt298 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_rt298.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index bc9ee0975073..09be868833d1 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -92,9 +92,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp5 Tx"},
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_da7219_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 3774b11..c4dca26 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -82,9 +82,9 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"codec0_in", NULL, "ssp1 Rx"}, {"ssp1 Rx", NULL, "Capture"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"},
{"hifi3", NULL, "iDisp3 Tx"}, {"iDisp3 Tx", NULL, "iDisp3_out"},
The patch
ASoC: Intel: bxt: Add route change to da7219_max98357a machine
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 6d707a74a79c7698bd3b797586c2f6ae55eae56c Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 24 Jan 2017 21:49:13 +0530 Subject: [PATCH] ASoC: Intel: bxt: Add route change to da7219_max98357a machine
To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_da7219_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 02439ace3519..876d82d4a39e 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -84,9 +84,9 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"codec0_in", NULL, "ssp1 Rx"}, {"ssp1 Rx", NULL, "Capture"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"},
{"hifi3", NULL, "iDisp3 Tx"}, {"iDisp3 Tx", NULL, "iDisp3_out"},
From: Jeeja KP jeeja.kp@intel.com
To handle Jack event and Configure the Pin widget for MST capable pin, this patch adds: 1. Flag to identify the pin is MST capable. 2. In notify callback(), based on the pipe and port information marks if the port is mst_capable. In case of Non MST, port is defaulted to zero.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 88d6dae..c9f4d4a 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -81,6 +81,7 @@ struct hdac_hdmi_eld { struct hdac_hdmi_pin { struct list_head head; hda_nid_t nid; + bool is_mst_capable; struct hdac_hdmi_port *ports; int num_ports; struct hdac_ext_device *edev; @@ -1057,6 +1058,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; int size = 0; + int port_id;
if (!hdmi) return; @@ -1064,7 +1066,9 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, mutex_lock(&hdmi->pin_mutex); port->eld.monitor_present = false;
- size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + port_id = (pin->is_mst_capable)? port->id: -1; + + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, port_id, &port->eld.monitor_present, port->eld.eld_buffer, ELD_MAX_SIZE);
@@ -1154,6 +1158,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) return -ENOMEM;
pin->nid = nid; + pin->is_mst_capable = false; pin->edev = edev; ret = hdac_hdmi_add_ports(hdmi, pin); if (ret < 0) @@ -1352,6 +1357,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int dport, int pipe) struct hdac_hdmi_pin *pin = NULL; struct hdac_hdmi_port *port = NULL; struct snd_soc_codec *codec = edev->scodec; + int i;
/* Don't know how this mapping is derived */ hda_nid_t pin_nid = dport + 0x04; @@ -1377,13 +1383,23 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int dport, int pipe) continue;
if (pipe == -1) { + pin->is_mst_capable = false; /* if not MST, default is port[0] */ port = &pin->ports[0]; - break; + goto out; + } else { + for (i=0; i < pin->num_ports; i++) { + pin->is_mst_capable = true; + if (pin->ports[i].id == pipe) { + port = &pin->ports[i]; + goto out; + } + } } }
- if (port) +out: + if (pin && port) hdac_hdmi_present_sense(pin, port); }
From: Jeeja KP jeeja.kp@intel.com
To support DP MST audio, new pin verbs/params are added. This patch adds helper functions to do following: 1. To set a specific port 2. To get the currently selected port 3. To get the length of port.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c9f4d4a..d99eb9c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -125,6 +125,75 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; };
+/* MST supported verbs */ +/* + * Get the no devices that can be connected to a port on the Pin widget. + */ +static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid) +{ + unsigned int caps; + unsigned int type, param; + + caps = get_wcaps(&hdac->hdac, nid); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN)) + return 0; + + param = snd_hdac_read_parm_uncached(&hdac->hdac, nid, + AC_PAR_DEVLIST_LEN); + if (param == -1) + return param; + + return param & AC_DEV_LIST_LEN_MASK; +} + +/* + * Get the port entry select on the pin. Return the port entry + * id selected on the pin. Return 0 means the first port entry + * is selected or MST is not supported. + */ +static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + return snd_hdac_codec_read(&hdac->hdac, port->pin->nid, + 0, AC_VERB_GET_DEVICE_SEL, 0); +} + +/* + * Sets the selected port entry for the configuring Pin widget verb. + * returns error if port set is not equal to port get otherwise success + */ +static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + int num_ports; + + if (!port->pin->is_mst_capable) + return 0; + + /* AC_PAR_DEVLIST_LEN is 0 based. */ + num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid); + + if (num_ports < 0) + return -EIO; + /* + * Device List Length is a 0 based integer value indicating the + * number of sink device that a MST Pin Widget can support. + */ + if (num_ports +1 <port->id) + return 0; + + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, + AC_VERB_SET_DEVICE_SEL, port->id); + + if (port->id != hdac_hdmi_port_select_get(hdac, port)) + return -EIO; + + dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id); + return 0; +} + static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, struct hdac_hdmi_dai_port_map *dai_map);
From: Jeeja KP jeeja.kp@intel.com
To enable stream on to specific port which is MST capable pin, before configuring the pin widget verb, Port need to be selected.
When Port is selected, all the Pin widget verb controlling the sink device operation will be directed to selected port. So add port selection before configuring the pin widget verb.
Since the port select can change between pcm, need to protect the selection of port and the configuration of pin widget verb. So moved the port lock to pcm lock.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 80 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 18 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index d99eb9c..618af31 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -93,7 +93,6 @@ struct hdac_hdmi_port { int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; - struct mutex lock; bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ int channels; /* current number of channels */ @@ -101,6 +100,7 @@ struct hdac_hdmi_port {
struct hdac_hdmi_pcm { struct list_head head; + struct mutex lock; int pcm_id; struct hdac_hdmi_port *port; struct hdac_hdmi_cvt *cvt; @@ -125,6 +125,20 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; };
+static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm_from_cvt( + struct hdac_hdmi_priv *hdmi, + struct hdac_hdmi_cvt *cvt) +{ + struct hdac_hdmi_pcm *pcm = NULL; + + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->cvt == cvt) + break; + } + + return pcm; +} + /* MST supported verbs */ /* * Get the no devices that can be connected to a port on the Pin widget. @@ -323,6 +337,9 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, break; }
+ if (hdac_hdmi_port_select_set(hdac, port) < 0) + return -EIO; + ca = snd_hdac_channel_allocation(&hdac->hdac, port->eld.info.spk_alloc, port->channels, port->chmap_set, true, port->chmap);
@@ -416,6 +433,7 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_port *port; + struct hdac_hdmi_pcm *pcm; struct hdac_ext_dma_params *dd; int ret;
@@ -427,16 +445,21 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, dd->stream_tag, dd->format);
hdac_hdmi_enable_cvt(hdac, dai_map); + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); + + if (!pcm) + return -EIO; + + mutex_lock(&pcm->lock); ret = hdac_hdmi_enable_pin(hdac, dai_map); if (ret < 0) return ret;
- mutex_lock(&port->lock); port->channels = substream->runtime->channels;
ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, port->pin->nid, port); - mutex_unlock(&port->lock); + mutex_unlock(&pcm->lock); if (ret < 0) return ret;
@@ -520,6 +543,10 @@ static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, int mux_idx; struct hdac_hdmi_port *port = dai_map->port;
+ /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(hdac, port) < 0) + return -EIO; + for (mux_idx = 0; mux_idx < port->num_mux_nids; mux_idx++) { if (port->mux_nids[mux_idx] == dai_map->cvt->nid) { snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, @@ -547,6 +574,11 @@ static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, struct hdac_hdmi_pin *pin, struct hdac_hdmi_port *port) { + + /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(hdac, port) < 0) + return -EIO; + if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { dev_warn(&hdac->hdac.dev, "HDMI: pin %d wcaps %#x does not support connection list\n", @@ -593,7 +625,10 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( }
if (port) { + mutex_lock(&pcm->lock); ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); + mutex_unlock(&pcm->lock); + if (ret < 0) return NULL;
@@ -681,25 +716,32 @@ static void hdac_hdmi_pcm_close(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_port_map *dai_map; + struct hdac_hdmi_port *port; + struct hdac_hdmi_pcm *pcm;
dai_map = &hdmi->dai_map[dai->id];
- if (dai_map->port) { + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); + + if (dai_map->port && pcm) { + port = dai_map->port; snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
- hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); - - snd_hdac_codec_write(&hdac->hdac, dai_map->port->pin->nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + mutex_lock(&pcm->lock); + /* set the device if pin is mst_capable */ + if (!hdac_hdmi_port_select_set(hdac, port)) { + hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
- mutex_lock(&dai_map->port->lock); + snd_hdac_codec_write(&hdac->hdac, dai_map->port->pin->nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + } dai_map->port->chmap_set = false; memset(dai_map->port->chmap, 0, sizeof(dai_map->port->chmap)); dai_map->port->channels = 0; - mutex_unlock(&dai_map->port->lock); + mutex_unlock(&pcm->lock);
dai_map->port = NULL; } @@ -1209,7 +1251,6 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, for (i=0; i < max_ports; i++) { ports[i].id = i + 1; ports[i].pin = pin; - mutex_init(&ports[i].lock); } pin->ports = ports; pin->num_ports = max_ports; @@ -1510,6 +1551,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + mutex_init(&pcm->lock);
snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); if (snd_pcm) { @@ -1676,13 +1718,15 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_hdmi_port *port = pcm->port; struct hdac_hdmi_pin *pin = port->pin;
- mutex_lock(&port->lock); - port->chmap_set = true; - memcpy(port->chmap, chmap, ARRAY_SIZE(port->chmap)); - if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, - pin->nid, port); - mutex_unlock(&port->lock); + if (pcm) { + mutex_lock(&pcm->lock); + port->chmap_set = true; + memcpy(port->chmap, chmap, ARRAY_SIZE(port->chmap)); + if (prepared) + hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, + pin->nid, port); + mutex_unlock(&pcm->lock); + } }
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
From: Jeeja KP jeeja.kp@intel.com
Since we have the MST feature enabled and Pin-Port mux for user to select the converter routing, Multiple port mapping to same converter needs to be supported.
This patch the following changes to support Multiple port mapped to same converter. 1. Jack reporting in case where Multiple port are attached to same PCM. 2. Enable all the port if the device connected in pcm prepare. 3. Configure Audio frame for all ports in pcm prepare.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 295 +++++++++++++++++++++++++++---------------- 1 file changed, 183 insertions(+), 112 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 618af31..bfa0ffb 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -88,6 +88,7 @@ struct hdac_hdmi_pin { };
struct hdac_hdmi_port { + struct list_head head; int id; struct hdac_hdmi_pin *pin; int num_mux_nids; @@ -96,15 +97,17 @@ struct hdac_hdmi_port { bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ int channels; /* current number of channels */ + bool is_connected; /* flag to indicate device connected to port */ };
struct hdac_hdmi_pcm { struct list_head head; struct mutex lock; int pcm_id; - struct hdac_hdmi_port *port; + struct list_head port_list; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; + int jack_event; };
struct hdac_hdmi_dai_port_map { @@ -125,6 +128,39 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; };
+static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, + struct hdac_hdmi_port *port, bool is_connect) +{ + struct hdac_ext_device *edev = port->pin->edev; + + if (is_connect) { + /* + * Report Jack connect event when a device is connected + * for the first time where same PCM is attached to mutiple + * ports. + */ + if (pcm->jack_event == 0) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); + snd_jack_report(pcm->jack, SND_JACK_AVOUT); + } + pcm->jack_event++; + port->is_connected = true; + } else { + /* + * Report Jack disconnect event when a device is disconnected + * is the only last connected device when same PCM is attached + * to mutiple ports. + */ + if (pcm->jack_event == 1) + snd_jack_report(pcm->jack, 0); + if (pcm->jack_event > 0) + pcm->jack_event--; + port->is_connected = false; + } +} + static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm_from_cvt( struct hdac_hdmi_priv *hdmi, struct hdac_hdmi_cvt *cvt) @@ -212,7 +248,7 @@ static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, struct hdac_hdmi_dai_port_map *dai_map);
static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, - struct hdac_hdmi_dai_port_map *dai_map); + struct hdac_hdmi_port *port, struct hdac_hdmi_cvt *cvt);
static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) @@ -274,13 +310,12 @@ format_constraint: }
static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, - hda_nid_t cvt_nid, hda_nid_t pin_nid, - u32 stream_tag, int format) + hda_nid_t cvt_nid, u32 stream_tag, int format) { unsigned int val;
- dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", - cvt_nid, pin_nid, stream_tag, format); + dev_dbg(&hdac->hdac.dev, "cvt nid %d stream %d format 0x%x\n", + cvt_nid, stream_tag, format);
val = (stream_tag << 4);
@@ -409,9 +444,10 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, }
static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_port_map *dai_map, unsigned int pwr_state) + struct hdac_hdmi_cvt *cvt, struct hdac_hdmi_port *port, + unsigned int pwr_state) { - struct hdac_hdmi_pin *pin = dai_map->port->pin; + struct hdac_hdmi_pin *pin = port->pin;
/* Power up pin widget */ if (!snd_hdac_check_power_state(&edev->hdac, pin->nid, @@ -420,9 +456,9 @@ static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, AC_VERB_SET_POWER_STATE, pwr_state);
/* Power up converter */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, + if (!snd_hdac_check_power_state(&edev->hdac, cvt->nid, pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, AC_VERB_SET_POWER_STATE, pwr_state); }
@@ -438,7 +474,6 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, int ret;
dai_map = &hdmi->dai_map[dai->id]; - port = dai_map->port;
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", @@ -450,21 +485,30 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, if (!pcm) return -EIO;
- mutex_lock(&pcm->lock); - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; + if (list_empty(&pcm->port_list)) + return -EIO;
- port->channels = substream->runtime->channels; + mutex_lock(&pcm->lock); + list_for_each_entry(port, &pcm->port_list, head) { + if (port->is_connected) { + ret = hdac_hdmi_enable_pin(hdac, port, dai_map->cvt); + if (ret < 0) { + mutex_unlock(&pcm->lock); + return ret; + } + port->channels = substream->runtime->channels;
- ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, + ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, port->pin->nid, port); + if (ret < 0) { + mutex_unlock(&pcm->lock); + return ret; + } + } + } mutex_unlock(&pcm->lock); - if (ret < 0) - return ret;
- return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, - port->pin->nid, dd->stream_tag, dd->format); + return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, dd->stream_tag, dd->format); }
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, @@ -538,17 +582,16 @@ static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, }
static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, - struct hdac_hdmi_dai_port_map *dai_map) + struct hdac_hdmi_port *port, struct hdac_hdmi_cvt *cvt) { int mux_idx; - struct hdac_hdmi_port *port = dai_map->port;
/* set the device if pin is mst_capable */ if (hdac_hdmi_port_select_set(hdac, port) < 0) return -EIO;
for (mux_idx = 0; mux_idx < port->num_mux_nids; mux_idx++) { - if (port->mux_nids[mux_idx] == dai_map->cvt->nid) { + if (port->mux_nids[mux_idx] == cvt->nid) { snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, mux_idx); break; @@ -562,7 +605,7 @@ static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); + hdac_hdmi_set_power_state(hdac, cvt, port, AC_PWRST_D0);
snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); @@ -614,30 +657,33 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( struct hdac_hdmi_cvt *cvt) { struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_port *port = NULL; + struct hdac_hdmi_port *port = NULL, *valid_port = NULL; int ret, i;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) { - port = pcm->port; - break; - } - } + if (list_empty(&pcm->port_list)) + continue;
- if (port) { - mutex_lock(&pcm->lock); - ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); - mutex_unlock(&pcm->lock); + list_for_each_entry(port, &pcm->port_list, head) { + mutex_lock(&pcm->lock); + ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); + mutex_unlock(&pcm->lock);
- if (ret < 0) - return NULL; + if (ret < 0) + return NULL;
- for (i = 0; i < port->num_mux_nids; i++) { - if (port->mux_nids[i] == cvt->nid) - return port; + for (i = 0; i < port->num_mux_nids; i++) { + if (port->mux_nids[i] == cvt->nid) + valid_port = port; + } + } } }
+ if (valid_port) + return valid_port; + return NULL; }
@@ -667,7 +713,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, */ if (!port) return 0; - if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
@@ -693,19 +738,10 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct hdac_hdmi_dai_port_map *dai_map; - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; - int ret; - - dai_map = &hdmi->dai_map[dai->id]; - if (cmd == SNDRV_PCM_TRIGGER_RESUME) { - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret;
+ if (cmd == SNDRV_PCM_TRIGGER_RESUME) return hdac_hdmi_playback_prepare(substream, dai); - } +
return 0; } @@ -718,32 +754,39 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_port *port; struct hdac_hdmi_pcm *pcm; + struct hdac_hdmi_cvt *cvt;
dai_map = &hdmi->dai_map[dai->id];
pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
+ cvt = dai_map->cvt; + if (dai_map->port && pcm) { - port = dai_map->port; snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
- mutex_lock(&pcm->lock); - /* set the device if pin is mst_capable */ - if (!hdac_hdmi_port_select_set(hdac, port)) { - hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); + if (!list_empty(&pcm->port_list)) { + mutex_lock(&pcm->lock); + list_for_each_entry(port, &pcm->port_list, head) { + /* set the device if pin is mst_capable */ + if (!hdac_hdmi_port_select_set(hdac, port)) { + hdac_hdmi_set_power_state(hdac, cvt, port, + AC_PWRST_D3);
- snd_hdac_codec_write(&hdac->hdac, dai_map->port->pin->nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - } - dai_map->port->chmap_set = false; - memset(dai_map->port->chmap, 0, sizeof(dai_map->port->chmap)); - dai_map->port->channels = 0; - mutex_unlock(&pcm->lock); + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + }
- dai_map->port = NULL; + port->chmap_set = false; + memset(port->chmap, 0, sizeof(port->chmap)); + port->channels = 0; + dai_map->port = NULL; + } + mutex_unlock(&pcm->lock); + } } }
@@ -813,13 +856,16 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; + struct hdac_hdmi_port *p;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port) + if (list_empty(&pcm->port_list)) continue;
- if (pcm->port == port) - return pcm; + list_for_each_entry(p, &pcm->port_list, head) { + if (p->id == port->id && port->pin == p->pin) + return pcm; + } }
return NULL; @@ -832,6 +878,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; + struct hdac_hdmi_port *p, *p_next; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_dapm_context *dapm = w->dapm; @@ -850,25 +897,30 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
mutex_lock(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port && pcm->port == port && - pcm->port->id == port->id) - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue;
- /* - * Jack status is not reported during device probe as the - * PCMs are not registered by then. So report it here. - */ - if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { - pcm->port = port; - if (port->eld.monitor_present && port->eld.eld_valid) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + list_for_each_entry_safe(p, p_next, &pcm->port_list, head) { + if (p == port && p->id == port->id && + p->pin == port->pin) { + hdac_hdmi_jack_report(pcm, port, false); + list_del(&p->head); + } + } + }
- snd_jack_report(pcm->jack, SND_JACK_AVOUT); + /* + * Jack status is not reported during device probe as the + * PCMs are not registered by then. So report it here. + */ + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (!strcmp(cvt_name, pcm->cvt->name)) { + list_add_tail(&port->head, &pcm->port_list); + if (port->eld.monitor_present && port->eld.eld_valid) { + hdac_hdmi_jack_report(pcm, port, true); + mutex_unlock(&hdmi->pin_mutex); + return ret; } - mutex_unlock(&hdmi->pin_mutex); - return ret; } } mutex_unlock(&hdmi->pin_mutex); @@ -1209,25 +1261,16 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, * report jack here. It will be done in usermode mux * control select. */ - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", pcm->pcm_id); - - snd_jack_report(pcm->jack, 0); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, false);
mutex_unlock(&hdmi->pin_mutex); return; }
if (port->eld.monitor_present && port->eld.eld_valid) { - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, true);
print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, port->eld.eld_buffer, port->eld.eld_size, false); @@ -1551,8 +1594,9 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + pcm->jack_event = 0; mutex_init(&pcm->lock); - + INIT_LIST_HEAD(&pcm->port_list); 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); @@ -1610,6 +1654,11 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) return ret; }
+ /* FIXME + * At boot driver does not know if the port is mst capable, to get + * the ELD, i915 acomp API expects to pass pipe id as -1 when the + * port is non mst. + */ list_for_each_entry(pin, &hdmi->pin_list, head) for (i = 0; i < pin->num_ports; i++) hdac_hdmi_present_sense(pin, &pin->ports[i]); @@ -1700,13 +1749,15 @@ static void hdac_hdmi_get_chmap(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_port *port = pcm->port; + struct hdac_hdmi_port *port;
- /* chmap is already set to 0 in caller */ - if (!port) + if (list_empty(&pcm->port_list)) return;
- memcpy(chmap, port->chmap, ARRAY_SIZE(port->chmap)); + list_for_each_entry(port, &pcm->port_list, head) { + /* chmap is already set to 0 in caller */ + memcpy(chmap, port->chmap, ARRAY_SIZE(port->chmap)); + } }
static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, @@ -1715,16 +1766,20 @@ static void hdac_hdmi_set_chmap(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_port *port = pcm->port; - struct hdac_hdmi_pin *pin = port->pin; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return;
if (pcm) { mutex_lock(&pcm->lock); - port->chmap_set = true; - memcpy(port->chmap, chmap, ARRAY_SIZE(port->chmap)); - if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, - pin->nid, port); + list_for_each_entry(port, &pcm->port_list, head) { + port->chmap_set = true; + memcpy(port->chmap, chmap, ARRAY_SIZE(port->chmap)); + if (prepared) + hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, + port->pin->nid, port); + } mutex_unlock(&pcm->lock); } } @@ -1734,9 +1789,11 @@ 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_port *port = pcm->port;
- return port ? true:false; + if (list_empty(&pcm->port_list)) + return false; + + return true; }
static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) @@ -1744,7 +1801,15 @@ 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_port *port = pcm->port; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return 0; + + port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head); + + if (!port) + return 0;
if (!port || !port->eld.eld_valid) return 0; @@ -1822,13 +1887,19 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; + struct hdac_hdmi_port *port; int i;
snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue; + + list_for_each_entry(port, &pcm->port_list, head) + port = NULL; + list_del(&pcm->head); kfree(pcm); }
From: Jeeja KP jeeja.kp@intel.com
Skylake platform support maximum of 3 ports per pin, so add the additional routes for rt286 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_rt286.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 367fc36..4b95e7f 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -96,7 +96,11 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{"HDMI1", NULL, "hif5-0 Output"}, {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif6-1 Output"}, + {"HDMI2", NULL, "hif6-2 Output"}, {"HDMI3", NULL, "hif7-0 Output"}, + {"HDMI3", NULL, "hif7-1 Output"}, + {"HDMI3", NULL, "hif7-2 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"},
From: Jeeja KP jeeja.kp@intel.com
Skylake platform support maximum of 3 ports per pin, so add the additional routes for nau88l25_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 9da1b64..ac77308 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -131,7 +131,11 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "DMic", NULL, "SoC DMIC" },
{"DP1", NULL, "hif5-0 Output"}, + {"DP1", NULL, "hif5-1 Output"}, + {"DP1", NULL, "hif5-2 Output"}, {"DP2", NULL, "hif6-0 Output"}, + {"DP2", NULL, "hif6-1 Output"}, + {"DP2", NULL, "hif6-2 Output"},
/* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" },
From: Jeeja KP jeeja.kp@intel.com
Skylake platform support maximum of 3 ports per pin, so add the additional routes for nau88l25_ssm4567 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index d1f843b..5901340 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -136,7 +136,11 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"DMic", NULL, "SoC DMIC"},
{"DP1", NULL, "hif5-0 Output"}, + {"DP1", NULL, "hif5-1 Output"}, + {"DP1", NULL, "hif5-2 Output"}, {"DP2", NULL, "hif6-0 Output"}, + {"DP2", NULL, "hif6-1 Output"}, + {"DP2", NULL, "hif6-2 Output"},
/* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"},
From: Jeeja KP jeeja.kp@intel.com
Skylake platform support maximum of 3 ports per pin, so add the additional routes for rt286 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_rt298.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 3052797..a99a91f 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -83,8 +83,13 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { {"DMic", NULL, "SoC DMIC"},
{"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, + {"HDMI2", NULL, "hif6-1 Output"}, + {"HDMI2", NULL, "hif6-2 Output"}, + {"HDMI3", NULL, "hif7-0 Output"}, + {"HDMI3", NULL, "hif7-1 Output"}, + {"HDMI3", NULL, "hif7-2 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp5 Tx"},
From: Jeeja KP jeeja.kp@intel.com
Skylake platform support maximum of 3 ports per pin, so add the additional routes for bxt_da7219_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c4dca26..5953c4f 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -84,7 +84,11 @@ static const struct snd_soc_dapm_route broxton_map[] = {
{"HDMI1", NULL, "hif5-0 Output"}, {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, + {"HDMI2", NULL, "hif6-1 Output"}, + {"HDMI2", NULL, "hif6-2 Output"}, + {"HDMI3", NULL, "hif7-0 Output"}, + {"HDMI3", NULL, "hif7-1 Output"}, + {"HDMI3", NULL, "hif7-2 Output"},
{"hifi3", NULL, "iDisp3 Tx"}, {"iDisp3 Tx", NULL, "iDisp3_out"},
participants (2)
-
jeeja.kp@intel.com
-
Mark Brown