Re: [PATCH v3 17/17] ASoC: Intel: avs: Code loading over HDA

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux