Unverified Commit 2775f88b authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: SOF: Extend ChainDMA and DSPless mode to LNL+

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

For both ChainDMA and DSPless mode the requirement is that the link must
be serviced by HD-DMA.
On pre Lunar Lake platforms this was only valid for HDAudio links but with
Lunar Lake all link types now serviced by HD-DMA.

This allows us to enable ChainDMA and DSPless mode for SoundWire links as
well.
parents fd236653 2065610b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
	/* DAI drivers */
	.drv		= skl_dai,
	.num_drv	= SOF_SKL_NUM_DAIS,
	.is_chain_dma_supported	= hda_is_chain_dma_supported,

	/* PM */
	.suspend		= hda_dsp_suspend,
+38 −13
Original line number Diff line number Diff line
@@ -522,6 +522,17 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
	.get_hlink = hda_get_hlink,
};

static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
	.get_hext_stream = hda_get_hext_stream,
	.assign_hext_stream = hda_assign_hext_stream,
	.release_hext_stream = hda_release_hext_stream,
	.setup_hext_stream = hda_setup_hext_stream,
	.reset_hext_stream = hda_reset_hext_stream,
	.trigger = hda_trigger,
	.calc_stream_format = generic_calc_stream_format,
	.get_hlink = sdw_get_hlink,
};

static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
				 struct snd_pcm_substream *substream, int cmd)
{
@@ -596,6 +607,13 @@ static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
	.get_hlink = hda_get_hlink,
};

static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {
	.get_hext_stream = hda_dspless_get_hext_stream,
	.setup_hext_stream = hda_dspless_setup_hext_stream,
	.calc_stream_format = generic_calc_stream_format,
	.get_hlink = sdw_get_hlink,
};

#endif

const struct hda_dai_widget_dma_ops *
@@ -603,12 +621,24 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
	struct snd_sof_dai *sdai;
	const struct sof_intel_dsp_desc *chip;

	if (sdev->dspless_mode_selected)
		return &hda_dspless_dma_ops;

	chip = get_chip_info(sdev->pdata);
	sdai = swidget->private;

	if (sdev->dspless_mode_selected) {
		switch (sdai->type) {
		case SOF_DAI_INTEL_HDA:
			return &hda_dspless_dma_ops;
		case SOF_DAI_INTEL_ALH:
			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
				return NULL;
			return &sdw_dspless_dma_ops;
		default:
			return NULL;
		}
	}

	switch (sdev->pdata->ipc_type) {
	case SOF_IPC_TYPE_3:
	{
@@ -619,23 +649,16 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
		break;
	}
	case SOF_IPC_TYPE_4:
	{
		struct sof_ipc4_copier *ipc4_copier = sdai->private;
		const struct sof_intel_dsp_desc *chip;

		chip = get_chip_info(sdev->pdata);

		switch (ipc4_copier->dai_type) {
		case SOF_DAI_INTEL_HDA:
	{
		struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;

		switch (sdai->type) {
		case SOF_DAI_INTEL_HDA:
			if (pipeline->use_chain_dma)
				return &hda_ipc4_chain_dma_ops;

			return &hda_ipc4_dma_ops;
		}
		case SOF_DAI_INTEL_SSP:
			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
				return NULL;
@@ -647,6 +670,8 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
		case SOF_DAI_INTEL_ALH:
			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
				return NULL;
			if (pipeline->use_chain_dma)
				return &sdw_ipc4_chain_dma_ops;
			return &sdw_ipc4_dma_ops;

		default:
+11 −6
Original line number Diff line number Diff line
@@ -83,12 +83,13 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai

	sdev = widget_to_sdev(w);

	/*
	 * The swidget parameter of hda_select_dai_widget_ops() is ignored in
	 * case of DSPless mode
	 */
	if (!swidget) {
		dev_err(sdev->dev, "%s: swidget is NULL\n", __func__);
		return NULL;
	}

	if (sdev->dspless_mode_selected)
		return hda_select_dai_widget_ops(sdev, NULL);
		return hda_select_dai_widget_ops(sdev, swidget);

	sdai = swidget->private;

@@ -368,8 +369,11 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
		return ret;
	}

	/* get stream_id */
	sdev = widget_to_sdev(w);
	if (sdev->dspless_mode_selected)
		goto skip_tlv;

	/* get stream_id */
	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);

	if (!hext_stream) {
@@ -402,6 +406,7 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
	dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
	dma_config->dma_priv_config_size = 0;

skip_tlv:
	return 0;
}

+5 −0
Original line number Diff line number Diff line
@@ -748,6 +748,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)

static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
{
	const struct sof_intel_dsp_desc *chip;
	int ret;

	/* display codec must be powered before link reset */
@@ -780,6 +781,10 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
		hda_dsp_ctrl_ppcap_int_enable(sdev, true);
	}

	chip = get_chip_info(sdev->pdata);
	if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0)
		hda_sdw_int_enable(sdev, true);

cleanup:
	/* display codec can powered off after controller init */
	hda_codec_i915_display_power(sdev, false);
+9 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <trace/events/sof_intel.h>
#include "../ops.h"
#include "../sof-audio.h"
#include "../ipc4-priv.h"
#include "hda.h"

#define HDA_LTRP_GB_VALUE_US	95
@@ -937,6 +938,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
	/* store total stream count (playback + capture) from GCAP */
	sof_hda->stream_max = num_total;

	/* store stream count from GCAP required for CHAIN_DMA */
	if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
		struct sof_ipc4_fw_data *ipc4_data = sdev->private;

		ipc4_data->num_playback_streams = num_playback;
		ipc4_data->num_capture_streams = num_capture;
	}

	return 0;
}

Loading