@@ -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)