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

Configure Feed

Select the types of activity you want to include in your feed.

ASoC/SoundWire: clean up link DMA during stop for IPC4

Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>:

Clean up the link DMA for playback during stop for IPC4 is required to
reset the DMA read/write pointers when the stream is prepared and
restarted after a call to snd_pcm_drain()/snd_pcm_drop().

The change is mainly on ASoC. We may go via ASoC tree with Vinod's
Acked-by tag

Ranjani Sridharan (4):
ASoC: SOF: ipc4-topology: Do not set ALH node_id for aggregated DAIs
ASoC: SOF: Intel: hda: Handle prepare without close for non-HDA DAI's
soundwire: intel_ace2x: Send PDI stream number during prepare
ASoC: SOF: Intel: hda: Always clean up link DMA during stop

drivers/soundwire/intel_ace2x.c | 19 +++++-----------
sound/soc/sof/intel/hda-dai-ops.c | 23 +++++++++----------
sound/soc/sof/intel/hda-dai.c | 37 +++++++++++++++++++++++++++----
sound/soc/sof/ipc4-topology.c | 15 +++++++++++--
4 files changed, 62 insertions(+), 32 deletions(-)

--
2.43.0

+62 -32
+6 -13
drivers/soundwire/intel_ace2x.c
··· 376 376 static int intel_prepare(struct snd_pcm_substream *substream, 377 377 struct snd_soc_dai *dai) 378 378 { 379 + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 379 380 struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 380 381 struct sdw_intel *sdw = cdns_to_intel(cdns); 381 382 struct sdw_cdns_dai_runtime *dai_runtime; 383 + struct snd_pcm_hw_params *hw_params; 382 384 int ch, dir; 383 - int ret = 0; 384 385 385 386 dai_runtime = cdns->dai_runtime_array[dai->id]; 386 387 if (!dai_runtime) { ··· 390 389 return -EIO; 391 390 } 392 391 392 + hw_params = &rtd->dpcm[substream->stream].hw_params; 393 393 if (dai_runtime->suspended) { 394 - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 395 - struct snd_pcm_hw_params *hw_params; 396 - 397 - hw_params = &rtd->dpcm[substream->stream].hw_params; 398 - 399 394 dai_runtime->suspended = false; 400 395 401 396 /* ··· 412 415 /* the SHIM will be configured in the callback functions */ 413 416 414 417 sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi); 415 - 416 - /* Inform DSP about PDI stream number */ 417 - ret = intel_params_stream(sdw, substream, dai, 418 - hw_params, 419 - sdw->instance, 420 - dai_runtime->pdi->intel_alh_id); 421 418 } 422 419 423 - return ret; 420 + /* Inform DSP about PDI stream number */ 421 + return intel_params_stream(sdw, substream, dai, hw_params, sdw->instance, 422 + dai_runtime->pdi->intel_alh_id); 424 423 } 425 424 426 425 static int
+10 -13
sound/soc/sof/intel/hda-dai-ops.c
··· 346 346 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 347 347 snd_hdac_ext_stream_start(hext_stream); 348 348 break; 349 - case SNDRV_PCM_TRIGGER_SUSPEND: 350 - case SNDRV_PCM_TRIGGER_STOP: 351 349 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 352 - snd_hdac_ext_stream_clear(hext_stream); 353 - 354 350 /* 355 - * Save the LLP registers in case the stream is 356 - * restarting due PAUSE_RELEASE, or START without a pcm 357 - * close/open since in this case the LLP register is not reset 358 - * to 0 and the delay calculation will return with invalid 359 - * results. 351 + * Save the LLP registers since in case of PAUSE the LLP 352 + * register are not reset to 0, the delay calculation will use 353 + * the saved offsets for compensating the delay calculation. 360 354 */ 361 355 hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL); 362 356 hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU); 357 + snd_hdac_ext_stream_clear(hext_stream); 358 + break; 359 + case SNDRV_PCM_TRIGGER_SUSPEND: 360 + case SNDRV_PCM_TRIGGER_STOP: 361 + hext_stream->pplcllpl = 0; 362 + hext_stream->pplcllpu = 0; 363 + snd_hdac_ext_stream_clear(hext_stream); 363 364 break; 364 365 default: 365 366 dev_err(sdev->dev, "unknown trigger command %d\n", cmd); ··· 513 512 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, 514 513 struct snd_pcm_substream *substream, int cmd) 515 514 { 516 - struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); 517 515 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 518 516 519 517 switch (cmd) { ··· 526 526 ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); 527 527 if (ret < 0) 528 528 return ret; 529 - 530 - if (cmd == SNDRV_PCM_TRIGGER_STOP) 531 - return hda_link_dma_cleanup(substream, hext_stream, cpu_dai); 532 529 533 530 break; 534 531 }
+33 -4
sound/soc/sof/intel/hda-dai.c
··· 302 302 } 303 303 304 304 switch (cmd) { 305 + case SNDRV_PCM_TRIGGER_STOP: 305 306 case SNDRV_PCM_TRIGGER_SUSPEND: 306 307 ret = hda_link_dma_cleanup(substream, hext_stream, dai); 307 308 if (ret < 0) { ··· 371 370 return -EINVAL; 372 371 } 373 372 373 + sdev = widget_to_sdev(w); 374 + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 375 + 376 + /* nothing more to do if the link is already prepared */ 377 + if (hext_stream && hext_stream->link_prepared) 378 + return 0; 379 + 374 380 /* use HDaudio stream handling */ 375 381 ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags); 376 382 if (ret < 0) { ··· 385 377 return ret; 386 378 } 387 379 388 - sdev = widget_to_sdev(w); 389 380 if (sdev->dspless_mode_selected) 390 381 return 0; 391 382 ··· 489 482 int ret; 490 483 int i; 491 484 485 + ops = hda_dai_get_ops(substream, cpu_dai); 486 + if (!ops) { 487 + dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 488 + return -EINVAL; 489 + } 490 + 491 + sdev = widget_to_sdev(w); 492 + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 493 + 494 + /* nothing more to do if the link is already prepared */ 495 + if (hext_stream && hext_stream->link_prepared) 496 + return 0; 497 + 498 + /* 499 + * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted 500 + * due to xruns or after a call to snd_pcm_drain/drop() 501 + */ 502 + ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, 503 + 0, 0, substream->stream); 504 + if (ret < 0) { 505 + dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", 506 + __func__, ret); 507 + return ret; 508 + } 509 + 492 510 data.dai_index = (link_id << 8) | cpu_dai->id; 493 511 data.dai_node_id = intel_alh_id; 494 512 ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags); ··· 522 490 return ret; 523 491 } 524 492 525 - ops = hda_dai_get_ops(substream, cpu_dai); 526 - sdev = widget_to_sdev(w); 527 493 hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 528 - 529 494 if (!hext_stream) 530 495 return -ENODEV; 531 496
+13 -2
sound/soc/sof/ipc4-topology.c
··· 3129 3129 * group_id during copier's ipc_prepare op. 3130 3130 */ 3131 3131 if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { 3132 + struct sof_ipc4_alh_configuration_blob *blob; 3133 + 3134 + blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 3132 3135 ipc4_copier->dai_index = data->dai_node_id; 3133 - copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 3134 - copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_node_id); 3136 + 3137 + /* 3138 + * no need to set the node_id for aggregated DAI's. These will be assigned 3139 + * a group_id during widget ipc_prepare 3140 + */ 3141 + if (blob->alh_cfg.device_count == 1) { 3142 + copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 3143 + copier_data->gtw_cfg.node_id |= 3144 + SOF_IPC4_NODE_INDEX(data->dai_node_id); 3145 + } 3135 3146 } 3136 3147 3137 3148 break;