diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 78568abe26735e..c58f00ef054a78 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -106,12 +106,19 @@ enum sof_ipc4_global_msg { SOF_IPC4_GLB_SAVE_PIPELINE, SOF_IPC4_GLB_RESTORE_PIPELINE, - /* Loads library (using Code Load or HD/A Host Output DMA) */ + /* + * library loading + * + * Loads library (using Code Load or HD/A Host Output DMA) + */ SOF_IPC4_GLB_LOAD_LIBRARY, + /* + * Prepare the host DMA channel for library loading, must be followed by + * a SOF_IPC4_GLB_LOAD_LIBRARY message as the library loading step + */ + SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE, - /* 25: RESERVED - do not use */ - - SOF_IPC4_GLB_INTERNAL_MESSAGE = 26, + SOF_IPC4_GLB_INTERNAL_MESSAGE, /* Notification (FW to SW driver) */ SOF_IPC4_GLB_NOTIFICATION, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 769697bdc3951a..46fb2d1425e9f2 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -545,11 +545,40 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size); + /* + * 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE + * Message includes the dma_id to be prepared for the library loading. + * If the firmware does not have support for the message, we will + * receive -EOPNOTSUPP. In this case we will use single step library + * loading and proceed to send the LOAD_LIBRARY message. + */ 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_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE); 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 = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); + if (!ret) { + int sd_offset = SOF_STREAM_SD_OFFSET(&hext_stream->hstream); + unsigned int status; + + /* + * Make sure that the FIFOS value is not 0 in SDxFIFOS register + * which indicates that the firmware set the GEN bit and we can + * continue to start the DMA + */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_SD_FIFOSIZE, + status, + status & SOF_HDA_SD_FIFOSIZE_FIFOS_MASK, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_BASEFW_TIMEOUT_US); + + if (ret < 0) + dev_warn(sdev->dev, + "%s: timeout waiting for FIFOS\n", __func__); + } else if (ret != -EOPNOTSUPP) { + goto cleanup; + } ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START); if (ret < 0) { @@ -557,8 +586,17 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, goto cleanup; } + /* + * 2nd stage: LOAD_LIBRARY + * Message includes the dma_id and the lib_id, the dma_id must be + * identical to the one sent via LOAD_LIBRARY_PREPARE + */ + msg.primary &= ~SOF_IPC4_MSG_TYPE_MASK; + msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY); + msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id); ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); + /* Stop the DMA channel */ ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP); if (ret1 < 0) { dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 0b0087abcc50ed..65e9242365bedb 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -668,7 +668,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_SD_FIFOSIZE); - hstream->fifo_size &= 0xffff; + hstream->fifo_size &= SOF_HDA_SD_FIFOSIZE_FIFOS_MASK; hstream->fifo_size += 1; } else { hstream->fifo_size = 0; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 5c517ec57d4a20..2b228c63905bfd 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -135,6 +135,9 @@ #define SOF_HDA_ADSP_REG_SD_BDLPU 0x1C #define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20 +/* SDxFIFOS FIFOS */ +#define SOF_HDA_SD_FIFOSIZE_FIFOS_MASK GENMASK(15, 0) + /* CL: Software Position Based FIFO Capability Registers */ #define SOF_DSP_REG_CL_SPBFIFO \ (SOF_HDA_ADSP_LOADER_BASE + 0x20) diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index ab6eddd91bb771..e14924048eb5b9 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -99,6 +99,10 @@ static int sof_ipc4_check_reply_status(struct snd_sof_dev *sdev, u32 status) to_errno: switch (status) { + case 2: + case 15: + ret = -EOPNOTSUPP; + break; case 8: case 11: case 105 ... 109: @@ -153,6 +157,7 @@ static const char * const ipc4_dbg_glb_msg_type[] = { DBG_IPC4_MSG_TYPE_ENTRY(GLB_SAVE_PIPELINE), DBG_IPC4_MSG_TYPE_ENTRY(GLB_RESTORE_PIPELINE), DBG_IPC4_MSG_TYPE_ENTRY(GLB_LOAD_LIBRARY), + DBG_IPC4_MSG_TYPE_ENTRY(GLB_LOAD_LIBRARY_PREPARE), DBG_IPC4_MSG_TYPE_ENTRY(GLB_INTERNAL_MESSAGE), DBG_IPC4_MSG_TYPE_ENTRY(GLB_NOTIFICATION), };