summaryrefslogtreecommitdiff
path: root/sound/soc/sof
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof')
-rw-r--r--sound/soc/sof/amd/acp-loader.c6
-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-skl.c7
-rw-r--r--sound/soc/sof/intel/hda-loader.c83
-rw-r--r--sound/soc/sof/intel/hda.h4
-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/pci-apl.c6
-rw-r--r--sound/soc/sof/intel/pci-cnl.c9
-rw-r--r--sound/soc/sof/intel/pci-icl.c6
-rw-r--r--sound/soc/sof/intel/pci-mtl.c5
-rw-r--r--sound/soc/sof/intel/pci-tgl.c54
-rw-r--r--sound/soc/sof/intel/tgl.c3
-rw-r--r--sound/soc/sof/ipc.c6
-rw-r--r--sound/soc/sof/ipc3-loader.c26
-rw-r--r--sound/soc/sof/ipc4-loader.c233
-rw-r--r--sound/soc/sof/ipc4-mtrace.c20
-rw-r--r--sound/soc/sof/ipc4-priv.h65
-rw-r--r--sound/soc/sof/ipc4-topology.c17
-rw-r--r--sound/soc/sof/ipc4.c41
-rw-r--r--sound/soc/sof/loader.c25
-rw-r--r--sound/soc/sof/sof-pci-dev.c26
-rw-r--r--sound/soc/sof/sof-priv.h27
24 files changed, 582 insertions, 99 deletions
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index d1e74baf5d8b..090c8b18c83c 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -48,7 +48,6 @@ EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON);
int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
u32 offset, void *src, size_t size)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct pci_dev *pci = to_pci_dev(sdev->dev);
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
struct acp_dev_data *adata;
@@ -61,7 +60,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
switch (blk_type) {
case SOF_FW_BLK_TYPE_IRAM:
if (!adata->bin_buf) {
- size_fw = plat_data->fw->size;
+ size_fw = sdev->basefw.fw->size;
page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
dma_size = page_count * ACP_PAGE_SIZE;
adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size,
@@ -152,7 +151,6 @@ static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev
int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct acp_dev_data *adata;
unsigned int src_addr, size_fw;
u32 page_count, dma_size;
@@ -186,7 +184,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
/* Free memory once DMA is complete */
- dma_size = (PAGE_ALIGN(plat_data->fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
+ dma_size = (PAGE_ALIGN(sdev->basefw.fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr);
dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf, adata->dma_addr);
adata->bin_buf = NULL;
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 da26f0ce9abc..2553afe6f27d 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -407,6 +407,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-skl.c b/sound/soc/sof/intel/hda-loader-skl.c
index 0193fb3964a0..3211f561db29 100644
--- a/sound/soc/sof/intel/hda-loader-skl.c
+++ b/sound/soc/sof/intel/hda-loader-skl.c
@@ -494,14 +494,13 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev,
struct snd_dma_buffer *dmab)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ const struct firmware *fw = sdev->basefw.fw;
struct firmware stripped_firmware;
unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE;
int ret;
- stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
- stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
+ stripped_firmware.data = fw->data + sdev->basefw.payload_offset;
+ stripped_firmware.size = fw->size - sdev->basefw.payload_offset;
dev_dbg(sdev->dev, "firmware size: %#zx buffer size %#x\n", fw->size, bufsize);
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 98812d51b31c..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"
@@ -318,7 +320,6 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct hdac_ext_stream *iccmax_stream;
struct hdac_bus *bus = sof_to_bus(sdev);
struct firmware stripped_firmware;
@@ -329,12 +330,12 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
/* save the original LTRP guardband value */
original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK;
- if (plat_data->fw->size <= plat_data->fw_offset) {
+ if (sdev->basefw.fw->size <= sdev->basefw.payload_offset) {
dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
return -EINVAL;
}
- stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
+ stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
/* prepare capture stream for ICCMAX */
iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
@@ -397,21 +398,25 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
hda->boot_iteration = 0;
ret = hda_dsp_boot_imr(sdev);
- if (!ret)
+ if (!ret) {
+ hda->booted_from_imr = true;
return 0;
+ }
dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n");
}
+ hda->booted_from_imr = false;
+
chip_info = desc->chip_info;
- if (plat_data->fw->size <= plat_data->fw_offset) {
+ if (sdev->basefw.fw->size <= sdev->basefw.payload_offset) {
dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
return -EINVAL;
}
- stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
- stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
+ stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
+ stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
/* init for booting wait */
init_waitqueue_head(&sdev->boot_wait);
@@ -515,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 65657d145dc2..c91fc3637823 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -481,6 +481,7 @@ enum sof_hda_D0_substate {
struct sof_intel_hda_dev {
bool imrboot_supported;
bool skip_imr_boot;
+ bool booted_from_imr;
int boot_iteration;
@@ -865,4 +866,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 054b9ab721ff..7e8b298786df 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -659,6 +659,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/pci-apl.c b/sound/soc/sof/intel/pci-apl.c
index 998e219011f0..69279dcc92dc 100644
--- a/sound/soc/sof/intel/pci-apl.c
+++ b/sound/soc/sof/intel/pci-apl.c
@@ -33,6 +33,9 @@ static const struct sof_dev_desc bxt_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/apl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/apl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -61,6 +64,9 @@ static const struct sof_dev_desc glk_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/glk",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/glk",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c
index c797356f7028..8db3f8d15b55 100644
--- a/sound/soc/sof/intel/pci-cnl.c
+++ b/sound/soc/sof/intel/pci-cnl.c
@@ -34,6 +34,9 @@ static const struct sof_dev_desc cnl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc cfl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -91,6 +97,9 @@ static const struct sof_dev_desc cml_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c
index 48f24f8ace26..d6cf75e357db 100644
--- a/sound/soc/sof/intel/pci-icl.c
+++ b/sound/soc/sof/intel/pci-icl.c
@@ -34,6 +34,9 @@ static const struct sof_dev_desc icl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/icl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/icl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc jsl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/jsl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/jsl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c
index 899b00d53d64..6e4e6d4ef5a5 100644
--- a/sound/soc/sof/intel/pci-mtl.c
+++ b/sound/soc/sof/intel/pci-mtl.c
@@ -34,11 +34,14 @@ static const struct sof_dev_desc mtl_desc = {
.default_fw_path = {
[SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/sof-ipc4-lib/mtl",
+ },
.default_tplg_path = {
[SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
},
.default_fw_filename = {
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_INTEL_IPC4] = "sof-mtl.ri",
},
.nocodec_tplg_filename = "sof-mtl-nocodec.tplg",
.ops = &sof_mtl_ops,
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index 2d63cc236a68..e80c4dfef85a 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -34,6 +34,9 @@ static const struct sof_dev_desc tgl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/tgl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc tglh_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl-h",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/tgl-h",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -90,6 +96,9 @@ static const struct sof_dev_desc ehl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/ehl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/ehl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -118,6 +127,9 @@ static const struct sof_dev_desc adls_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl-s",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/adl-s",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -146,6 +158,9 @@ static const struct sof_dev_desc adl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/adl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -159,6 +174,37 @@ static const struct sof_dev_desc adl_desc = {
.ops_init = sof_tgl_ops_init,
};
+static const struct sof_dev_desc adl_n_desc = {
+ .machines = snd_soc_acpi_intel_adl_machines,
+ .alt_machines = snd_soc_acpi_intel_adl_sdw_machines,
+ .use_acpi_target_states = true,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &tgl_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
+ .ipc_default = SOF_IPC,
+ .default_fw_path = {
+ [SOF_IPC] = "intel/sof",
+ [SOF_INTEL_IPC4] = "intel/avs/adl-n",
+ },
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/adl-n",
+ },
+ .default_tplg_path = {
+ [SOF_IPC] = "intel/sof-tplg",
+ [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC] = "sof-adl-n.ri",
+ [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ },
+ .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
+ .ops = &sof_tgl_ops,
+ .ops_init = sof_tgl_ops_init,
+};
+
static const struct sof_dev_desc rpls_desc = {
.machines = snd_soc_acpi_intel_rpl_machines,
.alt_machines = snd_soc_acpi_intel_rpl_sdw_machines,
@@ -174,6 +220,9 @@ static const struct sof_dev_desc rpls_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/rpl-s",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/rpl-s",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -202,6 +251,9 @@ static const struct sof_dev_desc rpl_desc = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/rpl",
},
+ .default_lib_path = {
+ [SOF_INTEL_IPC4] = "intel/avs-lib/rpl",
+ },
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -246,7 +298,7 @@ static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0x51cf), /* RPL-PX */
.driver_data = (unsigned long)&rpl_desc},
{ PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */
- .driver_data = (unsigned long)&adl_desc},
+ .driver_data = (unsigned long)&adl_n_desc},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
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;
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index 6ed3f9b6a0c4..30781e808a02 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -200,6 +200,9 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
return NULL;
}
+ if (ops->init && ops->init(sdev))
+ return NULL;
+
ipc->ops = ops;
return ipc;
@@ -217,5 +220,8 @@ void snd_sof_ipc_free(struct snd_sof_dev *sdev)
mutex_lock(&ipc->tx_mutex);
ipc->disable_ipc_tx = true;
mutex_unlock(&ipc->tx_mutex);
+
+ if (ipc->ops->exit)
+ ipc->ops->exit(sdev);
}
EXPORT_SYMBOL(snd_sof_ipc_free);
diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c
index bf423ca4e97b..28218766d211 100644
--- a/sound/soc/sof/ipc3-loader.c
+++ b/sound/soc/sof/ipc3-loader.c
@@ -138,8 +138,7 @@ static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmw
static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ const struct firmware *fw = sdev->basefw.fw;
const struct sof_ext_man_elem_header *elem_hdr;
const struct sof_ext_man_header *head;
ssize_t ext_man_size;
@@ -310,18 +309,18 @@ static int sof_ipc3_parse_module_memcpy(struct snd_sof_dev *sdev,
static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ u32 payload_offset = sdev->basefw.payload_offset;
+ const struct firmware *fw = sdev->basefw.fw;
struct snd_sof_fw_header *header;
struct snd_sof_mod_hdr *module;
int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr);
size_t remaining;
int ret, count;
- if (!plat_data->fw)
+ if (!fw)
return -EINVAL;
- header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset);
+ header = (struct snd_sof_fw_header *)(fw->data + payload_offset);
load_module = sof_ops(sdev)->load_module;
if (!load_module) {
dev_dbg(sdev->dev, "Using generic module loading\n");
@@ -331,9 +330,8 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
}
/* parse each module */
- module = (struct snd_sof_mod_hdr *)(fw->data + plat_data->fw_offset +
- sizeof(*header));
- remaining = fw->size - sizeof(*header) - plat_data->fw_offset;
+ module = (struct snd_sof_mod_hdr *)(fw->data + payload_offset + sizeof(*header));
+ remaining = fw->size - sizeof(*header) - payload_offset;
/* check for wrap */
if (remaining > fw->size) {
dev_err(sdev->dev, "%s: fw size smaller than header size\n", __func__);
@@ -374,19 +372,19 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
static int sof_ipc3_validate_firmware(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
- const struct firmware *fw = plat_data->fw;
+ u32 payload_offset = sdev->basefw.payload_offset;
+ const struct firmware *fw = sdev->basefw.fw;
struct snd_sof_fw_header *header;
- size_t fw_size = fw->size - plat_data->fw_offset;
+ size_t fw_size = fw->size - payload_offset;
- if (fw->size <= plat_data->fw_offset) {
+ if (fw->size <= payload_offset) {
dev_err(sdev->dev,
"firmware size must be greater than firmware offset\n");
return -EINVAL;
}
/* Read the header information from the data pointer */
- header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset);
+ header = (struct snd_sof_fw_header *)(fw->data + payload_offset);
/* verify FW sig */
if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index e635ae515fa9..af0018b38cf0 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -14,12 +14,15 @@
#include "sof-priv.h"
#include "ops.h"
-static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
+/* The module ID includes the id of the library it is part of at offset 12 */
+#define SOF_IPC4_MOD_LIB_ID_SHIFT 12
+
+static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_library *fw_lib)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct snd_sof_pdata *plat_data = sdev->pdata;
+ const struct firmware *fw = fw_lib->sof_fw.fw;
struct sof_man4_fw_binary_header *fw_header;
- const struct firmware *fw = plat_data->fw;
struct sof_ext_manifest4_hdr *ext_man_hdr;
struct sof_man4_module_config *fm_config;
struct sof_ipc4_fw_module *fw_module;
@@ -71,20 +74,20 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
return -EINVAL;
}
- dev_info(sdev->dev, "Loaded firmware version: %u.%u.%u.%u\n",
- fw_header->major_version, fw_header->minor_version,
+ dev_info(sdev->dev, "Loaded firmware library: %s, version: %u.%u.%u.%u\n",
+ fw_header->name, fw_header->major_version, fw_header->minor_version,
fw_header->hotfix_version, fw_header->build_version);
- dev_dbg(sdev->dev, "Firmware name: %s, header length: %u, module count: %u\n",
- fw_header->name, fw_header->len, fw_header->num_module_entries);
+ dev_dbg(sdev->dev, "Header length: %u, module count: %u\n",
+ fw_header->len, fw_header->num_module_entries);
- ipc4_data->fw_modules = devm_kmalloc_array(sdev->dev,
- fw_header->num_module_entries,
- sizeof(*fw_module), GFP_KERNEL);
- if (!ipc4_data->fw_modules)
+ fw_lib->modules = devm_kmalloc_array(sdev->dev, fw_header->num_module_entries,
+ sizeof(*fw_module), GFP_KERNEL);
+ if (!fw_lib->modules)
return -ENOMEM;
- ipc4_data->num_fw_modules = fw_header->num_module_entries;
- fw_module = ipc4_data->fw_modules;
+ fw_lib->name = fw_header->name;
+ fw_lib->num_modules = fw_header->num_module_entries;
+ fw_module = fw_lib->modules;
fm_entry = (struct sof_man4_module *)((u8 *)fw_header + fw_header->len);
remaining -= fw_header->len;
@@ -134,13 +137,182 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
return ext_man_hdr->len;
}
+static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ size_t payload_offset;
+ int ret;
+
+ fw_lib = devm_kzalloc(sdev->dev, sizeof(*fw_lib), GFP_KERNEL);
+ if (!fw_lib)
+ return -ENOMEM;
+
+ fw_lib->sof_fw.fw = sdev->basefw.fw;
+
+ payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
+ if (payload_offset > 0) {
+ fw_lib->sof_fw.payload_offset = payload_offset;
+
+ /* basefw ID is 0 */
+ fw_lib->id = 0;
+ ret = xa_insert(&ipc4_data->fw_lib_xa, 0, fw_lib, GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ return payload_offset;
+}
+
+static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
+ unsigned long lib_id, const guid_t *uuid)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ const char *fw_filename;
+ size_t payload_offset;
+ int ret, i, err;
+
+ if (!sdev->pdata->fw_lib_prefix) {
+ dev_err(sdev->dev,
+ "Library loading is not supported due to not set library path\n");
+ return -EINVAL;
+ }
+
+ if (!ipc4_data->load_library) {
+ dev_err(sdev->dev, "Library loading is not supported on this platform\n");
+ return -EOPNOTSUPP;
+ }
+
+ fw_lib = devm_kzalloc(sdev->dev, sizeof(*fw_lib), GFP_KERNEL);
+ if (!fw_lib)
+ return -ENOMEM;
+
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin",
+ sdev->pdata->fw_lib_prefix, uuid);
+ if (!fw_filename) {
+ ret = -ENOMEM;
+ goto free_fw_lib;
+ }
+
+ ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename);
+ goto free_filename;
+ } else {
+ dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename);
+ }
+
+ payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
+ if (payload_offset <= 0) {
+ if (!payload_offset)
+ ret = -EINVAL;
+ else
+ ret = payload_offset;
+
+ goto release;
+ }
+
+ fw_lib->sof_fw.payload_offset = payload_offset;
+ fw_lib->id = lib_id;
+
+ /* Fix up the module ID numbers within the library */
+ for (i = 0; i < fw_lib->num_modules; i++)
+ fw_lib->modules[i].man4_module_entry.id |= (lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT);
+
+ /*
+ * Make sure that the DSP is booted and stays up while attempting the
+ * loading the library for the first time
+ */
+ ret = pm_runtime_resume_and_get(sdev->dev);
+ if (ret < 0 && ret != -EACCES) {
+ dev_err_ratelimited(sdev->dev, "%s: pm_runtime resume failed: %d\n",
+ __func__, ret);
+ goto release;
+ }
+
+ ret = ipc4_data->load_library(sdev, fw_lib, false);
+
+ pm_runtime_mark_last_busy(sdev->dev);
+ err = pm_runtime_put_autosuspend(sdev->dev);
+ if (err < 0)
+ dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
+ __func__, err);
+
+ if (ret)
+ goto release;
+
+ ret = xa_insert(&ipc4_data->fw_lib_xa, lib_id, fw_lib, GFP_KERNEL);
+ if (unlikely(ret))
+ goto release;
+
+ kfree(fw_filename);
+
+ return 0;
+
+release:
+ release_firmware(fw_lib->sof_fw.fw);
+ /* Allocated within sof_ipc4_fw_parse_ext_man() */
+ devm_kfree(sdev->dev, fw_lib->modules);
+free_filename:
+ kfree(fw_filename);
+free_fw_lib:
+ devm_kfree(sdev->dev, fw_lib);
+
+ return ret;
+}
+
+struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
+ const guid_t *uuid)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ unsigned long lib_id;
+ int i, ret;
+
+ if (guid_is_null(uuid))
+ return NULL;
+
+ xa_for_each(&ipc4_data->fw_lib_xa, lib_id, fw_lib) {
+ for (i = 0; i < fw_lib->num_modules; i++) {
+ if (guid_equal(uuid, &fw_lib->modules[i].man4_module_entry.uuid))
+ return &fw_lib->modules[i];
+ }
+ }
+
+ /*
+ * Do not attempt to load external library in case the maximum number of
+ * firmware libraries have been already loaded
+ */
+ if ((lib_id + 1) == ipc4_data->max_libs_count) {
+ dev_err(sdev->dev,
+ "%s: Maximum allowed number of libraries reached (%u)\n",
+ __func__, ipc4_data->max_libs_count);
+ return NULL;
+ }
+
+ /* The module cannot be found, try to load it as a library */
+ ret = sof_ipc4_load_library_by_uuid(sdev, lib_id + 1, uuid);
+ if (ret)
+ return NULL;
+
+ /* Look for the module in the newly loaded library, it should be available now */
+ xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, lib_id) {
+ for (i = 0; i < fw_lib->num_modules; i++) {
+ if (guid_equal(uuid, &fw_lib->modules[i].man4_module_entry.uuid))
+ return &fw_lib->modules[i];
+ }
+ }
+
+ return NULL;
+}
+
static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
u32 fw_hdr_offset = ipc4_data->manifest_fw_hdr_offset;
- struct snd_sof_pdata *plat_data = sdev->pdata;
struct sof_man4_fw_binary_header *fw_header;
- const struct firmware *fw = plat_data->fw;
+ const struct firmware *fw = sdev->basefw.fw;
struct sof_ext_manifest4_hdr *ext_man_hdr;
ext_man_hdr = (struct sof_ext_manifest4_hdr *)fw->data;
@@ -156,7 +328,7 @@ static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev)
return 0;
}
-static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
+int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
const struct sof_ipc_ops *iops = sdev->ipc->ops;
@@ -204,6 +376,13 @@ static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
trace_sof_ipc4_fw_config(sdev, "Trace log size", *tuple->value);
ipc4_data->mtrace_log_bytes = *tuple->value;
break;
+ case SOF_IPC4_FW_CFG_MAX_LIBS_COUNT:
+ trace_sof_ipc4_fw_config(sdev, "maximum number of libraries",
+ *tuple->value);
+ ipc4_data->max_libs_count = *tuple->value;
+ if (!ipc4_data->max_libs_count)
+ ipc4_data->max_libs_count = 1;
+ break;
default:
break;
}
@@ -217,8 +396,26 @@ out:
return ret;
}
+int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ unsigned long lib_id;
+ int ret = 0;
+
+ xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, 1) {
+ ret = ipc4_data->load_library(sdev, fw_lib, true);
+ if (ret) {
+ dev_err(sdev->dev, "%s: Failed to reload library: %s, %d\n",
+ __func__, fw_lib->name, ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
const struct sof_ipc_fw_loader_ops ipc4_loader_ops = {
.validate = sof_ipc4_validate_firmware,
- .parse_ext_manifest = sof_ipc4_fw_parse_ext_man,
- .query_fw_configuration = sof_ipc4_query_fw_configuration,
+ .parse_ext_manifest = sof_ipc4_fw_parse_basefw_ext_man,
};
diff --git a/sound/soc/sof/ipc4-mtrace.c b/sound/soc/sof/ipc4-mtrace.c
index 9c7080041d08..70dea8ae706e 100644
--- a/sound/soc/sof/ipc4-mtrace.c
+++ b/sound/soc/sof/ipc4-mtrace.c
@@ -108,6 +108,7 @@ struct sof_mtrace_core_data {
int id;
u32 slot_offset;
void *log_buffer;
+ struct mutex buffer_lock; /* for log_buffer alloc/free */
u32 host_read_ptr;
u32 dsp_write_ptr;
/* pos update IPC arrived before the slot offset is known, queried */
@@ -128,14 +129,22 @@ static int sof_ipc4_mtrace_dfs_open(struct inode *inode, struct file *file)
struct sof_mtrace_core_data *core_data = inode->i_private;
int ret;
+ mutex_lock(&core_data->buffer_lock);
+
+ if (core_data->log_buffer) {
+ ret = -EBUSY;
+ goto out;
+ }
+
ret = debugfs_file_get(file->f_path.dentry);
if (unlikely(ret))
- return ret;
+ goto out;
core_data->log_buffer = kmalloc(SOF_MTRACE_SLOT_SIZE, GFP_KERNEL);
if (!core_data->log_buffer) {
debugfs_file_put(file->f_path.dentry);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
ret = simple_open(inode, file);
@@ -144,6 +153,9 @@ static int sof_ipc4_mtrace_dfs_open(struct inode *inode, struct file *file)
debugfs_file_put(file->f_path.dentry);
}
+out:
+ mutex_unlock(&core_data->buffer_lock);
+
return ret;
}
@@ -280,7 +292,10 @@ static int sof_ipc4_mtrace_dfs_release(struct inode *inode, struct file *file)
debugfs_file_put(file->f_path.dentry);
+ mutex_lock(&core_data->buffer_lock);
kfree(core_data->log_buffer);
+ core_data->log_buffer = NULL;
+ mutex_unlock(&core_data->buffer_lock);
return 0;
}
@@ -563,6 +578,7 @@ static int ipc4_mtrace_init(struct snd_sof_dev *sdev)
struct sof_mtrace_core_data *core_data = &priv->cores[i];
init_waitqueue_head(&core_data->trace_sleep);
+ mutex_init(&core_data->buffer_lock);
core_data->sdev = sdev;
core_data->id = i;
}
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index e3b8484a2f1f..d6f35004c4b7 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -25,35 +25,61 @@ enum sof_ipc4_mtrace_type {
};
/**
+ * struct sof_ipc4_fw_module - IPC4 module info
+ * @sof_man4_module: Module info
+ * @m_ida: Module instance identifier
+ * @bss_size: Module object size
+ * @private: Module private data
+ */
+struct sof_ipc4_fw_module {
+ struct sof_man4_module man4_module_entry;
+ struct ida m_ida;
+ u32 bss_size;
+ void *private;
+};
+
+/**
+ * struct sof_ipc4_fw_library - IPC4 library information
+ * @sof_fw: SOF Firmware of the library
+ * @id: Library ID. 0 is reserved for basefw, external libraries must have unique
+ * ID number between 1 and (sof_ipc4_fw_data.max_libs_count - 1)
+ * Note: sof_ipc4_fw_data.max_libs_count == 1 implies that external libraries
+ * are not supported
+ * @num_modules : Number of FW modules in the library
+ * @modules: Array of FW modules
+ */
+struct sof_ipc4_fw_library {
+ struct sof_firmware sof_fw;
+ const char *name;
+ u32 id;
+ int num_modules;
+ struct sof_ipc4_fw_module *modules;
+};
+
+/**
* struct sof_ipc4_fw_data - IPC4-specific data
* @manifest_fw_hdr_offset: FW header offset in the manifest
- * @num_fw_modules : Number of modules in base FW
- * @fw_modules: Array of base FW modules
+ * @fw_lib_xa: XArray for firmware libraries, including basefw (ID = 0)
+ * Used to store the FW libraries and to manage the unique IDs of the
+ * libraries.
* @nhlt: NHLT table either from the BIOS or the topology manifest
* @mtrace_type: mtrace type supported on the booted platform
* @mtrace_log_bytes: log bytes as reported by the firmware via fw_config reply
+ * @max_libs_count: Maximum number of libraries support by the FW including the
+ * base firmware
+ *
+ * @load_library: Callback function for platform dependent library loading
*/
struct sof_ipc4_fw_data {
u32 manifest_fw_hdr_offset;
- int num_fw_modules;
- void *fw_modules;
+ struct xarray fw_lib_xa;
void *nhlt;
enum sof_ipc4_mtrace_type mtrace_type;
u32 mtrace_log_bytes;
-};
+ u32 max_libs_count;
-/**
- * struct sof_ipc4_fw_module - IPC4 module info
- * @sof_man4_module : Module info
- * @m_ida: Module instance identifier
- * @bss_size: Module object size
- * @private: Module private data
- */
-struct sof_ipc4_fw_module {
- struct sof_man4_module man4_module_entry;
- struct ida m_ida;
- u32 bss_size;
- void *private;
+ int (*load_library)(struct snd_sof_dev *sdev,
+ struct sof_ipc4_fw_library *fw_lib, bool reload);
};
extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
@@ -64,4 +90,9 @@ extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops;
int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core);
+
+int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
+int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
+struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
+ const guid_t *uuid);
#endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index a81af5f73a4b..ab85dde4303b 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -289,22 +289,11 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct sof_ipc4_fw_module *fw_modules = ipc4_data->fw_modules;
- int i;
- if (!fw_modules) {
- dev_err(sdev->dev, "no fw_module information\n");
- return -EINVAL;
- }
+ swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
- /* set module info */
- for (i = 0; i < ipc4_data->num_fw_modules; i++) {
- if (guid_equal(&swidget->uuid, &fw_modules[i].man4_module_entry.uuid)) {
- swidget->module_info = &fw_modules[i];
- return 0;
- }
- }
+ if (swidget->module_info)
+ return 0;
dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
swidget->widget->name, &swidget->uuid);
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 3c9b8692984a..74cd7e956019 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -8,6 +8,7 @@
// Authors: Rander Wang <rander.wang@linux.intel.com>
// Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
//
+#include <linux/firmware.h>
#include <sound/sof/header.h>
#include <sound/sof/ipc4/header.h>
#include "sof-priv.h"
@@ -657,7 +658,47 @@ static const struct sof_ipc_pm_ops ipc4_pm_ops = {
.set_core_state = sof_ipc4_set_core_state,
};
+static int sof_ipc4_init(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+ xa_init_flags(&ipc4_data->fw_lib_xa, XA_FLAGS_ALLOC);
+
+ return 0;
+}
+
+static void sof_ipc4_exit(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ unsigned long lib_id;
+
+ xa_for_each(&ipc4_data->fw_lib_xa, lib_id, fw_lib) {
+ /*
+ * The basefw (ID == 0) is handled by generic code, it is not
+ * loaded by IPC4 code.
+ */
+ if (lib_id != 0)
+ release_firmware(fw_lib->sof_fw.fw);
+
+ fw_lib->sof_fw.fw = NULL;
+ }
+
+ xa_destroy(&ipc4_data->fw_lib_xa);
+}
+
+static int sof_ipc4_post_boot(struct snd_sof_dev *sdev)
+{
+ if (sdev->first_boot)
+ return sof_ipc4_query_fw_configuration(sdev);
+
+ return sof_ipc4_reload_fw_libraries(sdev);
+}
+
const struct sof_ipc_ops ipc4_ops = {
+ .init = sof_ipc4_init,
+ .exit = sof_ipc4_exit,
+ .post_fw_boot = sof_ipc4_post_boot,
.tx_msg = sof_ipc4_tx_msg,
.rx_msg = sof_ipc4_rx_msg,
.set_get_data = sof_ipc4_set_get_data,
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
index 5f51d936b306..81d202e5ce53 100644
--- a/sound/soc/sof/loader.c
+++ b/sound/soc/sof/loader.c
@@ -22,7 +22,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
int ret;
/* Don't request firmware again if firmware is already requested */
- if (plat_data->fw)
+ if (sdev->basefw.fw)
return 0;
fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
@@ -31,7 +31,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
if (!fw_filename)
return -ENOMEM;
- ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
+ ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
if (ret < 0) {
dev_err(sdev->dev,
@@ -48,7 +48,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
if (ext_man_size > 0) {
/* when no error occurred, drop extended manifest */
- plat_data->fw_offset = ext_man_size;
+ sdev->basefw.payload_offset = ext_man_size;
} else if (!ext_man_size) {
/* No extended manifest, so nothing to skip during FW load */
dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
@@ -67,7 +67,6 @@ EXPORT_SYMBOL(snd_sof_load_firmware_raw);
int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
{
- struct snd_sof_pdata *plat_data = sdev->pdata;
int ret;
ret = snd_sof_load_firmware_raw(sdev);
@@ -100,8 +99,8 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
return 0;
error:
- release_firmware(plat_data->fw);
- plat_data->fw = NULL;
+ release_firmware(sdev->basefw.fw);
+ sdev->basefw.fw = NULL;
return ret;
}
@@ -165,6 +164,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED)
return -EIO; /* FW boots but fw_ready op failed */
+ dev_dbg(sdev->dev, "firmware boot complete\n");
+ sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
+
/* perform post fw run operations */
ret = snd_sof_dsp_post_fw_run(sdev);
if (ret < 0) {
@@ -172,11 +174,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
return ret;
}
- dev_dbg(sdev->dev, "firmware boot complete\n");
- sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
-
- if (sdev->first_boot && sdev->ipc->ops->fw_loader->query_fw_configuration)
- return sdev->ipc->ops->fw_loader->query_fw_configuration(sdev);
+ if (sdev->ipc->ops->post_fw_boot)
+ return sdev->ipc->ops->post_fw_boot(sdev);
return 0;
}
@@ -185,7 +184,7 @@ EXPORT_SYMBOL(snd_sof_run_firmware);
void snd_sof_fw_unload(struct snd_sof_dev *sdev)
{
/* TODO: support module unloading at runtime */
- release_firmware(sdev->pdata->fw);
- sdev->pdata->fw = NULL;
+ release_firmware(sdev->basefw.fw);
+ sdev->basefw.fw = NULL;
}
EXPORT_SYMBOL(snd_sof_fw_unload);
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 643fd1036d60..f5ece43d0ec2 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -28,6 +28,10 @@ static char *fw_filename;
module_param(fw_filename, charp, 0444);
MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware.");
+static char *lib_path;
+module_param(lib_path, charp, 0444);
+MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries.");
+
static char *tplg_path;
module_param(tplg_path, charp, 0444);
MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
@@ -272,6 +276,28 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
sof_pdata->desc->default_fw_path[sof_pdata->ipc_type];
}
+ if (lib_path) {
+ sof_pdata->fw_lib_prefix = lib_path;
+
+ dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
+ sof_pdata->fw_lib_prefix);
+
+ } else if (sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]) {
+ if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
+ sof_pdata->fw_lib_prefix =
+ devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
+ sof_pdata->desc->default_lib_path[sof_pdata->ipc_type],
+ "community");
+
+ dev_dbg(dev,
+ "Platform uses community key, changed fw_lib path to %s\n",
+ sof_pdata->fw_lib_prefix);
+ } else {
+ sof_pdata->fw_lib_prefix =
+ sof_pdata->desc->default_lib_path[sof_pdata->ipc_type];
+ }
+ }
+
if (tplg_path)
sof_pdata->tplg_filename_prefix = tplg_path;
else
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index de08825915b3..403e81220244 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -136,6 +136,17 @@ struct snd_sof_platform_stream_params {
bool cont_update_posn;
};
+/**
+ * struct sof_firmware - Container struct for SOF firmware
+ * @fw: Pointer to the firmware
+ * @payload_offset: Offset of the data within the loaded firmware image to be
+ * loaded to the DSP (skipping for example ext_manifest section)
+ */
+struct sof_firmware {
+ const struct firmware *fw;
+ u32 payload_offset;
+};
+
/*
* SOF DSP HW abstraction operations.
* Used to abstract DSP HW architecture and any IO busses between host CPU
@@ -410,15 +421,11 @@ struct sof_ipc_pm_ops {
* DSP.
* The function implements generic, hardware independent way
* of loading the initial firmware and its modules (if any).
- * @query_fw_configuration: Optional function pointer to query information and
- * configuration from the booted firmware.
- * Executed after the first successful firmware boot.
*/
struct sof_ipc_fw_loader_ops {
int (*validate)(struct snd_sof_dev *sdev);
size_t (*parse_ext_manifest)(struct snd_sof_dev *sdev);
int (*load_fw_to_dsp)(struct snd_sof_dev *sdev);
- int (*query_fw_configuration)(struct snd_sof_dev *sdev);
};
struct sof_ipc_tplg_ops;
@@ -432,6 +439,11 @@ struct sof_ipc_pcm_ops;
* @fw_loader: Pointer to Firmware Loader ops
* @fw_tracing: Pointer to Firmware tracing ops
*
+ * @init: Optional pointer for IPC related initialization
+ * @exit: Optional pointer for IPC related cleanup
+ * @post_fw_boot: Optional pointer to execute IPC related tasks after firmware
+ * boot.
+ *
* @tx_msg: Function pointer for sending a 'short' IPC message
* @set_get_data: Function pointer for set/get data ('large' IPC message). This
* function may split up the 'large' message and use the @tx_msg
@@ -453,6 +465,10 @@ struct sof_ipc_ops {
const struct sof_ipc_fw_loader_ops *fw_loader;
const struct sof_ipc_fw_tracing_ops *fw_tracing;
+ int (*init)(struct snd_sof_dev *sdev);
+ void (*exit)(struct snd_sof_dev *sdev);
+ int (*post_fw_boot)(struct snd_sof_dev *sdev);
+
int (*tx_msg)(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
void *reply_data, size_t reply_bytes, bool no_pm);
int (*set_get_data)(struct snd_sof_dev *sdev, void *data, size_t data_bytes,
@@ -487,6 +503,9 @@ struct snd_sof_dev {
spinlock_t ipc_lock; /* lock for IPC users */
spinlock_t hw_lock; /* lock for HW IO access */
+ /* Main, Base firmware image */
+ struct sof_firmware basefw;
+
/*
* ASoC components. plat_drv fields are set dynamically so
* can't use const