[PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA
Ranjani Sridharan
ranjani.sridharan at linux.intel.com
Fri Mar 4 17:59:59 CET 2022
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 at linux.intel.com>
> Signed-off-by: Cezary Rojewski <cezary.rojewski at intel.com>
> ---
> 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
More information about the Alsa-devel
mailing list