Commit 1499febc authored by Mark Brown's avatar Mark Brown

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
...@@ -175,6 +175,50 @@ static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stre ...@@ -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); 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, static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd) struct snd_pcm_substream *substream, int cmd)
{ {
...@@ -307,7 +351,10 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { ...@@ -307,7 +351,10 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.reset_hext_stream = hda_reset_hext_stream, .reset_hext_stream = hda_reset_hext_stream,
.pre_trigger = hda_ipc4_pre_trigger, .pre_trigger = hda_ipc4_pre_trigger,
.trigger = hda_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 = { 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 = { ...@@ -317,6 +364,9 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
.setup_hext_stream = hda_setup_hext_stream, .setup_hext_stream = hda_setup_hext_stream,
.reset_hext_stream = hda_reset_hext_stream, .reset_hext_stream = hda_reset_hext_stream,
.trigger = hda_trigger, .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, 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 = { ...@@ -350,6 +400,9 @@ static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
.reset_hext_stream = hda_reset_hext_stream, .reset_hext_stream = hda_reset_hext_stream,
.trigger = hda_trigger, .trigger = hda_trigger,
.post_trigger = hda_ipc3_post_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 * static struct hdac_ext_stream *
...@@ -376,6 +429,9 @@ static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev, ...@@ -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 = { static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
.get_hext_stream = hda_dspless_get_hext_stream, .get_hext_stream = hda_dspless_get_hext_stream,
.setup_hext_stream = hda_dspless_setup_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 #endif
......
...@@ -109,20 +109,22 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai ...@@ -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, static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
struct hdac_ext_stream *hext_stream, struct hdac_ext_stream *hext_stream,
struct snd_soc_dai *cpu_dai, struct snd_soc_dai *cpu_dai)
struct snd_soc_dai *codec_dai)
{ {
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, 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 sof_intel_hda_stream *hda_stream;
struct hdac_ext_link *hlink; struct hdac_ext_link *hlink;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
int stream_tag; 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); 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) if (!hlink)
return -EINVAL; return -EINVAL;
...@@ -147,21 +149,20 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, ...@@ -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) 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); 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_ext_stream *hext_stream;
struct hdac_stream *hstream; struct hdac_stream *hstream;
struct hdac_ext_link *hlink; struct hdac_ext_link *hlink;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
struct hdac_bus *bus;
unsigned int format_val;
unsigned int link_bps;
int stream_tag; 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); 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) if (!hlink)
return -EINVAL; return -EINVAL;
...@@ -182,24 +183,17 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, ...@@ -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); snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);
/* set the hdac_stream in the codec dai */ /* set the hdac_stream in the codec dai */
snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream); if (ops->codec_dai_set_stream)
ops->codec_dai_set_stream(sdev, substream, hstream);
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->reset_hext_stream) if (ops->reset_hext_stream)
ops->reset_hext_stream(sdev, hext_stream); ops->reset_hext_stream(sdev, hext_stream);
format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), if (ops->calc_stream_format && ops->setup_hext_stream) {
params_format(params), link_bps, 0); 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); ops->setup_hext_stream(sdev, hext_stream, format_val);
}
hext_stream->link_prepared = 1; hext_stream->link_prepared = 1;
...@@ -210,13 +204,11 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream, ...@@ -210,13 +204,11 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai) struct snd_soc_dai *cpu_dai)
{ {
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, 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_ext_stream *hext_stream;
struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai); struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai);
if (!ops) { 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; return -EINVAL;
} }
...@@ -224,7 +216,7 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream, ...@@ -224,7 +216,7 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
if (!hext_stream) if (!hext_stream)
return 0; 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, 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 ...@@ -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); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *hext_stream;
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai *codec_dai;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
int ret; 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, dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
dai->name, substream->stream); dai->name, substream->stream);
...@@ -283,9 +278,6 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i ...@@ -283,9 +278,6 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
if (!hext_stream) if (!hext_stream)
return -EINVAL; return -EINVAL;
rtd = asoc_substream_to_rtd(substream);
codec_dai = asoc_rtd_to_codec(rtd, 0);
if (ops->pre_trigger) { if (ops->pre_trigger) {
ret = ops->pre_trigger(sdev, dai, substream, cmd); ret = ops->pre_trigger(sdev, dai, substream, cmd);
if (ret < 0) if (ret < 0)
...@@ -306,7 +298,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i ...@@ -306,7 +298,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_SUSPEND: 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) { if (ret < 0) {
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
return ret; return ret;
...@@ -360,14 +352,12 @@ static int hda_dai_suspend(struct hdac_bus *bus) ...@@ -360,14 +352,12 @@ static int hda_dai_suspend(struct hdac_bus *bus)
const struct hda_dai_widget_dma_ops *ops; const struct hda_dai_widget_dma_ops *ops;
struct snd_sof_widget *swidget; struct snd_sof_widget *swidget;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai; struct snd_soc_dai *cpu_dai;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
struct snd_sof_dai *sdai; struct snd_sof_dai *sdai;
rtd = asoc_substream_to_rtd(hext_stream->link_substream); rtd = asoc_substream_to_rtd(hext_stream->link_substream);
cpu_dai = asoc_rtd_to_cpu(rtd, 0); 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); w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
swidget = w->dobj.private; swidget = w->dobj.private;
sdev = widget_to_sdev(w); sdev = widget_to_sdev(w);
...@@ -376,7 +366,7 @@ static int hda_dai_suspend(struct hdac_bus *bus) ...@@ -376,7 +366,7 @@ static int hda_dai_suspend(struct hdac_bus *bus)
ret = hda_link_dma_cleanup(hext_stream->link_substream, ret = hda_link_dma_cleanup(hext_stream->link_substream,
hext_stream, hext_stream,
cpu_dai, codec_dai); cpu_dai);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -222,6 +222,31 @@ int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev) ...@@ -222,6 +222,31 @@ int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
return 0; 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) static int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
{ {
const struct sof_intel_dsp_desc *chip; const struct sof_intel_dsp_desc *chip;
......
...@@ -781,6 +781,7 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd); ...@@ -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) #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_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); int hda_sdw_startup(struct snd_sof_dev *sdev);
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable); 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); 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) ...@@ -794,6 +795,11 @@ static inline int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
return 0; 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) static inline int hda_sdw_startup(struct snd_sof_dev *sdev)
{ {
return 0; return 0;
...@@ -919,6 +925,11 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, ...@@ -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 * @pre_trigger: Function pointer for DAI DMA pre-trigger actions
* @trigger: Function pointer for DAI DMA trigger actions * @trigger: Function pointer for DAI DMA trigger actions
* @post_trigger: Function pointer for DAI DMA post-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 hda_dai_widget_dma_ops {
struct hdac_ext_stream *(*get_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *(*get_hext_stream)(struct snd_sof_dev *sdev,
...@@ -938,6 +949,14 @@ struct hda_dai_widget_dma_ops { ...@@ -938,6 +949,14 @@ struct hda_dai_widget_dma_ops {
struct snd_pcm_substream *substream, int cmd); struct snd_pcm_substream *substream, int cmd);
int (*post_trigger)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, int (*post_trigger)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd); 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 * const struct hda_dai_widget_dma_ops *
......
...@@ -55,7 +55,7 @@ static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev) ...@@ -55,7 +55,7 @@ static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev)
} }
/* Check if an IPC IRQ occurred */ /* 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 irq_status;
u32 hfintipptr; u32 hfintipptr;
...@@ -118,7 +118,7 @@ static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *ms ...@@ -118,7 +118,7 @@ static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *ms
return 0; 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; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc; const struct sof_intel_dsp_desc *chip = hda->desc;
...@@ -132,7 +132,7 @@ static void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev) ...@@ -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); 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; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc; 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) ...@@ -173,7 +173,7 @@ static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
enable ? "enable" : "disable"); 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 hfintipptr;
u32 irqinten; u32 irqinten;
...@@ -394,7 +394,7 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core) ...@@ -394,7 +394,7 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
return ret; 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; u32 dsphfdsscs, cpa;
int ret; int ret;
...@@ -421,7 +421,7 @@ static int mtl_power_down_dsp(struct snd_sof_dev *sdev) ...@@ -421,7 +421,7 @@ static int mtl_power_down_dsp(struct snd_sof_dev *sdev)
HDA_DSP_RESET_TIMEOUT_US); 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; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc; const struct sof_intel_dsp_desc *chip = hda->desc;
......
...@@ -82,3 +82,10 @@ ...@@ -82,3 +82,10 @@
#define MTL_DSP_REG_HfIMRIS1 0x162088 #define MTL_DSP_REG_HfIMRIS1 0x162088
#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) #define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0)
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev);
void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev);
bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable);
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
int mtl_power_down_dsp(struct snd_sof_dev *sdev);
...@@ -559,7 +559,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) ...@@ -559,7 +559,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
strcmp(w->widget->sname, swidget->widget->sname)) strcmp(w->widget->sname, swidget->widget->sname))
continue; continue;
blob->alh_cfg.count++; blob->alh_cfg.device_count++;
} }
ipc4_copier->copier_config = (uint32_t *)blob; ipc4_copier->copier_config = (uint32_t *)blob;
...@@ -1225,7 +1225,7 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) ...@@ -1225,7 +1225,7 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
unsigned int group_id; unsigned int group_id;
blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
if (blob->alh_cfg.count > 1) { if (blob->alh_cfg.device_count > 1) {
group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) - group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
ALH_MULTI_GTW_BASE; ALH_MULTI_GTW_BASE;
ida_free(&alh_group_ida, group_id); ida_free(&alh_group_ida, group_id);
...@@ -1383,6 +1383,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ...@@ -1383,6 +1383,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_sof_dai *dai; struct snd_sof_dai *dai;
struct snd_mask *fmt; struct snd_mask *fmt;
int out_sample_valid_bits; int out_sample_valid_bits;
u32 gtw_cfg_config_length;
u32 dma_config_tlv_size = 0;
void **ipc_config_data; void **ipc_config_data;
int *ipc_config_size; int *ipc_config_size;
u32 **data; u32 **data;
...@@ -1609,7 +1611,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ...@@ -1609,7 +1611,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
ch_map >>= 4; ch_map >>= 4;
} }
step = ch_count / blob->alh_cfg.count; step = ch_count / blob->alh_cfg.device_count;
mask = GENMASK(step - 1, 0); mask = GENMASK(step - 1, 0);
/* /*
* Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
...@@ -1624,7 +1626,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ...@@ -1624,7 +1626,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
dai = w->private; dai = w->private;
alh_copier = (struct sof_ipc4_copier *)dai->private; alh_copier = (struct sof_ipc4_copier *)dai->private;
alh_data = &alh_copier->data; alh_data = &alh_copier->data;
blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id; blob->alh_cfg.mapping[i].device = alh_data->gtw_cfg.node_id;
/* /*
* Set the same channel mask for playback as the audio data is * Set the same channel mask for playback as the audio data is
* duplicated for all speakers. For capture, split the channels * duplicated for all speakers. For capture, split the channels
...@@ -1643,7 +1645,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ...@@ -1643,7 +1645,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
i++; i++;
} }
if (blob->alh_cfg.count > 1) { if (blob->alh_cfg.device_count > 1) {
int group_id; int group_id;
group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1, group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
...@@ -1699,7 +1701,27 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ...@@ -1699,7 +1701,27 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
ipc_config_data = &ipc4_copier->ipc_config_data; ipc_config_data = &ipc4_copier->ipc_config_data;
/* config_length is DWORD based */ /* config_length is DWORD based */
ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4; gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4;
ipc_size = sizeof(*copier_data) + gtw_cfg_config_length;
if (ipc4_copier->dma_config_tlv.type == SOF_IPC4_GTW_DMA_CONFIG_ID &&
ipc4_copier->dma_config_tlv.length) {
dma_config_tlv_size = sizeof(ipc4_copier->dma_config_tlv) +
ipc4_copier->dma_config_tlv.dma_config.dma_priv_config_size;
/* paranoia check on TLV size/length */
if (dma_config_tlv_size != ipc4_copier->dma_config_tlv.length +
sizeof(uint32_t) * 2) {
dev_err(sdev->dev, "Invalid configuration, TLV size %d length %d\n",
dma_config_tlv_size, ipc4_copier->dma_config_tlv.length);
return -EINVAL;
}
ipc_size += dma_config_tlv_size;
/* we also need to increase the size at the gtw level */
copier_data->gtw_cfg.config_length += dma_config_tlv_size / 4;
}
dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
...@@ -1711,9 +1733,15 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ...@@ -1711,9 +1733,15 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
/* copy IPC data */ /* copy IPC data */
memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
if (copier_data->gtw_cfg.config_length) if (gtw_cfg_config_length)
memcpy(*ipc_config_data + sizeof(*copier_data), memcpy(*ipc_config_data + sizeof(*copier_data),
*data, copier_data->gtw_cfg.config_length * 4); *data, gtw_cfg_config_length);
/* add DMA Config TLV, if configured */
if (dma_config_tlv_size)
memcpy(*ipc_config_data + sizeof(*copier_data) +
gtw_cfg_config_length,
&ipc4_copier->dma_config_tlv, dma_config_tlv_size);
/* update pipeline memory usage */ /* update pipeline memory usage */
sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
......
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
#define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff #define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff
#define SOF_IPC4_VOL_ZERO_DB 0x7fffffff #define SOF_IPC4_VOL_ZERO_DB 0x7fffffff
#define ALH_MAX_NUMBER_OF_GTW 16 #define SOF_IPC4_DMA_DEVICE_MAX_COUNT 16
#define SOF_IPC4_INVALID_NODE_ID 0xffffffff #define SOF_IPC4_INVALID_NODE_ID 0xffffffff
...@@ -220,18 +220,64 @@ struct sof_ipc4_gtw_attributes { ...@@ -220,18 +220,64 @@ struct sof_ipc4_gtw_attributes {
uint32_t rsvd : 30; uint32_t rsvd : 30;
}; };
/** struct sof_ipc4_alh_multi_gtw_cfg: ALH gateway cfg data /**
* @count: Number of streams (valid items in mapping array) * struct sof_ipc4_dma_device_stream_ch_map: abstract representation of
* @alh_id: ALH stream id of a single ALH stream aggregated * channel mapping to DMAs
* @channel_mask: Channel mask * @device: representation of hardware device address or FIFO
* @mapping: ALH streams * @channel_mask: channels handled by @device. Channels are expected to be
* contiguous
*/ */
struct sof_ipc4_alh_multi_gtw_cfg { struct sof_ipc4_dma_device_stream_ch_map {
uint32_t count; uint32_t device;
struct {
uint32_t alh_id;
uint32_t channel_mask; uint32_t channel_mask;
} mapping[ALH_MAX_NUMBER_OF_GTW]; };
/**
* struct sof_ipc4_dma_stream_ch_map: DMA configuration data
* @device_count: Number valid items in mapping array
* @mapping: device address and channel mask
*/
struct sof_ipc4_dma_stream_ch_map {
uint32_t device_count;
struct sof_ipc4_dma_device_stream_ch_map mapping[SOF_IPC4_DMA_DEVICE_MAX_COUNT];
} __packed;
#define SOF_IPC4_DMA_METHOD_HDA 1
#define SOF_IPC4_DMA_METHOD_GPDMA 2 /* defined for consistency but not used */
/**
* struct sof_ipc4_dma_config: DMA configuration
* @dma_method: HDAudio or GPDMA
* @pre_allocated_by_host: 1 if host driver allocates DMA channels, 0 otherwise
* @dma_channel_id: for HDaudio defined as @stream_id - 1
* @stream_id: HDaudio stream tag
* @dma_stream_channel_map: array of device/channel mappings
* @dma_priv_config_size: currently not used
* @dma_priv_config: currently not used
*/
struct sof_ipc4_dma_config {
uint8_t dma_method;
uint8_t pre_allocated_by_host;
uint16_t rsvd;
uint32_t dma_channel_id;
uint32_t stream_id;
struct sof_ipc4_dma_stream_ch_map dma_stream_channel_map;
uint32_t dma_priv_config_size;
uint8_t dma_priv_config[];
} __packed;
#define SOF_IPC4_GTW_DMA_CONFIG_ID 0x1000
/**
* struct sof_ipc4_dma_config: DMA configuration
* @type: set to SOF_IPC4_GTW_DMA_CONFIG_ID
* @length: sizeof(struct sof_ipc4_dma_config) + dma_config.dma_priv_config_size
* @dma_config: actual DMA configuration
*/
struct sof_ipc4_dma_config_tlv {
uint32_t type;
uint32_t length;
struct sof_ipc4_dma_config dma_config;
} __packed; } __packed;
/** struct sof_ipc4_alh_configuration_blob: ALH blob /** struct sof_ipc4_alh_configuration_blob: ALH blob
...@@ -240,7 +286,7 @@ struct sof_ipc4_alh_multi_gtw_cfg { ...@@ -240,7 +286,7 @@ struct sof_ipc4_alh_multi_gtw_cfg {
*/ */
struct sof_ipc4_alh_configuration_blob { struct sof_ipc4_alh_configuration_blob {
struct sof_ipc4_gtw_attributes gw_attr; struct sof_ipc4_gtw_attributes gw_attr;
struct sof_ipc4_alh_multi_gtw_cfg alh_cfg; struct sof_ipc4_dma_stream_ch_map alh_cfg;
}; };
/** /**
...@@ -254,6 +300,7 @@ struct sof_ipc4_alh_configuration_blob { ...@@ -254,6 +300,7 @@ struct sof_ipc4_alh_configuration_blob {
* @gtw_attr: Gateway attributes for copier blob * @gtw_attr: Gateway attributes for copier blob
* @dai_type: DAI type * @dai_type: DAI type
* @dai_index: DAI index * @dai_index: DAI index
* @dma_config_tlv: DMA configuration
*/ */
struct sof_ipc4_copier { struct sof_ipc4_copier {
struct sof_ipc4_copier_data data; struct sof_ipc4_copier_data data;
...@@ -266,6 +313,7 @@ struct sof_ipc4_copier { ...@@ -266,6 +313,7 @@ struct sof_ipc4_copier {
struct sof_ipc4_gtw_attributes *gtw_attr; struct sof_ipc4_gtw_attributes *gtw_attr;
u32 dai_type; u32 dai_type;
int dai_index; int dai_index;
struct sof_ipc4_dma_config_tlv dma_config_tlv;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment