Unverified Commit 1499febc authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: SOF: Intel: LunarLake preparation patches

Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

This patchset adds the changes required for the hda-dai extension to
deal with SSSP/DMIC/SoundWire starting with LunarLake, as well as the
new TLV IPC to provide the DMA stream_tag to the DSP firmware.

LunarLake support for SSP/DMIC is ready but is gated by the patch
"ASoC: SOF: Intel: shim: add enum for ACE 2.0 IP used in LunarLake"
currently only present in the SoundWire tree.
parents fd0a7ec3 d3e7c32b
Loading
Loading
Loading
Loading
+57 −1
Original line number Diff line number Diff line
@@ -175,6 +175,50 @@ static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stre
	snd_hdac_ext_stream_reset(hext_stream);
}

static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,
				     struct snd_pcm_substream *substream,
				     struct hdac_stream *hstream)
{
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);

	/* set the hdac_stream in the codec dai */
	snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);
}

static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
					   struct snd_pcm_substream *substream,
					   struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
	unsigned int link_bps;
	unsigned int format_val;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		link_bps = codec_dai->driver->playback.sig_bits;
	else
		link_bps = codec_dai->driver->capture.sig_bits;

	format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
						 params_format(params), link_bps, 0);

	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
		params_rate(params), params_channels(params), params_format(params));

	return format_val;
}

static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
					   struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
	struct hdac_bus *bus = sof_to_bus(sdev);

	return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
}

static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
				struct snd_pcm_substream *substream, int cmd)
{
@@ -307,7 +351,10 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
	.reset_hext_stream = hda_reset_hext_stream,
	.pre_trigger = hda_ipc4_pre_trigger,
	.trigger = hda_trigger,
	.post_trigger = hda_ipc4_post_trigger
	.post_trigger = hda_ipc4_post_trigger,
	.codec_dai_set_stream = hda_codec_dai_set_stream,
	.calc_stream_format = hda_calc_stream_format,
	.get_hlink = hda_get_hlink,
};

static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
@@ -317,6 +364,9 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
	.setup_hext_stream = hda_setup_hext_stream,
	.reset_hext_stream = hda_reset_hext_stream,
	.trigger = hda_trigger,
	.codec_dai_set_stream = hda_codec_dai_set_stream,
	.calc_stream_format = hda_calc_stream_format,
	.get_hlink = hda_get_hlink,
};

static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
@@ -350,6 +400,9 @@ static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
	.reset_hext_stream = hda_reset_hext_stream,
	.trigger = hda_trigger,
	.post_trigger = hda_ipc3_post_trigger,
	.codec_dai_set_stream = hda_codec_dai_set_stream,
	.calc_stream_format = hda_calc_stream_format,
	.get_hlink = hda_get_hlink,
};

static struct hdac_ext_stream *
@@ -376,6 +429,9 @@ static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,
static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
	.get_hext_stream = hda_dspless_get_hext_stream,
	.setup_hext_stream = hda_dspless_setup_hext_stream,
	.codec_dai_set_stream = hda_codec_dai_set_stream,
	.calc_stream_format = hda_calc_stream_format,
	.get_hlink = hda_get_hlink,
};

#endif
+27 −37
Original line number Diff line number Diff line
@@ -109,20 +109,22 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai

static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
				struct hdac_ext_stream *hext_stream,
				struct snd_soc_dai *cpu_dai,
				struct snd_soc_dai *codec_dai)
				struct snd_soc_dai *cpu_dai)
{
	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
	struct hdac_stream *hstream = &hext_stream->hstream;
	struct hdac_bus *bus = hstream->bus;
	struct sof_intel_hda_stream *hda_stream;
	struct hdac_ext_link *hlink;
	struct snd_sof_dev *sdev;
	int stream_tag;

	if (!ops) {
		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
		return -EINVAL;
	}

