Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: SOF: IPC: dai: Expand DAI_CONFIG IPC flags

Some DAI components, such as HDaudio, need to be stopped in two steps
a) stop the DAI component
b) stop the DAI DMA

This patch enables this two-step stop by expanding the DAI_CONFIG
IPC flags and split them into 2 parts.

The 4 LSB bits indicate when the DAI_CONFIG IPC is sent, ex: hw_params,
hw_free or pause. The 4 MSB bits are used as the quirk flags to be used
along with the command flags. The quirk flag called
SOF_DAI_CONFIG_FLAGS_2_STEP_STOP shall be set along with the HW_PARAMS
command flag, i.e. before the pipeline is started so that the stop/pause
trigger op in the FW can take the appropriate action to either
perform/skip the DMA stop. If set, the DMA stop will be executed when
the DAI_CONFIG IPC is sent during hw_free. In the case of pause, DMA
pause will be handled when the DAI_CONFIG IPC is sent with the PAUSE
command flag.

Along with this, modify the signature for the hda_ctrl_dai_widget_setup/
hda_ctrl_dai_widget_free() functions to take additional flags as an
argument and modify all users to pass the appropriate quirk flags. Only
the HDA DAI's need to pass the SOF_DAI_CONFIG_FLAGS_2_STEP_STOP quirk
flag during hw_params to indicate that it supports two-step stop and
pause.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20211125101520.291581-10-kai.vehmanen@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Ranjani Sridharan and committed by
Mark Brown
a0f84dfb 0b639dcd

+44 -21
+19 -6
include/sound/sof/dai.h
··· 52 52 #define SOF_DAI_FMT_INV_MASK 0x0f00 53 53 #define SOF_DAI_FMT_CLOCK_PROVIDER_MASK 0xf000 54 54 55 - /* DAI_CONFIG flags */ 56 - #define SOF_DAI_CONFIG_FLAGS_MASK 0x3 57 - #define SOF_DAI_CONFIG_FLAGS_NONE (0 << 0) /**< DAI_CONFIG sent without stage information */ 58 - #define SOF_DAI_CONFIG_FLAGS_HW_PARAMS (1 << 0) /**< DAI_CONFIG sent during hw_params stage */ 59 - #define SOF_DAI_CONFIG_FLAGS_HW_FREE (2 << 0) /**< DAI_CONFIG sent during hw_free stage */ 60 - #define SOF_DAI_CONFIG_FLAGS_RFU (3 << 0) /**< not used, reserved for future use */ 55 + /* 56 + * DAI_CONFIG flags. The 4 LSB bits are used for the commands, HW_PARAMS, HW_FREE and PAUSE 57 + * representing when the IPC is sent. The 4 MSB bits are used to add quirks along with the above 58 + * commands. 59 + */ 60 + #define SOF_DAI_CONFIG_FLAGS_CMD_MASK 0xF 61 + #define SOF_DAI_CONFIG_FLAGS_NONE 0 /**< DAI_CONFIG sent without stage information */ 62 + #define SOF_DAI_CONFIG_FLAGS_HW_PARAMS BIT(0) /**< DAI_CONFIG sent during hw_params stage */ 63 + #define SOF_DAI_CONFIG_FLAGS_HW_FREE BIT(1) /**< DAI_CONFIG sent during hw_free stage */ 64 + /**< DAI_CONFIG sent during pause trigger. Only available ABI 3.20 onwards */ 65 + #define SOF_DAI_CONFIG_FLAGS_PAUSE BIT(2) 66 + #define SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT 4 67 + #define SOF_DAI_CONFIG_FLAGS_QUIRK_MASK (0xF << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT) 68 + /* 69 + * This should be used along with the SOF_DAI_CONFIG_FLAGS_HW_PARAMS to indicate that pipeline 70 + * stop/pause and DAI DMA stop/pause should happen in two steps. This change is only available 71 + * ABI 3.20 onwards. 72 + */ 73 + #define SOF_DAI_CONFIG_FLAGS_2_STEP_STOP BIT(0) 61 74 62 75 /** \brief Types of DAI */ 63 76 enum sof_ipc_dai_type {
+4 -4
sound/soc/sof/intel/hda-dai.c
··· 197 197 198 198 /* set up/free DAI widget and send DAI_CONFIG IPC */ 199 199 if (widget_setup) 200 - return hda_ctrl_dai_widget_setup(w); 200 + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP); 201 201 202 - return hda_ctrl_dai_widget_free(w); 202 + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); 203 203 } 204 204 205 205 static int hda_link_hw_params(struct snd_pcm_substream *substream, ··· 452 452 return 0; 453 453 454 454 if (setup) 455 - return hda_ctrl_dai_widget_setup(w); 455 + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE); 456 456 457 - return hda_ctrl_dai_widget_free(w); 457 + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); 458 458 } 459 459 460 460 static int ssp_dai_startup(struct snd_pcm_substream *substream,
+18 -8
sound/soc/sof/intel/hda.c
··· 41 41 #define EXCEPT_MAX_HDR_SIZE 0x400 42 42 #define HDA_EXT_ROM_STATUS_SIZE 8 43 43 44 - int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w) 44 + int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags) 45 45 { 46 46 struct snd_sof_widget *swidget = w->dobj.private; 47 47 struct snd_soc_component *component = swidget->scomp; ··· 58 58 return -EINVAL; 59 59 } 60 60 61 + /* DAI already configured, reset it before reconfiguring it */ 62 + if (sof_dai->configured) { 63 + ret = hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); 64 + if (ret < 0) 65 + return ret; 66 + } 67 + 61 68 config = &sof_dai->dai_config[sof_dai->current_config]; 62 69 63 70 /* ··· 78 71 return ret; 79 72 } 80 73 81 - /* set HW_PARAMS flag */ 82 - config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_HW_PARAMS); 74 + /* set HW_PARAMS flag along with quirks */ 75 + config->flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS | 76 + quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; 77 + 83 78 84 79 /* send DAI_CONFIG IPC */ 85 80 ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, ··· 96 87 return 0; 97 88 } 98 89 99 - int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w) 90 + int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags) 100 91 { 101 92 struct snd_sof_widget *swidget = w->dobj.private; 102 93 struct snd_soc_component *component = swidget->scomp; ··· 119 110 120 111 config = &sof_dai->dai_config[sof_dai->current_config]; 121 112 122 - /* set HW_FREE flag */ 123 - config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_HW_FREE); 113 + /* set HW_FREE flag along with any quirks */ 114 + config->flags = SOF_DAI_CONFIG_FLAGS_HW_FREE | 115 + quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; 124 116 125 117 ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, 126 118 &reply, sizeof(reply)); ··· 176 166 config->alh.stream_id = alh_stream_id; 177 167 178 168 if (setup) 179 - return hda_ctrl_dai_widget_setup(w); 169 + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE); 180 170 181 - return hda_ctrl_dai_widget_free(w); 171 + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); 182 172 } 183 173 184 174 static int sdw_params_stream(struct device *dev,
+2 -2
sound/soc/sof/intel/hda.h
··· 739 739 740 740 struct snd_sof_dai; 741 741 struct sof_ipc_dai_config; 742 - int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w); 743 - int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w); 742 + int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); 743 + int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); 744 744 745 745 #endif
+1 -1
sound/soc/sof/sof-audio.c
··· 57 57 } 58 58 59 59 /* set NONE flag to clear all previous settings */ 60 - config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_NONE); 60 + config->flags = SOF_DAI_CONFIG_FLAGS_NONE; 61 61 62 62 ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, 63 63 &reply, sizeof(reply));