summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@linux.intel.com>2022-10-20 15:12:34 +0300
committerMark Brown <broonie@kernel.org>2022-10-21 13:05:07 +0100
commit3ab2c21e65188cac151de1fbe6adf841f2ecb082 (patch)
tree27e77f9e4777c851ae1f5abdfae0f9269188f96b
parent5d5d915bcde228cd78f5d42062fb65babe651363 (diff)
downloadlinux-3ab2c21e65188cac151de1fbe6adf841f2ecb082.tar.bz2
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: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Chao Song <chao.song@intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Link: https://lore.kernel.org/r/20221020121238.18339-16-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--include/sound/sof/ipc4/header.h4
-rw-r--r--sound/soc/sof/intel/apl.c3
-rw-r--r--sound/soc/sof/intel/cnl.c3
-rw-r--r--sound/soc/sof/intel/hda-loader.c66
-rw-r--r--sound/soc/sof/intel/hda.h3
-rw-r--r--sound/soc/sof/intel/icl.c3
-rw-r--r--sound/soc/sof/intel/mtl.c3
-rw-r--r--sound/soc/sof/intel/tgl.c3
8 files changed, 88 insertions, 0 deletions
diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h
index 99efe0ef1784..622193be7ac4 100644
--- a/include/sound/sof/ipc4/header.h
+++ b/include/sound/sof/ipc4/header.h
@@ -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,
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 1549ca7587a4..d93b4ead3c37 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -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;
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 19d0b1909bfd..f1e74b49deda 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -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;
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 5ed524e166d2..38204541fc5d 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -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 @@ cleanup:
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)
{
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index d004bcbb6326..4b9f3819f644 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -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
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index 6d5877108a3d..f95b2ec57077 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -130,6 +130,9 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* doorbell */
sof_icl_ops.irq_thread = cnl_ipc4_irq_thread;
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 10298532816f..459da05f4d7a 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -641,6 +641,9 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* set DAI ops */
hda_set_dai_drv_ops(sdev, &sof_mtl_ops);
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 9ae2890e9dac..143447f7c1ac 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -85,6 +85,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
/* doorbell */
sof_tgl_ops.irq_thread = cnl_ipc4_irq_thread;