Unverified Commit 3ab2c21e authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Mark Brown
Browse files

ASoC: SOF: Intel: Add ipc4 library loading implementation



On Intel HDA platforms the library loading is done via DMA and an IPC
message is also need to be sent to initiate the downloading of the new
library.

Co-developed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarChao Song <chao.song@intel.com>
Reviewed-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20221020121238.18339-16-peter.ujfalusi@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 5d5d915b
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -185,6 +185,10 @@ enum sof_ipc4_pipeline_state {
#define SOF_IPC4_GLB_PIPE_STATE_MASK		GENMASK(15, 0)
#define SOF_IPC4_GLB_PIPE_STATE(x)		((x) << SOF_IPC4_GLB_PIPE_STATE_SHIFT)

/* load library ipc msg */
#define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT	16
#define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(x)	((x) << SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT)

enum sof_ipc4_channel_config {
	/* one channel only. */
	SOF_IPC4_CHANNEL_CONFIG_MONO,
+3 −0
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)

		ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5;

		/* External library loading support */
		ipc4_data->load_library = hda_dsp_ipc4_load_library;

		/* doorbell */
		sof_apl_ops.irq_thread	= hda_dsp_ipc4_irq_thread;

+3 −0
Original line number Diff line number Diff line
@@ -389,6 +389,9 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)

		ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_8;

		/* External library loading support */
		ipc4_data->load_library = hda_dsp_ipc4_load_library;

		/* doorbell */
		sof_cnl_ops.irq_thread	= cnl_ipc4_irq_thread;

+66 −0
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include <sound/sof.h>
#include <sound/sof/ipc4/header.h>
#include "ext_manifest.h"
#include "../ipc4-priv.h"
#include "../ops.h"
#include "../sof-priv.h"
#include "hda.h"
@@ -518,6 +520,70 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
	return ret;
}

int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
			      struct sof_ipc4_fw_library *fw_lib, bool reload)
{
	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
	struct hdac_ext_stream *hext_stream;
	struct firmware stripped_firmware;
	struct sof_ipc4_msg msg = {};
	struct snd_dma_buffer dmab;
	int ret, ret1;

	/* IMR booting will restore the libraries as well, skip the loading */
	if (reload && hda->booted_from_imr)
		return 0;

	/* the fw_lib has been verified during loading, we can trust the validity here */
	stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset;
	stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;

	/* prepare DMA for code loader stream */
	hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
					    stripped_firmware.size,
					    &dmab, SNDRV_PCM_STREAM_PLAYBACK);
	if (IS_ERR(hext_stream)) {
		dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);
		return PTR_ERR(hext_stream);
	}

	memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size);

	msg.primary = hext_stream->hstream.stream_tag - 1;
	msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY);
	msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
	msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
	msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id);

	ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START);
	if (ret < 0) {
		dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);
		goto cleanup;
	}

	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);

	ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
	if (ret1 < 0) {
		dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__);
		if (!ret)
			ret = ret1;
	}

cleanup:
	/* clean up even in case of error and return the first error */
	ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
	if (ret1 < 0) {
		dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);

		/* set return value to indicate cleanup failure */
		if (!ret)
			ret = ret1;
	}

	return ret;
}

/* pre fw run operations */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
+3 −0
Original line number Diff line number Diff line
@@ -857,4 +857,7 @@ int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
void hda_ipc4_dump(struct snd_sof_dev *sdev);
extern struct sdw_intel_ops sdw_callback;

struct sof_ipc4_fw_library;
int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
			      struct sof_ipc4_fw_library *fw_lib, bool reload);
#endif
Loading