Commit b1ad9437 authored by Mark Brown's avatar Mark Brown

ASoC: SOF: ipc4/Intel: Implement split fw library

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

This series implements support for split library loading to comply with the HDA
DMA programming sequence recommendation, which is:
1. DSP side DMA programming and GEN bit set to 1
2. host side DMA programming and RUN bit set to 1

The SOF support for library loading is based on this sequence, backwards
compatibility with older reference firmware is supported (where only the
LOAD_LIBRARY message is supported).
parents e9c77480 5a8a9d70
......@@ -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,
......
......@@ -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__);
......
......@@ -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;
......
......@@ -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)
......
......@@ -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),
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment