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.
This commit is contained in:
commit
1499febc01
@ -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
|
||||
|
@ -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;
|
||||
|
||||
sdev = dai_to_sdev(substream, cpu_dai);
|
||||
bus = sof_to_bus(sdev);
|
||||
if (!ops) {
|
||||
dev_err(cpu_dai->dev, "DAI widget ops not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
|
||||
sdev = dai_to_sdev(substream, cpu_dai);
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 *
|
||||
|
@ -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;
|
||||
|
@ -82,3 +82,10 @@
|
||||
#define MTL_DSP_REG_HfIMRIS1 0x162088
|
||||
#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)
|
||||
strcmp(w->widget->sname, swidget->widget->sname))
|
||||
continue;
|
||||
|
||||
blob->alh_cfg.count++;
|
||||
blob->alh_cfg.device_count++;
|
||||
}
|
||||
|
||||
ipc4_copier->copier_config = (uint32_t *)blob;
|
||||
@ -1225,7 +1225,7 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
|
||||
unsigned int group_id;
|
||||
|
||||
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) -
|
||||
ALH_MULTI_GTW_BASE;
|
||||
ida_free(&alh_group_ida, group_id);
|
||||
@ -1383,6 +1383,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
|
||||
struct snd_sof_dai *dai;
|
||||
struct snd_mask *fmt;
|
||||
int out_sample_valid_bits;
|
||||
u32 gtw_cfg_config_length;
|
||||
u32 dma_config_tlv_size = 0;
|
||||
void **ipc_config_data;
|
||||
int *ipc_config_size;
|
||||
u32 **data;
|
||||
@ -1609,7 +1611,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
|
||||
ch_map >>= 4;
|
||||
}
|
||||
|
||||
step = ch_count / blob->alh_cfg.count;
|
||||
step = ch_count / blob->alh_cfg.device_count;
|
||||
mask = GENMASK(step - 1, 0);
|
||||
/*
|
||||
* 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,
|
||||
dai = w->private;
|
||||
alh_copier = (struct sof_ipc4_copier *)dai->private;
|
||||
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
|
||||
* duplicated for all speakers. For capture, split the channels
|
||||
@ -1643,7 +1645,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
|
||||
|
||||
i++;
|
||||
}
|
||||
if (blob->alh_cfg.count > 1) {
|
||||
if (blob->alh_cfg.device_count > 1) {
|
||||
int group_id;
|
||||
|
||||
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,
|
||||
ipc_config_data = &ipc4_copier->ipc_config_data;
|
||||
|
||||
/* 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);
|
||||
|
||||
@ -1711,9 +1733,15 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
|
||||
|
||||
/* copy IPC 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),
|
||||
*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 */
|
||||
sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
|
||||
|
@ -55,7 +55,7 @@
|
||||
#define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff
|
||||
#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
|
||||
|
||||
@ -220,18 +220,64 @@ struct sof_ipc4_gtw_attributes {
|
||||
uint32_t rsvd : 30;
|
||||
};
|
||||
|
||||
/** struct sof_ipc4_alh_multi_gtw_cfg: ALH gateway cfg data
|
||||
* @count: Number of streams (valid items in mapping array)
|
||||
* @alh_id: ALH stream id of a single ALH stream aggregated
|
||||
* @channel_mask: Channel mask
|
||||
* @mapping: ALH streams
|
||||
/**
|
||||
* struct sof_ipc4_dma_device_stream_ch_map: abstract representation of
|
||||
* channel mapping to DMAs
|
||||
* @device: representation of hardware device address or FIFO
|
||||
* @channel_mask: channels handled by @device. Channels are expected to be
|
||||
* contiguous
|
||||
*/
|
||||
struct sof_ipc4_alh_multi_gtw_cfg {
|
||||
uint32_t count;
|
||||
struct {
|
||||
uint32_t alh_id;
|
||||
uint32_t channel_mask;
|
||||
} mapping[ALH_MAX_NUMBER_OF_GTW];
|
||||
struct sof_ipc4_dma_device_stream_ch_map {
|
||||
uint32_t device;
|
||||
uint32_t channel_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/** struct sof_ipc4_alh_configuration_blob: ALH blob
|
||||
@ -240,7 +286,7 @@ struct sof_ipc4_alh_multi_gtw_cfg {
|
||||
*/
|
||||
struct sof_ipc4_alh_configuration_blob {
|
||||
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 {
|
||||
* @gtw_attr: Gateway attributes for copier blob
|
||||
* @dai_type: DAI type
|
||||
* @dai_index: DAI index
|
||||
* @dma_config_tlv: DMA configuration
|
||||
*/
|
||||
struct sof_ipc4_copier {
|
||||
struct sof_ipc4_copier_data data;
|
||||
@ -266,6 +313,7 @@ struct sof_ipc4_copier {
|
||||
struct sof_ipc4_gtw_attributes *gtw_attr;
|
||||
u32 dai_type;
|
||||
int dai_index;
|
||||
struct sof_ipc4_dma_config_tlv dma_config_tlv;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user