Skip to content

Commit

Permalink
ASoC: SOF: Intel: hda-loader: Add support for split library loading
Browse files Browse the repository at this point in the history
There is a certain sequence needs to be followed when configuring the HDA
DMA in host and DSP.
The firmware provides a way to handle this two stage sequencing by
splitting the library loading into two stage:
1st stage: LOAD_LIBRARY_PREPARE message
           the lib_id is 0, used to configure the DMA on DSP side
2nd stage: LOAD_LIBRARY message
           both dma_id and lib_id is valid, used for the actual transfer of
           the library

In case a firmware without support for this two stage loading is used then
the second stage message will trigger the loading and the first stage will
return with error, which is ignored by the kernel.

Signed-off-by: Peter Ujfalusi <[email protected]>
  • Loading branch information
ujfalusi authored and plbossart committed Aug 22, 2023
1 parent 8b0ef39 commit 1083fe3
Showing 1 changed file with 40 additions and 2 deletions.
42 changes: 40 additions & 2 deletions sound/soc/sof/intel/hda-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,20 +545,58 @@ 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) {
dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);
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__);
Expand Down

0 comments on commit 1083fe3

Please sign in to comment.