	sdev = dai_to_sdev(substream, cpu_dai);

	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
	hlink = ops->get_hlink(sdev, substream);
	if (!hlink)
		return -EINVAL;

@@ -147,21 +149,20 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai)
{
	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
	struct hdac_ext_stream *hext_stream;
	struct hdac_stream *hstream;
	struct hdac_ext_link *hlink;
	struct snd_sof_dev *sdev;
	struct hdac_bus *bus;
	unsigned int format_val;
	unsigned int link_bps;
	int stream_tag;

	if (!ops) {
		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
		return -EINVAL;
	}

	sdev = dai_to_sdev(substream, cpu_dai);
	bus = sof_to_bus(sdev);

	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
	hlink = ops->get_hlink(sdev, substream);
	if (!hlink)
		return -EINVAL;

@@ -182,24 +183,17 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
		snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);

	/* set the hdac_stream in the codec dai */
	snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream);

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		link_bps = codec_dai->driver->playback.sig_bits;
	else
		link_bps = codec_dai->driver->capture.sig_bits;
	if (ops->codec_dai_set_stream)
		ops->codec_dai_set_stream(sdev, substream, hstream);

	if (ops->reset_hext_stream)
		ops->reset_hext_stream(sdev, hext_stream);

	format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
						 params_format(params), link_bps, 0);
	if (ops->calc_stream_format && ops->setup_hext_stream) {
		unsigned int format_val = ops->calc_stream_format(sdev, substream, params);

	dev_dbg(bus->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
		params_rate(params), params_channels(params), params_format(params));

	if (ops->setup_hext_stream)
		ops->setup_hext_stream(sdev, hext_stream, format_val);
	}

	hext_stream->link_prepared = 1;

@@ -210,13 +204,11 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
					  struct snd_soc_dai *cpu_dai)
{
	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
	struct hdac_ext_stream *hext_stream;
	struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai);

	if (!ops) {
		dev_err(sdev->dev, "DAI widget ops not set\n");
		dev_err(cpu_dai->dev, "DAI widget ops not set\n");
		return -EINVAL;
	}

@@ -224,7 +216,7 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
	if (!hext_stream)
		return 0;

	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
}

static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
@@ -269,11 +261,14 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
{
	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
	struct hdac_ext_stream *hext_stream;
	struct snd_soc_pcm_runtime *rtd;
	struct snd_soc_dai *codec_dai;
	struct snd_sof_dev *sdev;
	int ret;

	if (!ops) {
		dev_err(dai->dev, "DAI widget ops not set\n");
		return -EINVAL;
	}

	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
		dai->name, substream->stream);

@@ -283,9 +278,6 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
	if (!hext_stream)
		return -EINVAL;

	rtd = asoc_substream_to_rtd(substream);
	codec_dai = asoc_rtd_to_codec(rtd, 0);

	if (ops->pre_trigger) {
		ret = ops->pre_trigger(sdev, dai, substream, cmd);
		if (ret < 0)
@@ -306,7 +298,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_SUSPEND:
		ret = hda_link_dma_cleanup(substream, hext_stream, dai, codec_dai);
		ret = hda_link_dma_cleanup(substream, hext_stream, dai);
		if (ret < 0) {
			dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
			return ret;
@@ -360,14 +352,12 @@ static int hda_dai_suspend(struct hdac_bus *bus)
			const struct hda_dai_widget_dma_ops *ops;
			struct snd_sof_widget *swidget;
			struct snd_soc_dapm_widget *w;
			struct snd_soc_dai *codec_dai;
			struct snd_soc_dai *cpu_dai;
			struct snd_sof_dev *sdev;
			struct snd_sof_dai *sdai;

			rtd = asoc_substream_to_rtd(hext_stream->link_substream);
			cpu_dai = asoc_rtd_to_cpu(rtd, 0);
			codec_dai = asoc_rtd_to_codec(rtd, 0);
			w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
			swidget = w->dobj.private;
			sdev = widget_to_sdev(w);
@@ -376,7 +366,7 @@ static int hda_dai_suspend(struct hdac_bus *bus)

			ret = hda_link_dma_cleanup(hext_stream->link_substream,
						   hext_stream,
						   cpu_dai, codec_dai);
						   cpu_dai);
			if (ret < 0)
				return ret;

+25 −0
Original line number Diff line number Diff line
@@ -222,6 +222,31 @@ int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
	return 0;
}

