--- Begin Message ---
Package: linux-source-5.2
Version: 5.2.9-2~bpo10+1
Severity: important
Tags: patch
Dear Maintainer,
* What led up to the situation?
The Lenovo X1 Carbon Gen 7 laptops use the Whiskeylake CPU and when testing
with Debian we found the audio was not working.
Whiskeylake requires the new SOF audio driver to be enabled - but some fixes
also need to be backported to prevent firmware load issues seen during suspend
and resume
Note we are using the buster-backports 5.2 kernel as SOF audio driver support
is not available in the earlier kernels.
* What exactly did you do (or not do) that was effective (or
ineffective)?
Enabled SOF audio driver kernel configs and rebuilt the kernel. Tested and
debugged the suspend/resume issue and identified the required commits from the
working 5.3 kernel.org kernel that are needed to fix the issue.
* What was the outcome of this action?
Audio is working correctly. The driver appears stable
* What outcome did you expect instead?
NA
Notes:
The patch I'm uploading is a combo of the following applied to 5.2:
https://github.com/thesofproject/linux/commit/c760776089f147c4d28875619f3a917c02d42307
https://github.com/thesofproject/linux/commit/bb1ea3b31c28a131a5f5a50dd325198645526b19
https://github.com/thesofproject/linux/commit/64632de9140e52b72781fefe542314db7cd29d8c
https://github.com/thesofproject/linux/commit/bf705eaa7ce07f9c132f8e367fc2fc46b7842528
https://github.com/thesofproject/linux/commit/38d0e9fc227c7876d09754863adc88aeca6dd205
https://github.com/thesofproject/linux/commit/f5dbba9fee801f4678a50d92c785f7f24d4ee2c6
https://github.com/thesofproject/linux/commit/7623ae793c28cc0928c5d1292542dbb92fc2e9e2
The kconfig snipped I'm also uploading is based on config settings from the SOF
team
This is my first bug raised against Debian - Lenovo are actively focussing on
getting Debian working on our systems so I'm hoping to get a lot more involved.
Please do let me know if I've made any mistakes or things I can improve on for
future bugs.
Thanks
Mrk Pearson
-- System Information:
Debian Release: 10.1
APT prefers stable-updates
APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: amd64 (x86_64)
Kernel: Linux 5.2.9 (SMP w/8 CPU cores)
Kernel taint flags: TAINT_UNSIGNED_MODULE
Locale: LANG=en_CA.UTF-8, LC_CTYPE=en_CA.UTF-8 (charmap=UTF-8),
LANGUAGE=en_CA.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
Versions of packages linux-source-5.2 depends on:
ii binutils 2.31.1-16
ii xz-utils 5.2.4-1
Versions of packages linux-source-5.2 recommends:
ii bc 1.07.1-2+b1
ii bison 2:3.3.2.dfsg-1
ii flex 2.6.4-6.2
ii gcc 4:8.3.0-1
ii libc6-dev [libc-dev] 2.28-10
ii linux-config-5.2 5.2.9-2~bpo10+1
ii make 4.2.1-1.2
Versions of packages linux-source-5.2 suggests:
ii libncurses-dev [ncurses-dev] 6.1+20181013-2+deb10u1
pn libqt4-dev <none>
pn pkg-config <none>
-- no debconf information
diff -Naurp linux-source-5.2-orig/sound/soc/sof/control.c
linux-source-5.2/sound/soc/sof/control.c
--- linux-source-5.2-orig/sound/soc/sof/control.c 2019-08-16
04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/control.c 2019-09-18 22:18:22.970932678
-0400
@@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontr
struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
- int err, ret;
-
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: volume get failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
-
- /* get all the mixer data from DSP */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_GET_VALUE,
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
- SOF_CTRL_CMD_VOLUME,
- false);
/* read back each channel */
for (i = 0; i < channels; i++)
@@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontr
ipc_to_mixer(cdata->chanv[i].value,
scontrol->volume_table, sm->max + 1);
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: volume get failed to idle %d\n",
- err);
return 0;
}
@@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontr
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
- int ret, err;
-
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: volume put failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
/* update each channel */
for (i = 0; i < channels; i++) {
@@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontr
}
/* notify DSP of mixer updates */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_SET_VALUE,
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
- SOF_CTRL_CMD_VOLUME,
- true);
-
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: volume put failed to idle %d\n",
- err);
+ if (pm_runtime_active(sdev->dev))
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ SOF_IPC_COMP_SET_VALUE,
+ SOF_CTRL_TYPE_VALUE_CHAN_GET,
+ SOF_CTRL_CMD_VOLUME,
+ true);
+
return 0;
}
@@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontr
struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
- int err, ret;
-
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: switch get failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
-
- /* get all the mixer data from DSP */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_GET_VALUE,
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
- SOF_CTRL_CMD_SWITCH,
- false);
/* read back each channel */
for (i = 0; i < channels; i++)
ucontrol->value.integer.value[i] = cdata->chanv[i].value;
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: switch get failed to idle %d\n",
- err);
return 0;
}
@@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontr
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
- int ret, err;
-
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: switch put failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
/* update each channel */
for (i = 0; i < channels; i++) {
@@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontr
}
/* notify DSP of mixer updates */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_SET_VALUE,
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
- SOF_CTRL_CMD_SWITCH,
- true);
-
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: switch put failed to idle %d\n",
- err);
+ if (pm_runtime_active(sdev->dev))
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ SOF_IPC_COMP_SET_VALUE,
+ SOF_CTRL_TYPE_VALUE_CHAN_GET,
+ SOF_CTRL_CMD_SWITCH,
+ true);
+
return 0;
}
@@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol
struct soc_enum *se =
(struct soc_enum *)kcontrol->private_value;
struct snd_sof_control *scontrol = se->dobj.private;
- struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
- int err, ret;
-
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: enum get failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
-
- /* get all the enum data from DSP */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_GET_VALUE,
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
- SOF_CTRL_CMD_ENUM,
- false);
/* read back each channel */
for (i = 0; i < channels; i++)
ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: enum get failed to idle %d\n",
- err);
return 0;
}
@@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
- int ret, err;
-
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: enum put failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
/* update each channel */
for (i = 0; i < channels; i++) {
@@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol
}
/* notify DSP of enum updates */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_SET_VALUE,
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
- SOF_CTRL_CMD_ENUM,
- true);
-
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: enum put failed to idle %d\n",
- err);
+ if (pm_runtime_active(sdev->dev))
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ SOF_IPC_COMP_SET_VALUE,
+ SOF_CTRL_TYPE_VALUE_CHAN_GET,
+ SOF_CTRL_CMD_ENUM,
+ true);
+
return 0;
}
@@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontro
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size;
- int ret, err;
+ int ret = 0;
if (be->max > sizeof(ucontrol->value.bytes.data)) {
dev_err_ratelimited(sdev->dev,
@@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontro
return -EINVAL;
}
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: bytes get failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
-
- /* get all the binary data from DSP */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_GET_DATA,
- SOF_CTRL_TYPE_DATA_GET,
- scontrol->cmd,
- false);
-
size = data->size + sizeof(*data);
if (size > be->max) {
dev_err_ratelimited(sdev->dev,
@@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontro
memcpy(ucontrol->value.bytes.data, data, size);
out:
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: bytes get failed to idle %d\n",
- err);
return ret;
}
@@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontro
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size = data->size + sizeof(*data);
- int ret, err;
if (be->max > sizeof(ucontrol->value.bytes.data)) {
dev_err_ratelimited(sdev->dev,
@@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontro
return -EINVAL;
}
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: bytes put failed to resume %d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
-
/* copy from kcontrol */
memcpy(data, ucontrol->value.bytes.data, size);
/* notify DSP of byte control updates */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_SET_DATA,
- SOF_CTRL_TYPE_DATA_SET,
- scontrol->cmd,
- true);
-
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: bytes put failed to idle %d\n",
- err);
- return ret;
+ if (pm_runtime_active(sdev->dev))
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ SOF_IPC_COMP_SET_DATA,
+ SOF_CTRL_TYPE_DATA_SET,
+ scontrol->cmd,
+ true);
+
+ return 0;
}
int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
@@ -406,8 +252,6 @@ int snd_sof_bytes_ext_put(struct snd_kco
struct snd_ctl_tlv header;
const struct snd_ctl_tlv __user *tlvd =
(const struct snd_ctl_tlv __user *)binary_data;
- int ret;
- int err;
/*
* The beginning of bytes data contains a header from where
@@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kco
return -EINVAL;
}
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: bytes_ext put failed to resume
%d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
-
/* notify DSP of byte control updates */
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_SET_DATA,
- SOF_CTRL_TYPE_DATA_SET,
- scontrol->cmd,
- true);
-
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: bytes_ext put failed to idle %d\n",
- err);
+ if (pm_runtime_active(sdev->dev))
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ SOF_IPC_COMP_SET_DATA,
+ SOF_CTRL_TYPE_DATA_SET,
+ scontrol->cmd,
+ true);
- return ret;
+ return 0;
}
int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
@@ -492,17 +321,7 @@ int snd_sof_bytes_ext_get(struct snd_kco
struct snd_ctl_tlv __user *tlvd =
(struct snd_ctl_tlv __user *)binary_data;
int data_size;
- int err;
- int ret;
-
- ret = pm_runtime_get_sync(sdev->dev);
- if (ret < 0) {
- dev_err_ratelimited(sdev->dev,
- "error: bytes_ext get failed to resume
%d\n",
- ret);
- pm_runtime_put_noidle(sdev->dev);
- return ret;
- }
+ int ret = 0;
/*
* Decrement the limit by ext bytes header size to
@@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kco
cdata->data->magic = SOF_ABI_MAGIC;
cdata->data->abi = SOF_ABI_VERSION;
- /* get all the component data from DSP */
- ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
- SOF_IPC_COMP_GET_DATA,
- SOF_CTRL_TYPE_DATA_GET,
- scontrol->cmd,
- false);
-
/* Prevent read of other kernel data or possibly corrupt response */
data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
@@ -543,11 +355,5 @@ int snd_sof_bytes_ext_get(struct snd_kco
ret = -EFAULT;
out:
- pm_runtime_mark_last_busy(sdev->dev);
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev,
- "error: bytes_ext get failed to idle %d\n",
- err);
return ret;
}
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda-dai.c
linux-source-5.2/sound/soc/sof/intel/hda-dai.c
--- linux-source-5.2-orig/sound/soc/sof/intel/hda-dai.c 2019-08-16
04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda-dai.c 2019-09-18
22:17:59.327619433 -0400
@@ -30,62 +30,84 @@ struct hda_pipe_params {
};
/*
- * Unlike GP dma, there is a set of stream registers in hda controller
- * to control the link dma channels. Each register controls one link
- * dma channel and the relation is fixed. To make sure FW uses correct
- * link dma channels, host allocates stream registers and sends the
- * corresponding link dma channels to FW to allocate link dma channel
- *
- * FIXME: this API is abused in the sense that tx_num and rx_num are
- * passed as arguments, not returned. We need to find a better way to
- * retrieve the stream tag allocated for the link DMA
+ * This function checks if the host dma channel corresponding
+ * to the link DMA stream_tag argument is assigned to one
+ * of the FEs connected to the BE DAI.
*/
-static int hda_link_dma_get_channels(struct snd_soc_dai *dai,
- unsigned int *tx_num,
- unsigned int *tx_slot,
- unsigned int *rx_num,
- unsigned int *rx_slot)
+static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
+ int dir, int stream_tag)
{
- struct hdac_bus *bus;
- struct hdac_ext_stream *stream;
- struct snd_pcm_substream substream;
- struct snd_sof_dev *sdev =
- snd_soc_component_get_drvdata(dai->component);
+ struct snd_pcm_substream *fe_substream;
+ struct hdac_stream *fe_hstream;
+ struct snd_soc_dpcm *dpcm;
+
+ for_each_dpcm_fe(rtd, dir, dpcm) {
+ fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
+ fe_hstream = fe_substream->runtime->private_data;
+ if (fe_hstream->stream_tag == stream_tag)
+ return true;
+ }
- bus = sof_to_bus(sdev);
+ return false;
+}
- memset(&substream, 0, sizeof(substream));
- if (*tx_num == 1) {
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- stream = snd_hdac_ext_stream_assign(bus, &substream,
- HDAC_EXT_STREAM_TYPE_LINK);
- if (!stream) {
- dev_err(bus->dev, "error: failed to find a free hda ext
stream for playback");
- return -EBUSY;
- }
+static struct hdac_ext_stream *
+ hda_link_stream_assign(struct hdac_bus *bus,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sof_intel_hda_stream *hda_stream;
+ struct hdac_ext_stream *res = NULL;
+ struct hdac_stream *stream = NULL;
- snd_soc_dai_set_dma_data(dai, &substream, stream);
- *tx_slot = hdac_stream(stream)->stream_tag - 1;
+ int stream_dir = substream->stream;
- dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot);
+ if (!bus->ppcap) {
+ dev_err(bus->dev, "stream type not supported\n");
+ return NULL;
}
- if (*rx_num == 1) {
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- stream = snd_hdac_ext_stream_assign(bus, &substream,
- HDAC_EXT_STREAM_TYPE_LINK);
- if (!stream) {
- dev_err(bus->dev, "error: failed to find a free hda ext
stream for capture");
- return -EBUSY;
+ list_for_each_entry(stream, &bus->stream_list, list) {
+ struct hdac_ext_stream *hstream =
+ stream_to_hdac_ext_stream(stream);
+ if (stream->direction != substream->stream)
+ continue;
+
+ hda_stream = hstream_to_sof_hda_stream(hstream);
+
+ /* check if available */
+ if (!hstream->link_locked) {
+ if (stream->opened) {
+ /*
+ * check if the stream tag matches the stream
+ * tag of one of the connected FEs
+ */
+ if (hda_check_fes(rtd, stream_dir,
+ stream->stream_tag)) {
+ res = hstream;
+ break;
+ }
+ } else {
+ res = hstream;
+ break;
+ }
}
+ }
- snd_soc_dai_set_dma_data(dai, &substream, stream);
- *rx_slot = hdac_stream(stream)->stream_tag - 1;
-
- dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot);
+ if (res) {
+ /*
+ * Decouple host and link DMA. The decoupled flag
+ * is updated in snd_hdac_ext_stream_decouple().
+ */
+ if (!res->decoupled)
+ snd_hdac_ext_stream_decouple(bus, res, true);
+ spin_lock_irq(&bus->reg_lock);
+ res->link_locked = 1;
+ res->link_substream = substream;
+ spin_unlock_irq(&bus->reg_lock);
}
- return 0;
+ return res;
}
static int hda_link_dma_params(struct hdac_ext_stream *stream,
@@ -122,6 +144,51 @@ static int hda_link_dma_params(struct hd
return 0;
}
+/* Send DAI_CONFIG IPC to the DAI that matches the dai_name and direction */
+static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
+ const char *dai_name, int channel, int dir)
+{
+ struct sof_ipc_dai_config *config;
+ struct snd_sof_dai *sof_dai;
+ struct sof_ipc_reply reply;
+ int ret = 0;
+
+ list_for_each_entry(sof_dai, &hda_stream->sdev->dai_list, list) {
+ if (!sof_dai->cpu_dai_name)
+ continue;
+
+ if (!strcmp(dai_name, sof_dai->cpu_dai_name) &&
+ dir == sof_dai->comp_dai.direction) {
+ config = sof_dai->dai_config;
+
+ if (!config) {
+ dev_err(hda_stream->sdev->dev,
+ "error: no config for DAI %s\n",
+ sof_dai->name);
+ return -EINVAL;
+ }
+
+ /* update config with stream tag */
+ config->hda.link_dma_ch = channel;
+
+ /* send IPC */
+ ret = sof_ipc_tx_message(hda_stream->sdev->ipc,
+ config->hdr.cmd,
+ config,
+ config->hdr.size,
+ &reply, sizeof(reply));
+
+ if (ret < 0)
+ dev_err(hda_stream->sdev->dev,
+ "error: failed to set dai config for
%s\n",
+ sof_dai->name);
+ return ret;
+ }
+ }
+
+ return -EINVAL;
+}
+
static int hda_link_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -135,20 +202,31 @@ static int hda_link_hw_params(struct snd
struct hda_pipe_params p_params = {0};
struct hdac_ext_link *link;
int stream_tag;
+ int ret;
- link_dev = snd_soc_dai_get_dma_data(dai, substream);
+ link_dev = hda_link_stream_assign(bus, substream);
+ if (!link_dev)
+ return -EBUSY;
+
+ stream_tag = hdac_stream(link_dev)->stream_tag;
+
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
+
+ /* update the DSP with the new tag */
+ ret = hda_link_config_ipc(hda_stream, dai->name, stream_tag - 1,
+ substream->stream);
+ if (ret < 0)
+ return ret;
+
+ snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
- hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
- hda_stream);
hda_stream->hw_params_upon_resume = 0;
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
- stream_tag = hdac_stream(link_dev)->stream_tag;
-
- /* set the stream tag in the codec dai dma params */
+ /* set the stream tag in the codec dai dma params */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
else
@@ -181,8 +259,7 @@ static int hda_link_pcm_prepare(struct s
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
int stream = substream->stream;
- hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
- hda_stream);
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
/* setup hw_params again only if resuming from system suspend */
if (!hda_stream->hw_params_upon_resume)
@@ -199,8 +276,24 @@ static int hda_link_pcm_trigger(struct s
{
struct hdac_ext_stream *link_dev =
snd_soc_dai_get_dma_data(dai, substream);
+ struct sof_intel_hda_stream *hda_stream;
+ struct snd_soc_pcm_runtime *rtd;
+ struct hdac_ext_link *link;
+ struct hdac_stream *hstream;
+ struct hdac_bus *bus;
+ int stream_tag;
int ret;
+ hstream = substream->runtime->private_data;
+ bus = hstream->bus;
+ rtd = snd_pcm_substream_chip(substream);
+
+ link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
+ if (!link)
+ return -EINVAL;
+
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
+
dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
@@ -217,8 +310,22 @@ static int hda_link_pcm_trigger(struct s
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_hdac_ext_link_stream_start(link_dev);
break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
+ /*
+ * clear and release link DMA channel. It will be assigned when
+ * hw_params is set up again after resume.
+ */
+ ret = hda_link_config_ipc(hda_stream, dai->name,
+ DMA_CHAN_INVALID, substream->stream);
+ if (ret < 0)
+ return ret;
+ stream_tag = hdac_stream(link_dev)->stream_tag;
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_stream_release(link_dev,
+ HDAC_EXT_STREAM_TYPE_LINK);
+
+ /* fallthrough */
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
snd_hdac_ext_link_stream_clear(link_dev);
break;
@@ -228,62 +335,38 @@ static int hda_link_pcm_trigger(struct s
return 0;
}
-/*
- * FIXME: This API is also abused since it's used for two purposes.
- * when the substream argument is NULL this function is used for cleanups
- * that aren't necessarily required, and called explicitly by handling
- * ASoC core structures, which is not recommended.
- * This part will be reworked in follow-up patches.
- */
static int hda_link_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- const char *name;
unsigned int stream_tag;
+ struct sof_intel_hda_stream *hda_stream;
struct hdac_bus *bus;
struct hdac_ext_link *link;
struct hdac_stream *hstream;
- struct hdac_ext_stream *stream;
struct snd_soc_pcm_runtime *rtd;
struct hdac_ext_stream *link_dev;
- struct snd_pcm_substream pcm_substream;
+ int ret;
- memset(&pcm_substream, 0, sizeof(pcm_substream));
- if (substream) {
- hstream = substream->runtime->private_data;
- bus = hstream->bus;
- rtd = snd_pcm_substream_chip(substream);
- link_dev = snd_soc_dai_get_dma_data(dai, substream);
- snd_hdac_ext_stream_decouple(bus, link_dev, false);
- name = rtd->codec_dai->component->name;
- link = snd_hdac_ext_bus_get_link(bus, name);
- if (!link)
- return -EINVAL;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
- }
+ hstream = substream->runtime->private_data;
+ bus = hstream->bus;
+ rtd = snd_pcm_substream_chip(substream);
+ link_dev = snd_soc_dai_get_dma_data(dai, substream);
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
- link_dev->link_prepared = 0;
- } else {
- /* release all hda streams when dai link is unloaded */
- pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
- if (stream) {
- snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
- snd_hdac_ext_stream_release(stream,
- HDAC_EXT_STREAM_TYPE_LINK);
- }
+ /* free the link DMA channel in the FW */
+ ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID,
+ substream->stream);
+ if (ret < 0)
+ return ret;
- pcm_substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
- if (stream) {
- snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
- snd_hdac_ext_stream_release(stream,
- HDAC_EXT_STREAM_TYPE_LINK);
- }
- }
+ link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
+ if (!link)
+ return -EINVAL;
+
+ stream_tag = hdac_stream(link_dev)->stream_tag;
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
+ link_dev->link_prepared = 0;
return 0;
}
@@ -293,7 +376,6 @@ static const struct snd_soc_dai_ops hda_
.hw_free = hda_link_hw_free,
.trigger = hda_link_pcm_trigger,
.prepare = hda_link_pcm_prepare,
- .get_channel_map = hda_link_dma_get_channels,
};
#endif
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda-dsp.c
linux-source-5.2/sound/soc/sof/intel/hda-dsp.c
--- linux-source-5.2-orig/sound/soc/sof/intel/hda-dsp.c 2019-08-16
04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda-dsp.c 2019-09-18
22:18:13.739172971 -0400
@@ -454,18 +454,45 @@ int hda_dsp_suspend(struct snd_sof_dev *
return 0;
}
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
struct sof_intel_hda_stream *hda_stream;
struct hdac_ext_stream *stream;
struct hdac_stream *s;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ struct snd_soc_pcm_runtime *rtd;
+ struct hdac_ext_link *link;
+ const char *name;
+#endif
+ int stream_tag;
+
/* set internal flag for BE */
list_for_each_entry(s, &bus->stream_list, list) {
stream = stream_to_hdac_ext_stream(s);
hda_stream = container_of(stream, struct sof_intel_hda_stream,
hda_stream);
hda_stream->hw_params_upon_resume = 1;
+ stream_tag = hdac_stream(stream)->stream_tag;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ /*
+ * clear and release stream. This should already be taken care
+ * for running streams when the SUSPEND trigger is called.
+ * But paused streams do not get suspended, so this needs to be
+ * done explicitly during suspend.
+ */
+ if (stream->link_substream) {
+ rtd = snd_pcm_substream_chip(stream->link_substream);
+ name = rtd->codec_dai->component->name;
+ link = snd_hdac_ext_bus_get_link(bus, name);
+ if (!link)
+ return -EINVAL;
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_stream_release(stream,
+ HDAC_EXT_STREAM_TYPE_LINK);
+ }
+#endif
}
+ return 0;
}
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda.h
linux-source-5.2/sound/soc/sof/intel/hda.h
--- linux-source-5.2-orig/sound/soc/sof/intel/hda.h 2019-08-16
04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda.h 2019-09-18 22:18:37.726615756
-0400
@@ -407,11 +407,15 @@ static inline struct hda_bus *sof_to_hbu
}
struct sof_intel_hda_stream {
+ struct snd_sof_dev *sdev;
struct hdac_ext_stream hda_stream;
struct sof_intel_stream stream;
int hw_params_upon_resume; /* set up hw_params upon resume */
};
+#define hstream_to_sof_hda_stream(hstream) \
+ container_of(hstream, struct sof_intel_hda_stream, hda_stream)
+
#define bus_to_sof_hda(bus) \
container_of(bus, struct sof_intel_hda_dev, hbus.core)
@@ -444,7 +448,7 @@ int hda_dsp_suspend(struct snd_sof_dev *
int hda_dsp_resume(struct snd_sof_dev *sdev);
int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state);
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
void hda_ipc_dump(struct snd_sof_dev *sdev);
diff -Naurp linux-source-5.2-orig/sound/soc/sof/intel/hda-stream.c
linux-source-5.2/sound/soc/sof/intel/hda-stream.c
--- linux-source-5.2-orig/sound/soc/sof/intel/hda-stream.c 2019-08-16
04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/intel/hda-stream.c 2019-09-18
22:18:37.726615756 -0400
@@ -564,6 +564,8 @@ int hda_dsp_stream_init(struct snd_sof_d
if (!hda_stream)
return -ENOMEM;
+ hda_stream->sdev = sdev;
+
stream = &hda_stream->hda_stream;
stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
@@ -617,6 +619,8 @@ int hda_dsp_stream_init(struct snd_sof_d
if (!hda_stream)
return -ENOMEM;
+ hda_stream->sdev = sdev;
+
stream = &hda_stream->hda_stream;
/* we always have DSP support */
diff -Naurp linux-source-5.2-orig/sound/soc/sof/ops.h
linux-source-5.2/sound/soc/sof/ops.h
--- linux-source-5.2-orig/sound/soc/sof/ops.h 2019-08-16 04:11:12.000000000
-0400
+++ linux-source-5.2/sound/soc/sof/ops.h 2019-09-18 22:18:13.739172971
-0400
@@ -134,10 +134,11 @@ static inline int snd_sof_dsp_runtime_su
return 0;
}
-static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
if (sof_ops(sdev)->set_hw_params_upon_resume)
- sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+ return sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+ return 0;
}
static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
diff -Naurp linux-source-5.2-orig/sound/soc/sof/pm.c
linux-source-5.2/sound/soc/sof/pm.c
--- linux-source-5.2-orig/sound/soc/sof/pm.c 2019-08-16 04:11:12.000000000
-0400
+++ linux-source-5.2/sound/soc/sof/pm.c 2019-09-18 22:18:13.739172971 -0400
@@ -153,6 +153,15 @@ static int sof_restore_pipelines(struct
continue;
}
+ /*
+ * The link DMA channel would be invalidated for running
+ * streams but not for streams that were in the PAUSED
+ * state during suspend. So invalidate it here before setting
+ * the dai config in the DSP.
+ */
+ if (config->type == SOF_DAI_INTEL_HDA)
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
ret = sof_ipc_tx_message(sdev->ipc,
config->hdr.cmd, config,
config->hdr.size,
@@ -204,7 +213,7 @@ static int sof_send_pm_ipc(struct snd_so
sizeof(pm_ctx), &reply, sizeof(reply));
}
-static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
struct snd_pcm_substream *substream;
struct snd_sof_pcm *spcm;
@@ -229,7 +238,7 @@ static void sof_set_hw_params_upon_resum
}
/* set internal flag for BE */
- snd_sof_dsp_hw_params_upon_resume(sdev);
+ return snd_sof_dsp_hw_params_upon_resume(sdev);
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
@@ -333,8 +342,15 @@ static int sof_suspend(struct device *de
snd_sof_release_trace(sdev);
/* set restore_stream for all streams during system suspend */
- if (!runtime_suspend)
- sof_set_hw_params_upon_resume(sdev);
+ if (!runtime_suspend) {
+ ret = sof_set_hw_params_upon_resume(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev,
+ "error: setting hw_params flag during suspend
%d\n",
+ ret);
+ return ret;
+ }
+ }
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
/* cache debugfs contents during runtime suspend */
@@ -343,11 +359,20 @@ static int sof_suspend(struct device *de
#endif
/* notify DSP of upcoming power down */
ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
- if (ret < 0) {
+ if (ret == -EBUSY || ret == -EAGAIN) {
+ /*
+ * runtime PM has logic to handle -EBUSY/-EAGAIN so
+ * pass these errors up
+ */
dev_err(sdev->dev,
"error: ctx_save ipc error during suspend %d\n",
ret);
return ret;
+ } else if (ret < 0) {
+ /* FW in unexpected state, continue to power down */
+ dev_warn(sdev->dev,
+ "ctx_save ipc error %d, proceeding with suspend\n",
+ ret);
}
/* power down all DSP cores */
diff -Naurp linux-source-5.2-orig/sound/soc/sof/sof-priv.h
linux-source-5.2/sound/soc/sof/sof-priv.h
--- linux-source-5.2-orig/sound/soc/sof/sof-priv.h 2019-08-16
04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/sof-priv.h 2019-09-18 22:18:13.743172859
-0400
@@ -56,6 +56,8 @@
#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT)
+#define DMA_CHAN_INVALID 0xFFFFFFFF
+
struct snd_sof_dev;
struct snd_sof_ipc_msg;
struct snd_sof_ipc;
@@ -166,7 +168,7 @@ struct snd_sof_dsp_ops {
int (*runtime_suspend)(struct snd_sof_dev *sof_dev,
int state); /* optional */
int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */
- void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /*
optional */
+ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional
*/
/* DSP clocking */
int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */
@@ -331,6 +333,7 @@ struct snd_sof_route {
struct snd_sof_dai {
struct snd_sof_dev *sdev;
const char *name;
+ const char *cpu_dai_name;
struct sof_ipc_comp_dai comp_dai;
struct sof_ipc_dai_config *dai_config;
diff -Naurp linux-source-5.2-orig/sound/soc/sof/topology.c
linux-source-5.2/sound/soc/sof/topology.c
--- linux-source-5.2-orig/sound/soc/sof/topology.c 2019-08-16
04:11:12.000000000 -0400
+++ linux-source-5.2/sound/soc/sof/topology.c 2019-09-18 22:18:22.970932678
-0400
@@ -2340,6 +2340,9 @@ static int sof_set_dai_config(struct snd
if (!dai->dai_config)
return -ENOMEM;
+ /* set cpu_dai_name */
+ dai->cpu_dai_name = link->cpu_dai_name;
+
found = 1;
}
}
@@ -2568,9 +2571,7 @@ err:
*/
static int sof_link_hda_process(struct snd_sof_dev *sdev,
struct snd_soc_dai_link *link,
- struct sof_ipc_dai_config *config,
- int tx_slot,
- int rx_slot)
+ struct sof_ipc_dai_config *config)
{
struct sof_ipc_reply reply;
u32 size = sizeof(*config);
@@ -2583,27 +2584,18 @@ static int sof_link_hda_process(struct s
continue;
if (strcmp(link->name, sof_dai->name) == 0) {
- if (sof_dai->comp_dai.direction ==
- SNDRV_PCM_STREAM_PLAYBACK) {
- if (!link->dpcm_playback)
- return -EINVAL;
-
- config->hda.link_dma_ch = tx_slot;
- } else {
- if (!link->dpcm_capture)
- return -EINVAL;
-
- config->hda.link_dma_ch = rx_slot;
- }
-
config->dai_index = sof_dai->comp_dai.dai_index;
found = 1;
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
/* save config in dai component */
sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL);
if (!sof_dai->dai_config)
return -ENOMEM;
+ sof_dai->cpu_dai_name = link->cpu_dai_name;
+
/* send message to DSP */
ret = sof_ipc_tx_message(sdev->ipc,
config->hdr.cmd, config, size,
@@ -2643,10 +2635,6 @@ static int sof_link_hda_load(struct snd_
struct snd_soc_tplg_private *private = &cfg->priv;
struct snd_soc_dai *dai;
u32 size = sizeof(*config);
- u32 tx_num = 0;
- u32 tx_slot = 0;
- u32 rx_num = 0;
- u32 rx_slot = 0;
int ret;
/* init IPC */
@@ -2672,22 +2660,7 @@ static int sof_link_hda_load(struct snd_
return -EINVAL;
}
- if (link->dpcm_playback)
- tx_num = 1;
-
- if (link->dpcm_capture)
- rx_num = 1;
-
- ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot,
- &rx_num, &rx_slot);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to get dma channel for
HDA%d\n",
- config->dai_index);
-
- return ret;
- }
-
- ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot);
+ ret = sof_link_hda_process(sdev, link, config);
if (ret < 0)
dev_err(sdev->dev, "error: failed to process hda dai link %s",
link->name);
@@ -2814,17 +2787,6 @@ static int sof_link_hda_unload(struct sn
return -EINVAL;
}
- /*
- * FIXME: this call to hw_free is mainly to release the link DMA ID.
- * This is abusing the API and handling SOC internals is not
- * recommended. This part will be reworked.
- */
- if (dai->driver->ops->hw_free)
- ret = dai->driver->ops->hw_free(NULL, dai);
- if (ret < 0)
- dev_err(sdev->dev, "error: failed to free hda resource for
%s\n",
- link->name);
-
return ret;
}
@@ -2998,6 +2960,49 @@ err:
return ret;
}
+/* Function to set the initial value of SOF kcontrols.
+ * The value will be stored in scontrol->control_data
+ */
+static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_control *scontrol = NULL;
+ int ipc_cmd, ctrl_type;
+ int ret = 0;
+
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
+
+ /* notify DSP of kcontrol values */
+ switch (scontrol->cmd) {
+ case SOF_CTRL_CMD_VOLUME:
+ case SOF_CTRL_CMD_ENUM:
+ case SOF_CTRL_CMD_SWITCH:
+ ipc_cmd = SOF_IPC_COMP_GET_VALUE;
+ ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET;
+ break;
+ case SOF_CTRL_CMD_BINARY:
+ ipc_cmd = SOF_IPC_COMP_GET_DATA;
+ ctrl_type = SOF_CTRL_TYPE_DATA_GET;
+ break;
+ default:
+ dev_err(sdev->dev,
+ "error: Invalid scontrol->cmd: %d\n",
+ scontrol->cmd);
+ return -EINVAL;
+ }
+ ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
+ ipc_cmd, ctrl_type,
+ scontrol->cmd,
+ false);
+ if (ret < 0) {
+ dev_warn(sdev->dev,
+ "error: kcontrol value get for widget: %d\n",
+ scontrol->comp_id);
+ }
+ }
+
+ return ret;
+}
+
int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget)
{
@@ -3041,6 +3046,11 @@ static void sof_complete(struct snd_soc_
break;
}
}
+ /*
+ * cache initial values of SOF kcontrols by reading DSP value over
+ * IPC. It may be overwritten by alsa-mixer after booting up
+ */
+ snd_sof_cache_kcontrol_val(sdev);
}
/* manifest - optional to inform component of manifest */
# Generic SOF selections
CONFIG_SND_SOC_SOF_TOPLEVEL=y
CONFIG_SND_SOC_SOF_PCI=m
CONFIG_SND_SOC_SOF_ACPI=m
# debug options
CONFIG_SND_SOC_SOF_DEBUG=y
CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC=y
CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE=y
CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE=y
CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST=y
# SOF Intel platform drivers
CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL=y
CONFIG_SND_SOC_SOF_BAYTRAIL_SUPPORT=y
CONFIG_SND_SOC_SOF_HASWELL_SUPPORT=y
CONFIG_SND_SOC_SOF_BROADWELL_SUPPORT=y
CONFIG_SND_SOC_SOF_MERRIFIELD_SUPPORT=y
CONFIG_SND_SOC_SOF_SKYLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_APOLLOLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_KABYLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_GEMINILAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_CANNONLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_COFFEELAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_ICELAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_COMETLAKE_LP_SUPPORT=y
CONFIG_SND_SOC_SOF_COMETLAKE_H_SUPPORT=y
CONFIG_SND_SOC_SOF_TIGERLAKE_SUPPORT=y
CONFIG_SND_SOC_SOF_ELKHARTLAKE_SUPPORT=y
# Intel machine drivers
CONFIG_SND_SOC_INTEL_HASWELL_MACH=m
CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH=m
CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m
CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m
CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH=m
CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH=m
CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH=m
CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH=m
CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH=m
CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH=m
CONFIG_SND_SOC_INTEL_BXT_RT298_MACH=m
CONFIG_SND_SOC_INTEL_BXT_PCM512x_MACH=m
CONFIG_SND_SOC_INTEL_BXT_WM8804_MACH=m
CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH=m
CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH=m
CONFIG_SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH=m
CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH=m
CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT700_MACH=m
CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH=m
CONFIG_SND_HDA_INTEL=m
# enable HDaudio support in SST
CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC=y
# enable HDaudio in SOF. this might be redundant with sof-mach-driver-defconfig
CONFIG_SND_SOC_SOF_HDA_LINK=y
CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC=y
# machine driver for HDaudio support
CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH=m
# HDaudio configs
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_CODEC_REALTEK=m
CONFIG_SND_HDA_CODEC_ANALOG=m
CONFIG_SND_HDA_CODEC_SIGMATEL=m
CONFIG_SND_HDA_CODEC_VIA=m
CONFIG_SND_HDA_CODEC_HDMI=m
CONFIG_SND_HDA_CODEC_CIRRUS=m
CONFIG_SND_HDA_CODEC_CONEXANT=m
CONFIG_SND_HDA_CODEC_CA0110=m
CONFIG_SND_HDA_CODEC_CA0132=m
CONFIG_SND_HDA_CODEC_CMEDIA=m
CONFIG_SND_HDA_CODEC_SI3054=m
CONFIG_SND_HDA_GENERIC=m
--- End Message ---