On Fri, 2022-03-04 at 15:57 +0100, Cezary Rojewski wrote: > Compared to SKL and KBL, younger cAVS platforms are meant to re-use > one Younger? you mean newer? > of HDAudio streams during boot procedure causing CLDMA to become > obsolete. Once transferred, given stream is returned to pool > available > for audio streaming. > > Module loading handler is dummy as library and module code became > inseparable in later firmware generations. replace dummy with "stub" maybe? lets use inclusive terms > > Signed-off-by: Amadeusz Sławiński < > amadeuszx.slawinski@xxxxxxxxxxxxxxx> > Signed-off-by: Cezary Rojewski <cezary.rojewski@xxxxxxxxx> > --- > sound/soc/intel/Kconfig | 1 + > sound/soc/intel/avs/avs.h | 5 + > sound/soc/intel/avs/loader.c | 211 > +++++++++++++++++++++++++++++++++++ > 3 files changed, 217 insertions(+) > > diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig > index e9768c4aa1a9..d025ca0c77fa 100644 > --- a/sound/soc/intel/Kconfig > +++ b/sound/soc/intel/Kconfig > @@ -215,6 +215,7 @@ config SND_SOC_INTEL_AVS > depends on COMMON_CLK > select SND_SOC_ACPI > select SND_HDA_EXT_CORE > + select SND_HDA_DSP_LOADER > help > Enable support for Intel(R) cAVS 1.5 platforms with DSP > capabilities. This includes Skylake, Kabylake, Amberlake and > diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h > index fb3520f32488..6dc5d17ccf21 100644 > --- a/sound/soc/intel/avs/avs.h > +++ b/sound/soc/intel/avs/avs.h > @@ -45,6 +45,7 @@ struct avs_dsp_ops { > ((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__)) > > #define AVS_PLATATTR_CLDMA BIT_ULL(0) > +#define AVS_PLATATTR_IMR BIT_ULL(1) > > #define avs_platattr_test(adev, attr) \ > ((adev)->spec->attributes & AVS_PLATATTR_##attr) > @@ -239,5 +240,9 @@ int avs_cldma_load_basefw(struct avs_dev *adev, > struct firmware *fw); > int avs_cldma_load_library(struct avs_dev *adev, struct firmware > *lib, u32 id); > int avs_cldma_transfer_modules(struct avs_dev *adev, bool load, > struct avs_module_entry *mods, u32 > num_mods); > +int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw); > +int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, > u32 id); > +int avs_hda_transfer_modules(struct avs_dev *adev, bool load, > + struct avs_module_entry *mods, u32 > num_mods); > > #endif /* __SOUND_SOC_INTEL_AVS_H */ > diff --git a/sound/soc/intel/avs/loader.c > b/sound/soc/intel/avs/loader.c > index 2134aaabe2c6..6520f23fc70e 100644 > --- a/sound/soc/intel/avs/loader.c > +++ b/sound/soc/intel/avs/loader.c > @@ -9,6 +9,7 @@ > #include <linux/firmware.h> > #include <linux/module.h> > #include <linux/slab.h> > +#include <sound/hdaudio.h> > #include <sound/hdaudio_ext.h> > #include "avs.h" > #include "cldma.h" > @@ -18,8 +19,11 @@ > #define AVS_ROM_STS_MASK 0xFF > #define AVS_ROM_INIT_DONE 0x1 > #define SKL_ROM_BASEFW_ENTERED 0xF > +#define APL_ROM_FW_ENTERED 0x5 > #define AVS_ROM_INIT_POLLING_US 5 > #define SKL_ROM_INIT_TIMEOUT_US 1000000 > +#define APL_ROM_INIT_TIMEOUT_US 300000 > +#define APL_ROM_INIT_RETRIES 3 > > #define AVS_FW_INIT_POLLING_US 500 > #define AVS_FW_INIT_TIMEOUT_US 3000000 > @@ -261,6 +265,204 @@ int avs_cldma_transfer_modules(struct avs_dev > *adev, bool load, > return 0; > } > > +static int > +avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool > purge) > +{ > + const struct avs_spec *const spec = adev->spec; > + unsigned int corex_mask, reg; > + int ret; > + > + corex_mask = spec->core_init_mask & ~AVS_MAIN_CORE_MASK; > + > + ret = avs_dsp_op(adev, power, spec->core_init_mask, true); > + if (ret < 0) > + goto err; > + > + ret = avs_dsp_op(adev, reset, AVS_MAIN_CORE_MASK, false); > + if (ret < 0) > + goto err; > + > + reinit_completion(&adev->fw_ready); > + avs_dsp_op(adev, int_control, true); > + > + /* set boot config */ > + ret = avs_ipc_set_boot_config(adev, dma_id, purge); > + if (ret) { > + ret = AVS_IPC_RET(ret); > + goto err; > + } > + > + /* await ROM init */ > + ret = snd_hdac_adsp_readq_poll(adev, spec->rom_status, reg, > + (reg & 0xF) == AVS_ROM_INIT_DONE > || > + (reg & 0xF) == > APL_ROM_FW_ENTERED, > + AVS_ROM_INIT_POLLING_US, > APL_ROM_INIT_TIMEOUT_US); > + if (ret < 0) { > + dev_err(adev->dev, "rom init timeout: %d\n", ret); > + goto err; > + } > + > + /* power down non-main cores */ > + if (corex_mask) > + avs_dsp_op(adev, power, corex_mask, false); What if this fails? > + > + return 0; > + > +err: > + avs_dsp_core_disable(adev, spec->core_init_mask); > + return ret; > +} > + > +static int avs_imr_load_basefw(struct avs_dev *adev) > +{ > + int ret; > + > + /* DMA id ignored when flashing from IMR as no transfer occurs. > */ > + ret = avs_hda_init_rom(adev, 0, false); > + if (ret < 0) { > + dev_err(adev->dev, "rom init failed: %d\n", ret); > + return ret; > + } > + > + ret = wait_for_completion_timeout(&adev->fw_ready, > + msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS > )); > + if (!ret) { > + dev_err(adev->dev, "firmware ready timeout\n"); > + avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); > + return -ETIMEDOUT; > + } > + > + return 0; > +} > + > +int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw) > +{ > + struct snd_pcm_substream substream; > + struct snd_dma_buffer dmab; > + struct hdac_ext_stream *estream; > + struct hdac_stream *hstream; > + struct hdac_bus *bus = &adev->base.core; > + unsigned int sdfmt, reg; > + int ret, i; > + > + /* configure hda dma */ > + memset(&substream, 0, sizeof(substream)); > + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; > + estream = snd_hdac_ext_stream_assign(bus, &substream, > + HDAC_EXT_STREAM_TYPE_HOST) > ; > + if (!estream) > + return -ENODEV; > + hstream = hdac_stream(estream); > + > + /* code loading performed with default format */ > + sdfmt = snd_hdac_calc_stream_format(48000, 1, > SNDRV_PCM_FORMAT_S32_LE, 32, 0); > + ret = snd_hdac_dsp_prepare(hstream, sdfmt, fw->size, &dmab); > + if (ret < 0) > + goto release_stream; > + > + /* enable SPIB for hda stream */ > + snd_hdac_ext_stream_spbcap_enable(bus, true, hstream->index); > + ret = snd_hdac_ext_stream_set_spib(bus, estream, fw->size); > + if (ret) > + goto cleanup_resources; > + > + memcpy(dmab.area, fw->data, fw->size); > + > + for (i = 0; i < APL_ROM_INIT_RETRIES; i++) { > + unsigned int dma_id = hstream->stream_tag - 1; > + > + ret = avs_hda_init_rom(adev, dma_id, true); > + if (!ret) > + break; > + dev_info(adev->dev, "#%d rom init fail: %d\n", i + 1, > ret); > + } > + if (ret < 0) > + goto cleanup_resources; > + > + /* transfer firmware */ > + snd_hdac_dsp_trigger(hstream, true); > + ret = snd_hdac_adsp_readl_poll(adev, AVS_FW_REG_STATUS(adev), > reg, > + (reg & AVS_ROM_STS_MASK) == > APL_ROM_FW_ENTERED, > + AVS_FW_INIT_POLLING_US, > AVS_FW_INIT_TIMEOUT_US); > + snd_hdac_dsp_trigger(hstream, false); > + if (ret < 0) { > + dev_err(adev->dev, "transfer fw failed: %d\n", ret); > + avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); > + } > + > +cleanup_resources: > + /* disable SPIB for hda stream */ > + snd_hdac_ext_stream_spbcap_enable(bus, false, hstream->index); > + snd_hdac_ext_stream_set_spib(bus, estream, 0); > + > + snd_hdac_dsp_cleanup(hstream, &dmab); > +release_stream: > + snd_hdac_ext_stream_release(estream, > HDAC_EXT_STREAM_TYPE_HOST); > + > + return ret; > +} > + > +int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, > u32 id) > +{ > + struct snd_pcm_substream substream; > + struct snd_dma_buffer dmab; > + struct hdac_ext_stream *estream; > + struct hdac_stream *stream; > + struct hdac_bus *bus = &adev->base.core; > + unsigned int sdfmt; > + int ret; > + > + /* configure hda dma */ > + memset(&substream, 0, sizeof(substream)); > + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; > + estream = snd_hdac_ext_stream_assign(bus, &substream, > + HDAC_EXT_STREAM_TYPE_HOST) > ; > + if (!estream) > + return -ENODEV; > + stream = hdac_stream(estream); > + > + /* code loading performed with default format */ > + sdfmt = snd_hdac_calc_stream_format(48000, 1, > SNDRV_PCM_FORMAT_S32_LE, 32, 0); > + ret = snd_hdac_dsp_prepare(stream, sdfmt, lib->size, &dmab); > + if (ret < 0) > + goto release_stream; > + > + /* enable SPIB for hda stream */ > + snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index); > + snd_hdac_ext_stream_set_spib(bus, estream, lib->size); > + > + memcpy(dmab.area, lib->data, lib->size); > + > + /* transfer firmware */ > + snd_hdac_dsp_trigger(stream, true); > + ret = avs_ipc_load_library(adev, stream->stream_tag - 1, id); > + snd_hdac_dsp_trigger(stream, false); > + if (ret) { > + dev_err(adev->dev, "transfer lib %d failed: %d\n", id, > ret); > + ret = AVS_IPC_RET(ret); > + } > + > + /* disable SPIB for hda stream */ > + snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index); > + snd_hdac_ext_stream_set_spib(bus, estream, 0); > + > + snd_hdac_dsp_cleanup(stream, &dmab); > +release_stream: > + snd_hdac_ext_stream_release(estream, > HDAC_EXT_STREAM_TYPE_HOST); > + > + return ret; > +} > + > +int avs_hda_transfer_modules(struct avs_dev *adev, bool load, > + struct avs_module_entry *mods, u32 > num_mods) What is the difference between transfer_modules and load_library? Thanks,Ranjani