int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
{
	struct sof_intel_hda_dev *hdev;
	struct sdw_intel_ctx *ctx;
	struct hdac_bus *bus;
	u32 slcount;

	bus = sof_to_bus(sdev);

	hdev = sdev->pdata->hw_pdata;
	ctx = hdev->sdw;

	slcount = hdac_bus_eml_get_count(bus, true, AZX_REG_ML_LEPTR_ID_SDW);

	/* Check HW supported vs property value */
	if (slcount < ctx->count) {
		dev_err(sdev->dev,
			"%s: BIOS master count %d is larger than hardware capabilities %d\n",
			__func__, ctx->count, slcount);
		return -EINVAL;
	}

	return 0;
}

static int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
{
	const struct sof_intel_dsp_desc *chip;
+19 −0
Original line number Diff line number Diff line
@@ -781,6 +781,7 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)

int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev);
int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev);
int hda_sdw_startup(struct snd_sof_dev *sdev);
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
@@ -794,6 +795,11 @@ static inline int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
	return 0;
}

static inline int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
{
	return 0;
}

static inline int hda_sdw_startup(struct snd_sof_dev *sdev)
{
	return 0;
@@ -919,6 +925,11 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
 * @pre_trigger: Function pointer for DAI DMA pre-trigger actions
 * @trigger: Function pointer for DAI DMA trigger actions
 * @post_trigger: Function pointer for DAI DMA post-trigger actions
 * @codec_dai_set_stream: Function pointer to set codec-side stream information
 * @calc_stream_format: Function pointer to determine stream format from hw_params and
 * for HDaudio codec DAI from the .sig bits
 * @get_hlink: Mandatory function pointer to retrieve hlink, mainly to program LOSIDV
 * for legacy HDaudio links or program HDaudio Extended Link registers.
 */
struct hda_dai_widget_dma_ops {
	struct hdac_ext_stream *(*get_hext_stream)(struct snd_sof_dev *sdev,
@@ -938,6 +949,14 @@ struct hda_dai_widget_dma_ops {
		       struct snd_pcm_substream *substream, int cmd);
	int (*post_trigger)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
			    struct snd_pcm_substream *substream, int cmd);
	void (*codec_dai_set_stream)(struct snd_sof_dev *sdev,
				     struct snd_pcm_substream *substream,
				     struct hdac_stream *hstream);
	unsigned int (*calc_stream_format)(struct snd_sof_dev *sdev,
					   struct snd_pcm_substream *substream,
					   struct snd_pcm_hw_params *params);
	struct hdac_ext_link * (*get_hlink)(struct snd_sof_dev *sdev,
					    struct snd_pcm_substream *substream);
};

const struct hda_dai_widget_dma_ops *
+6 −6
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev)
}

/* Check if an IPC IRQ occurred */
static bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
{
	u32 irq_status;
	u32 hfintipptr;
@@ -118,7 +118,7 @@ static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *ms
	return 0;
}

static void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)
{
	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
	const struct sof_intel_dsp_desc *chip = hda->desc;
@@ -132,7 +132,7 @@ static void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)
				MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE);
}

static void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
{
	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
	const struct sof_intel_dsp_desc *chip = hda->desc;
@@ -173,7 +173,7 @@ static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
			enable ? "enable" : "disable");
}

static int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
{
	u32 hfintipptr;
	u32 irqinten;
@@ -394,7 +394,7 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
	return ret;
}

static int mtl_power_down_dsp(struct snd_sof_dev *sdev)
int mtl_power_down_dsp(struct snd_sof_dev *sdev)
{
	u32 dsphfdsscs, cpa;
	int ret;
@@ -421,7 +421,7 @@ static int mtl_power_down_dsp(struct snd_sof_dev *sdev)
					     HDA_DSP_RESET_TIMEOUT_US);
}

static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
{
	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
	const struct sof_intel_dsp_desc *chip = hda->desc;
Loading