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