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/hda-mlink.h> 11 #include <sound/sof/ipc4/header.h> 12 #include <uapi/sound/sof/header.h> 13 #include "../ipc4-priv.h" 14 #include "../ipc4-topology.h" 15 #include "../sof-priv.h" 16 #include "../sof-audio.h" 17 #include "hda.h" 18 19 /* These ops are only applicable for the HDA DAI's in their current form */ 20 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 21 /* 22 * This function checks if the host dma channel corresponding 23 * to the link DMA stream_tag argument is assigned to one 24 * of the FEs connected to the BE DAI. 25 */ 26 static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, 27 int dir, int stream_tag) 28 { 29 struct snd_pcm_substream *fe_substream; 30 struct hdac_stream *fe_hstream; 31 struct snd_soc_dpcm *dpcm; 32 33 for_each_dpcm_fe(rtd, dir, dpcm) { 34 fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir); 35 fe_hstream = fe_substream->runtime->private_data; 36 if (fe_hstream->stream_tag == stream_tag) 37 return true; 38 } 39 40 return false; 41 } 42 43 static struct hdac_ext_stream * 44 hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) 45 { 46 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 47 struct sof_intel_hda_stream *hda_stream; 48 const struct sof_intel_dsp_desc *chip; 49 struct snd_sof_dev *sdev; 50 struct hdac_ext_stream *res = NULL; 51 struct hdac_stream *hstream = NULL; 52 53 int stream_dir = substream->stream; 54 55 if (!bus->ppcap) { 56 dev_err(bus->dev, "stream type not supported\n"); 57 return NULL; 58 } 59 60 spin_lock_irq(&bus->reg_lock); 61 list_for_each_entry(hstream, &bus->stream_list, list) { 62 struct hdac_ext_stream *hext_stream = 63 stream_to_hdac_ext_stream(hstream); 64 if (hstream->direction != substream->stream) 65 continue; 66 67 hda_stream = hstream_to_sof_hda_stream(hext_stream); 68 sdev = hda_stream->sdev; 69 chip = get_chip_info(sdev->pdata); 70 71 /* check if link is available */ 72 if (!hext_stream->link_locked) { 73 /* 74 * choose the first available link for platforms that do not have the 75 * PROCEN_FMT_QUIRK set. 76 */ 77 if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) { 78 res = hext_stream; 79 break; 80 } 81 82 if (hstream->opened) { 83 /* 84 * check if the stream tag matches the stream 85 * tag of one of the connected FEs 86 */ 87 if (hda_check_fes(rtd, stream_dir, 88 hstream->stream_tag)) { 89 res = hext_stream; 90 break; 91 } 92 } else { 93 res = hext_stream; 94 95 /* 96 * This must be a hostless stream. 97 * So reserve the host DMA channel. 98 */ 99 hda_stream->host_reserved = 1; 100 break; 101 } 102 } 103 } 104 105 if (res) { 106 /* Make sure that host and link DMA is decoupled. */ 107 snd_hdac_ext_stream_decouple_locked(bus, res, true); 108 109 res->link_locked = 1; 110 res->link_substream = substream; 111 } 112 spin_unlock_irq(&bus->reg_lock); 113 114 return res; 115 } 116 117 static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev, 118 struct snd_soc_dai *cpu_dai, 119 struct snd_pcm_substream *substream) 120 { 121 return snd_soc_dai_get_dma_data(cpu_dai, substream); 122 } 123 124 static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, 125 struct snd_soc_dai *cpu_dai, 126 struct snd_pcm_substream *substream) 127 { 128 struct snd_sof_widget *pipe_widget; 129 struct sof_ipc4_pipeline *pipeline; 130 struct snd_sof_widget *swidget; 131 struct snd_soc_dapm_widget *w; 132 133 w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 134 swidget = w->dobj.private; 135 pipe_widget = swidget->spipe->pipe_widget; 136 pipeline = pipe_widget->private; 137 138 /* mark pipeline so that it can be skipped during FE trigger */ 139 pipeline->skip_during_fe_trigger = true; 140 141 return snd_soc_dai_get_dma_data(cpu_dai, substream); 142 } 143 144 static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, 145 struct snd_soc_dai *cpu_dai, 146 struct snd_pcm_substream *substream) 147 { 148 struct hdac_ext_stream *hext_stream; 149 150 hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); 151 if (!hext_stream) 152 return NULL; 153 154 snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream); 155 156 return hext_stream; 157 } 158 159 static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 160 struct snd_pcm_substream *substream) 161 { 162 struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); 163 164 snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); 165 snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); 166 } 167 168 static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, 169 unsigned int format_val) 170 { 171 snd_hdac_ext_stream_setup(hext_stream, format_val); 172 } 173 174 static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream) 175 { 176 snd_hdac_ext_stream_reset(hext_stream); 177 } 178 179 static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev, 180 struct snd_pcm_substream *substream, 181 struct hdac_stream *hstream) 182 { 183 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 184 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 185 186 /* set the hdac_stream in the codec dai */ 187 snd_soc_dai_set_stream(codec_dai, hstream, substream->stream); 188 } 189 190 static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev, 191 struct snd_pcm_substream *substream, 192 struct snd_pcm_hw_params *params) 193 { 194 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 195 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 196 unsigned int link_bps; 197 unsigned int format_val; 198 unsigned int bits; 199 200 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 201 link_bps = codec_dai->driver->playback.sig_bits; 202 else 203 link_bps = codec_dai->driver->capture.sig_bits; 204 205 bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD, 206 link_bps); 207 format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params)); 208 209 dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, 210 params_rate(params), params_channels(params), params_format(params)); 211 212 return format_val; 213 } 214 215 static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev, 216 struct snd_pcm_substream *substream) 217 { 218 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 219 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 220 struct hdac_bus *bus = sof_to_bus(sdev); 221 222 return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); 223 } 224 225 static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, 226 struct snd_pcm_substream *substream, 227 struct snd_pcm_hw_params *params) 228 { 229 unsigned int format_val; 230 unsigned int bits; 231 232 bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD, 233 params_physical_width(params)); 234 format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params)); 235 236 dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, 237 params_rate(params), params_channels(params), params_format(params)); 238 239 return format_val; 240 } 241 242 static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev, 243 struct snd_pcm_substream *substream, 244 struct snd_pcm_hw_params *params) 245 { 246 unsigned int format_val; 247 snd_pcm_format_t format; 248 unsigned int channels; 249 unsigned int width; 250 unsigned int bits; 251 252 channels = params_channels(params); 253 format = params_format(params); 254 width = params_physical_width(params); 255 256 if (format == SNDRV_PCM_FORMAT_S16_LE) { 257 format = SNDRV_PCM_FORMAT_S32_LE; 258 channels /= 2; 259 width = 32; 260 } 261 262 bits = snd_hdac_stream_format_bits(format, SNDRV_PCM_SUBFORMAT_STD, width); 263 format_val = snd_hdac_stream_format(channels, bits, params_rate(params)); 264 265 dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, 266 params_rate(params), channels, format); 267 268 return format_val; 269 } 270 271 static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, 272 struct snd_pcm_substream *substream) 273 { 274 struct hdac_bus *bus = sof_to_bus(sdev); 275 276 return hdac_bus_eml_ssp_get_hlink(bus); 277 } 278 279 static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev, 280 struct snd_pcm_substream *substream) 281 { 282 struct hdac_bus *bus = sof_to_bus(sdev); 283 284 return hdac_bus_eml_dmic_get_hlink(bus); 285 } 286 287 static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev, 288 struct snd_pcm_substream *substream) 289 { 290 struct hdac_bus *bus = sof_to_bus(sdev); 291 292 return hdac_bus_eml_sdw_get_hlink(bus); 293 } 294 295 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 296 struct snd_pcm_substream *substream, int cmd) 297 { 298 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 299 struct snd_sof_widget *pipe_widget; 300 struct sof_ipc4_pipeline *pipeline; 301 struct snd_sof_widget *swidget; 302 struct snd_soc_dapm_widget *w; 303 int ret = 0; 304 305 w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 306 swidget = w->dobj.private; 307 pipe_widget = swidget->spipe->pipe_widget; 308 pipeline = pipe_widget->private; 309 310 if (pipe_widget->instance_id < 0) 311 return 0; 312 313 mutex_lock(&ipc4_data->pipeline_state_mutex); 314 315 switch (cmd) { 316 case SNDRV_PCM_TRIGGER_START: 317 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 318 break; 319 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 320 case SNDRV_PCM_TRIGGER_SUSPEND: 321 case SNDRV_PCM_TRIGGER_STOP: 322 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 323 SOF_IPC4_PIPE_PAUSED); 324 if (ret < 0) 325 goto out; 326 327 pipeline->state = SOF_IPC4_PIPE_PAUSED; 328 break; 329 default: 330 dev_err(sdev->dev, "unknown trigger command %d\n", cmd); 331 ret = -EINVAL; 332 } 333 out: 334 mutex_unlock(&ipc4_data->pipeline_state_mutex); 335 return ret; 336 } 337 338 static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 339 struct snd_pcm_substream *substream, int cmd) 340 { 341 struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); 342 343 switch (cmd) { 344 case SNDRV_PCM_TRIGGER_START: 345 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 346 snd_hdac_ext_stream_start(hext_stream); 347 break; 348 case SNDRV_PCM_TRIGGER_SUSPEND: 349 case SNDRV_PCM_TRIGGER_STOP: 350 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 351 snd_hdac_ext_stream_clear(hext_stream); 352 break; 353 default: 354 dev_err(sdev->dev, "unknown trigger command %d\n", cmd); 355 return -EINVAL; 356 } 357 358 return 0; 359 } 360 361 static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 362 struct snd_pcm_substream *substream, int cmd) 363 { 364 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 365 struct snd_sof_widget *pipe_widget; 366 struct sof_ipc4_pipeline *pipeline; 367 struct snd_sof_widget *swidget; 368 struct snd_soc_dapm_widget *w; 369 int ret = 0; 370 371 w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 372 swidget = w->dobj.private; 373 pipe_widget = swidget->spipe->pipe_widget; 374 pipeline = pipe_widget->private; 375 376 if (pipe_widget->instance_id < 0) 377 return 0; 378 379 mutex_lock(&ipc4_data->pipeline_state_mutex); 380 381 switch (cmd) { 382 case SNDRV_PCM_TRIGGER_START: 383 if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { 384 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 385 SOF_IPC4_PIPE_PAUSED); 386 if (ret < 0) 387 goto out; 388 pipeline->state = SOF_IPC4_PIPE_PAUSED; 389 } 390 391 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 392 SOF_IPC4_PIPE_RUNNING); 393 if (ret < 0) 394 goto out; 395 pipeline->state = SOF_IPC4_PIPE_RUNNING; 396 swidget->spipe->started_count++; 397 break; 398 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 399 ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 400 SOF_IPC4_PIPE_RUNNING); 401 if (ret < 0) 402 goto out; 403 pipeline->state = SOF_IPC4_PIPE_RUNNING; 404 break; 405 case SNDRV_PCM_TRIGGER_SUSPEND: 406 case SNDRV_PCM_TRIGGER_STOP: 407 /* 408 * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have 409 * been stopped. So, clear the started_count so that the pipeline can be reset 410 */ 411 swidget->spipe->started_count = 0; 412 break; 413 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 414 break; 415 default: 416 dev_err(sdev->dev, "unknown trigger command %d\n", cmd); 417 ret = -EINVAL; 418 break; 419 } 420 out: 421 mutex_unlock(&ipc4_data->pipeline_state_mutex); 422 return ret; 423 } 424 425 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { 426 .get_hext_stream = hda_ipc4_get_hext_stream, 427 .assign_hext_stream = hda_assign_hext_stream, 428 .release_hext_stream = hda_release_hext_stream, 429 .setup_hext_stream = hda_setup_hext_stream, 430 .reset_hext_stream = hda_reset_hext_stream, 431 .pre_trigger = hda_ipc4_pre_trigger, 432 .trigger = hda_trigger, 433 .post_trigger = hda_ipc4_post_trigger, 434 .codec_dai_set_stream = hda_codec_dai_set_stream, 435 .calc_stream_format = hda_calc_stream_format, 436 .get_hlink = hda_get_hlink, 437 }; 438 439 static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = { 440 .get_hext_stream = hda_ipc4_get_hext_stream, 441 .assign_hext_stream = hda_assign_hext_stream, 442 .release_hext_stream = hda_release_hext_stream, 443 .setup_hext_stream = hda_setup_hext_stream, 444 .reset_hext_stream = hda_reset_hext_stream, 445 .pre_trigger = hda_ipc4_pre_trigger, 446 .trigger = hda_trigger, 447 .post_trigger = hda_ipc4_post_trigger, 448 .calc_stream_format = generic_calc_stream_format, 449 .get_hlink = ssp_get_hlink, 450 }; 451 452 static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { 453 .get_hext_stream = hda_ipc4_get_hext_stream, 454 .assign_hext_stream = hda_assign_hext_stream, 455 .release_hext_stream = hda_release_hext_stream, 456 .setup_hext_stream = hda_setup_hext_stream, 457 .reset_hext_stream = hda_reset_hext_stream, 458 .pre_trigger = hda_ipc4_pre_trigger, 459 .trigger = hda_trigger, 460 .post_trigger = hda_ipc4_post_trigger, 461 .calc_stream_format = dmic_calc_stream_format, 462 .get_hlink = dmic_get_hlink, 463 }; 464 465 static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { 466 .get_hext_stream = hda_ipc4_get_hext_stream, 467 .assign_hext_stream = hda_assign_hext_stream, 468 .release_hext_stream = hda_release_hext_stream, 469 .setup_hext_stream = hda_setup_hext_stream, 470 .reset_hext_stream = hda_reset_hext_stream, 471 .pre_trigger = hda_ipc4_pre_trigger, 472 .trigger = hda_trigger, 473 .post_trigger = hda_ipc4_post_trigger, 474 .calc_stream_format = generic_calc_stream_format, 475 .get_hlink = sdw_get_hlink, 476 }; 477 478 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { 479 .get_hext_stream = hda_get_hext_stream, 480 .assign_hext_stream = hda_assign_hext_stream, 481 .release_hext_stream = hda_release_hext_stream, 482 .setup_hext_stream = hda_setup_hext_stream, 483 .reset_hext_stream = hda_reset_hext_stream, 484 .trigger = hda_trigger, 485 .codec_dai_set_stream = hda_codec_dai_set_stream, 486 .calc_stream_format = hda_calc_stream_format, 487 .get_hlink = hda_get_hlink, 488 }; 489 490 static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = { 491 .get_hext_stream = hda_get_hext_stream, 492 .assign_hext_stream = hda_assign_hext_stream, 493 .release_hext_stream = hda_release_hext_stream, 494 .setup_hext_stream = hda_setup_hext_stream, 495 .reset_hext_stream = hda_reset_hext_stream, 496 .trigger = hda_trigger, 497 .calc_stream_format = generic_calc_stream_format, 498 .get_hlink = sdw_get_hlink, 499 }; 500 501 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 502 struct snd_pcm_substream *substream, int cmd) 503 { 504 struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); 505 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 506 507 switch (cmd) { 508 case SNDRV_PCM_TRIGGER_SUSPEND: 509 case SNDRV_PCM_TRIGGER_STOP: 510 { 511 struct snd_sof_dai_config_data data = { 0 }; 512 int ret; 513 514 data.dai_data = DMA_CHAN_INVALID; 515 ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); 516 if (ret < 0) 517 return ret; 518 519 if (cmd == SNDRV_PCM_TRIGGER_STOP) 520 return hda_link_dma_cleanup(substream, hext_stream, cpu_dai); 521 522 break; 523 } 524 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 525 return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); 526 default: 527 break; 528 } 529 530 return 0; 531 } 532 533 static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = { 534 .get_hext_stream = hda_get_hext_stream, 535 .assign_hext_stream = hda_assign_hext_stream, 536 .release_hext_stream = hda_release_hext_stream, 537 .setup_hext_stream = hda_setup_hext_stream, 538 .reset_hext_stream = hda_reset_hext_stream, 539 .trigger = hda_trigger, 540 .post_trigger = hda_ipc3_post_trigger, 541 .codec_dai_set_stream = hda_codec_dai_set_stream, 542 .calc_stream_format = hda_calc_stream_format, 543 .get_hlink = hda_get_hlink, 544 }; 545 546 static struct hdac_ext_stream * 547 hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 548 struct snd_pcm_substream *substream) 549 { 550 struct hdac_stream *hstream = substream->runtime->private_data; 551 552 return stream_to_hdac_ext_stream(hstream); 553 } 554 555 static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev, 556 struct hdac_ext_stream *hext_stream, 557 unsigned int format_val) 558 { 559 /* 560 * Save the format_val which was adjusted by the maxbps of the codec. 561 * This information is not available on the FE side since there we are 562 * using dummy_codec. 563 */ 564 hext_stream->hstream.format_val = format_val; 565 } 566 567 static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = { 568 .get_hext_stream = hda_dspless_get_hext_stream, 569 .setup_hext_stream = hda_dspless_setup_hext_stream, 570 .codec_dai_set_stream = hda_codec_dai_set_stream, 571 .calc_stream_format = hda_calc_stream_format, 572 .get_hlink = hda_get_hlink, 573 }; 574 575 static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = { 576 .get_hext_stream = hda_dspless_get_hext_stream, 577 .setup_hext_stream = hda_dspless_setup_hext_stream, 578 .calc_stream_format = generic_calc_stream_format, 579 .get_hlink = sdw_get_hlink, 580 }; 581 582 #endif 583 584 const struct hda_dai_widget_dma_ops * 585 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 586 { 587 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 588 struct snd_sof_dai *sdai; 589 const struct sof_intel_dsp_desc *chip; 590 591 chip = get_chip_info(sdev->pdata); 592 sdai = swidget->private; 593 594 if (sdev->dspless_mode_selected) { 595 switch (sdai->type) { 596 case SOF_DAI_INTEL_HDA: 597 return &hda_dspless_dma_ops; 598 case SOF_DAI_INTEL_ALH: 599 if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) 600 return NULL; 601 return &sdw_dspless_dma_ops; 602 default: 603 return NULL; 604 } 605 } 606 607 switch (sdev->pdata->ipc_type) { 608 case SOF_IPC_TYPE_3: 609 { 610 struct sof_dai_private_data *private = sdai->private; 611 612 if (private->dai_config->type == SOF_DAI_INTEL_HDA) 613 return &hda_ipc3_dma_ops; 614 break; 615 } 616 case SOF_IPC_TYPE_4: 617 { 618 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 619 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 620 621 switch (sdai->type) { 622 case SOF_DAI_INTEL_HDA: 623 if (pipeline->use_chain_dma) 624 return &hda_ipc4_chain_dma_ops; 625 626 return &hda_ipc4_dma_ops; 627 case SOF_DAI_INTEL_SSP: 628 if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) 629 return NULL; 630 return &ssp_ipc4_dma_ops; 631 case SOF_DAI_INTEL_DMIC: 632 if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) 633 return NULL; 634 return &dmic_ipc4_dma_ops; 635 case SOF_DAI_INTEL_ALH: 636 if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) 637 return NULL; 638 if (pipeline->use_chain_dma) 639 return &sdw_ipc4_chain_dma_ops; 640 return &sdw_ipc4_dma_ops; 641 642 default: 643 break; 644 } 645 break; 646 } 647 default: 648 break; 649 } 650 #endif 651 return NULL; 652 } 653