1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2022 Intel Corporation. All rights reserved. 7 8 #include <sound/pcm_params.h> 9 #include <sound/hdaudio_ext.h> 10 #include <sound/sof/ipc4/header.h> 11 #include <uapi/sound/sof/header.h> 12 #include "../ipc4-priv.h" 13 #include "../ipc4-topology.h" 14 #include "../sof-priv.h" 15 #include "../sof-audio.h" 16 #include "hda.h" 17 18 /* These ops are only applicable for the HDA DAI's in their current form */ 19 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 20 /* 21 * This function checks if the host dma channel corresponding 22 * to the link DMA stream_tag argument is assigned to one 23 * of the FEs connected to the BE DAI. 24 */ 25 static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, 26 int dir, int stream_tag) 27 { 28 struct snd_pcm_substream *fe_substream; 29 struct hdac_stream *fe_hstream; 30 struct snd_soc_dpcm *dpcm; 31 32 for_each_dpcm_fe(rtd, dir, dpcm) { 33 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir); 34 fe_hstream = fe_substream->runtime->private_data; 35 if (fe_hstream->stream_tag == stream_tag) 36 return true; 37 } 38 39 return false; 40 } 41 42 static struct hdac_ext_stream * 43 hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) 44 { 45 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 46 struct sof_intel_hda_stream *hda_stream; 47 const struct sof_intel_dsp_desc *chip; 48 struct snd_sof_dev *sdev; 49 struct hdac_ext_stream *res = NULL; 50 struct hdac_stream *hstream = NULL; 51 52 int stream_dir = substream->stream; 53 54 if (!bus->ppcap) { 55 dev_err(bus->dev, "stream type not supported\n"); 56 return NULL; 57 } 58 59 spin_lock_irq(&bus->reg_lock); 60 list_for_each_entry(hstream, &bus->stream_list, list) { 61 struct hdac_ext_stream *hext_stream = 62 stream_to_hdac_ext_stream(hstream); 63 if (hstream->direction != substream->stream) 64 continue; 65 66 hda_stream = hstream_to_sof_hda_stream(hext_stream); 67 sdev = hda_stream->sdev; 68 chip = get_chip_info(sdev->pdata); 69 70 /* check if link is available */ 71 if (!hext_stream->link_locked) { 72 /* 73 * choose the first available link for platforms that do not have the 74 * PROCEN_FMT_QUIRK set. 75 */ 76 if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) { 77 res = hext_stream; 78 break; 79 } 80 81 if (hstream->opened) { 82 /* 83 * check if the stream tag matches the stream 84 * tag of one of the connected FEs 85 */ 86 if (hda_check_fes(rtd, stream_dir, 87 hstream->stream_tag)) { 88 res = hext_stream; 89 break; 90 } 91 } else { 92 res = hext_stream; 93 94 /* 95 * This must be a hostless stream. 96 * So reserve the host DMA channel. 97 */ 98 hda_stream->host_reserved = 1; 99 break; 100 } 101 } 102 } 103 104 if (res) { 105 /* Make sure that host and link DMA is decoupled. */ 106 snd_hdac_ext_stream_decouple_locked(bus, res, true); 107 108 res->link_locked = 1; 109 res->link_substream = substream; 110 } 111 spin_unlock_irq(&bus->reg_lock); 112 113 return res; 114 } 115 116 static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev, 117 struct snd_soc_dai *cpu_dai, 118 struct snd_pcm_substream *substream) 119 { 120 return snd_soc_dai_get_dma_data(cpu_dai, substream); 121 } 122 123 static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, 124 struct snd_soc_dai *cpu_dai, 125 struct snd_pcm_substream *substream) 126 { 127 struct snd_sof_widget *pipe_widget; 128 struct sof_ipc4_pipeline *pipeline; 129 struct snd_sof_widget *swidget; 130 struct snd_soc_dapm_widget *w; 131 132 w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 133 swidget = w->dobj.private; 134 pipe_widget = swidget->spipe->pipe_widget; 135 pipeline = pipe_widget->private; 136 137 /* mark pipeline so that it can be skipped during FE trigger */ 138 pipeline->skip_during_fe_trigger = true; 139 140 return snd_soc_dai_get_dma_data(cpu_dai, substream); 141 } 142 143 static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, 144 struct snd_soc_dai *cpu_dai, 145 struct snd_pcm_substream *substream) 146 { 147 struct hdac_ext_stream *hext_stream; 148 149 hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); 150 if (!hext_stream) 151 return NULL; 152 153 snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream); 154 155 return hext_stream; 156 } 157 158 static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 159 struct snd_pcm_substream *substream) 160 { 161 struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); 162 163 snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); 164 snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); 165 } 166 167 static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, 168 unsigned int format_val) 169 { 170 snd_hdac_ext_stream_setup(hext_stream, format_val); 171 } 172 173 static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream) 174 { 175 snd_hdac_ext_stream_reset(hext_stream); 176 } 177 178 static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev, 179 struct snd_pcm_substream *substream, 180 struct hdac_stream *hstream) 181 { 182 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 183 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 184 185 /* set the hdac_stream in the codec dai */ 186 snd_soc_dai_set_stream(codec_dai, hstream, substream->stream); 187 } 188 189 static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev, 190 struct snd_pcm_substream *substream, 191 struct snd_pcm_hw_params *params) 192 { 193 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 194 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 195 unsigned int link_bps; 196 unsigned int format_val; 197 198 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 199 link_bps = codec_dai->driver->playback.sig_bits; 200 else 201 link_bps = codec_dai->driver->capture.sig_bits; 202 203 format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), 204 params_format(params), link_bps, 0); 205 206 dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, 207 params_rate(params), params_channels(params), params_format(params)); 208 209 return format_val; 210 } 211 212 static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev, 213 struct snd_pcm_substream *substream) 214 { 215 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 216 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 217 struct hdac_bus *bus = sof_to_bus(sdev); 218 219 return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); 220 } 221 222 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 223 struct snd_pcm_substream *substream, int cmd) 224 { 225 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 226 struct snd_sof_widget *pipe_widget; 227 struct sof_ipc4_pipeline *pipeline; 228 struct snd_sof_widget *swidget; 229 struct snd_soc_dapm_widget *w; 230 int ret = 0; 231 232 w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 233 swidget = w->dobj.private; 234 pipe_widget = swidget->spipe->pipe_widget; 235 pipeline = pipe_widget->private; 236 237 mutex_lock(&ipc4_data->pipeline_state_mutex); 238 239 switch (cmd) { 240 case SNDRV_PCM_TRIGGER_START: 241 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 242 break; 243 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 244 case SNDRV_PCM_TRIGGER_SUSPEND: 245 case SNDRV_PCM_TRIGGER_STOP: 246 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 247 SOF_IPC4_PIPE_PAUSED); 248 if (ret < 0) 249 goto out; 250 251 pipeline->state = SOF_IPC4_PIPE_PAUSED; 252 break; 253 default: 254 dev_err(sdev->dev, "unknown trigger command %d\n", cmd); 255 ret = -EINVAL; 256 } 257 out: 258 mutex_unlock(&ipc4_data->pipeline_state_mutex); 259 return ret; 260 } 261 262 static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 263 struct snd_pcm_substream *substream, int cmd) 264 { 265 struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); 266 267 switch (cmd) { 268 case SNDRV_PCM_TRIGGER_START: 269 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 270 snd_hdac_ext_stream_start(hext_stream); 271 break; 272 case SNDRV_PCM_TRIGGER_SUSPEND: 273 case SNDRV_PCM_TRIGGER_STOP: 274 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 275 snd_hdac_ext_stream_clear(hext_stream); 276 break; 277 default: 278 dev_err(sdev->dev, "unknown trigger command %d\n", cmd); 279 return -EINVAL; 280 } 281 282 return 0; 283 } 284 285 static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 286 struct snd_pcm_substream *substream, int cmd) 287 { 288 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 289 struct snd_sof_widget *pipe_widget; 290 struct sof_ipc4_pipeline *pipeline; 291 struct snd_sof_widget *swidget; 292 struct snd_soc_dapm_widget *w; 293 int ret = 0; 294 295 w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 296 swidget = w->dobj.private; 297 pipe_widget = swidget->spipe->pipe_widget; 298 pipeline = pipe_widget->private; 299 300 mutex_lock(&ipc4_data->pipeline_state_mutex); 301 302 switch (cmd) { 303 case SNDRV_PCM_TRIGGER_START: 304 if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { 305 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 306 SOF_IPC4_PIPE_PAUSED); 307 if (ret < 0) 308 goto out; 309 pipeline->state = SOF_IPC4_PIPE_PAUSED; 310 } 311 312 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 313 SOF_IPC4_PIPE_RUNNING); 314 if (ret < 0) 315 goto out; 316 pipeline->state = SOF_IPC4_PIPE_RUNNING; 317 swidget->spipe->started_count++; 318 break; 319 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 320 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 321 SOF_IPC4_PIPE_RUNNING); 322 if (ret < 0) 323 goto out; 324 pipeline->state = SOF_IPC4_PIPE_RUNNING; 325 break; 326 case SNDRV_PCM_TRIGGER_SUSPEND: 327 case SNDRV_PCM_TRIGGER_STOP: 328 /* 329 * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have 330 * been stopped. So, clear the started_count so that the pipeline can be reset 331 */ 332 swidget->spipe->started_count = 0; 333 break; 334 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 335 break; 336 default: 337 dev_err(sdev->dev, "unknown trigger command %d\n", cmd); 338 ret = -EINVAL; 339 break; 340 } 341 out: 342 mutex_unlock(&ipc4_data->pipeline_state_mutex); 343 return ret; 344 } 345 346 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { 347 .get_hext_stream = hda_ipc4_get_hext_stream, 348 .assign_hext_stream = hda_assign_hext_stream, 349 .release_hext_stream = hda_release_hext_stream, 350 .setup_hext_stream = hda_setup_hext_stream, 351 .reset_hext_stream = hda_reset_hext_stream, 352 .pre_trigger = hda_ipc4_pre_trigger, 353 .trigger = hda_trigger, 354 .post_trigger = hda_ipc4_post_trigger, 355 .codec_dai_set_stream = hda_codec_dai_set_stream, 356 .calc_stream_format = hda_calc_stream_format, 357 .get_hlink = hda_get_hlink, 358 }; 359 360 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { 361 .get_hext_stream = hda_get_hext_stream, 362 .assign_hext_stream = hda_assign_hext_stream, 363 .release_hext_stream = hda_release_hext_stream, 364 .setup_hext_stream = hda_setup_hext_stream, 365 .reset_hext_stream = hda_reset_hext_stream, 366 .trigger = hda_trigger, 367 .codec_dai_set_stream = hda_codec_dai_set_stream, 368 .calc_stream_format = hda_calc_stream_format, 369 .get_hlink = hda_get_hlink, 370 }; 371 372 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 373 struct snd_pcm_substream *substream, int cmd) 374 { 375 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 376 377 switch (cmd) { 378 case SNDRV_PCM_TRIGGER_SUSPEND: 379 case SNDRV_PCM_TRIGGER_STOP: 380 { 381 struct snd_sof_dai_config_data data = { 0 }; 382 383 data.dai_data = DMA_CHAN_INVALID; 384 return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); 385 } 386 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 387 return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); 388 default: 389 break; 390 } 391 392 return 0; 393 } 394 395 static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = { 396 .get_hext_stream = hda_get_hext_stream, 397 .assign_hext_stream = hda_assign_hext_stream, 398 .release_hext_stream = hda_release_hext_stream, 399 .setup_hext_stream = hda_setup_hext_stream, 400 .reset_hext_stream = hda_reset_hext_stream, 401 .trigger = hda_trigger, 402 .post_trigger = hda_ipc3_post_trigger, 403 .codec_dai_set_stream = hda_codec_dai_set_stream, 404 .calc_stream_format = hda_calc_stream_format, 405 .get_hlink = hda_get_hlink, 406 }; 407 408 static struct hdac_ext_stream * 409 hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 410 struct snd_pcm_substream *substream) 411 { 412 struct hdac_stream *hstream = substream->runtime->private_data; 413 414 return stream_to_hdac_ext_stream(hstream); 415 } 416 417 static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev, 418 struct hdac_ext_stream *hext_stream, 419 unsigned int format_val) 420 { 421 /* 422 * Save the format_val which was adjusted by the maxbps of the codec. 423 * This information is not available on the FE side since there we are 424 * using dummy_codec. 425 */ 426 hext_stream->hstream.format_val = format_val; 427 } 428 429 static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = { 430 .get_hext_stream = hda_dspless_get_hext_stream, 431 .setup_hext_stream = hda_dspless_setup_hext_stream, 432 .codec_dai_set_stream = hda_codec_dai_set_stream, 433 .calc_stream_format = hda_calc_stream_format, 434 .get_hlink = hda_get_hlink, 435 }; 436 437 #endif 438 439 const struct hda_dai_widget_dma_ops * 440 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 441 { 442 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 443 struct snd_sof_dai *sdai; 444 445 if (sdev->dspless_mode_selected) 446 return &hda_dspless_dma_ops; 447 448 sdai = swidget->private; 449 450 switch (sdev->pdata->ipc_type) { 451 case SOF_IPC: 452 { 453 struct sof_dai_private_data *private = sdai->private; 454 455 if (private->dai_config->type == SOF_DAI_INTEL_HDA) 456 return &hda_ipc3_dma_ops; 457 break; 458 } 459 case SOF_INTEL_IPC4: 460 { 461 struct sof_ipc4_copier *ipc4_copier = sdai->private; 462 463 if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) { 464 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 465 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 466 467 if (pipeline->use_chain_dma) 468 return &hda_ipc4_chain_dma_ops; 469 470 return &hda_ipc4_dma_ops; 471 } 472 break; 473 } 474 default: 475 break; 476 } 477 #endif 478 return NULL; 479 } 480