summaryrefslogtreecommitdiff
path: root/sound/soc/sof/ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/ipc.c')
-rw-r--r--sound/soc/sof/ipc.c134
1 files changed, 105 insertions, 29 deletions
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index e6c53c6c470e..5bcf906d90af 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -173,7 +173,22 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
}
break;
case SOF_IPC_GLB_TRACE_MSG:
- str = "GLB_TRACE_MSG"; break;
+ str = "GLB_TRACE_MSG";
+ switch (type) {
+ case SOF_IPC_TRACE_DMA_PARAMS:
+ str2 = "DMA_PARAMS"; break;
+ case SOF_IPC_TRACE_DMA_POSITION:
+ str2 = "DMA_POSITION"; break;
+ case SOF_IPC_TRACE_DMA_PARAMS_EXT:
+ str2 = "DMA_PARAMS_EXT"; break;
+ case SOF_IPC_TRACE_FILTER_UPDATE:
+ str2 = "FILTER_UPDATE"; break;
+ case SOF_IPC_TRACE_DMA_FREE:
+ str2 = "DMA_FREE"; break;
+ default:
+ str2 = "unknown type"; break;
+ }
+ break;
case SOF_IPC_GLB_TEST_MSG:
str = "GLB_TEST_MSG";
switch (type) {
@@ -287,7 +302,7 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header,
struct snd_sof_ipc_msg *msg;
int ret;
- if (ipc->disable_ipc_tx)
+ if (ipc->disable_ipc_tx || sdev->fw_state != SOF_FW_BOOT_COMPLETE)
return -ENODEV;
/*
@@ -379,6 +394,67 @@ int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, u32 header,
}
EXPORT_SYMBOL(sof_ipc_tx_message_no_pm);
+/* Generic helper function to retrieve the reply */
+void snd_sof_ipc_get_reply(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_ipc_msg *msg = sdev->msg;
+ struct sof_ipc_reply reply;
+ int ret = 0;
+
+ /*
+ * Sometimes, there is unexpected reply ipc arriving. The reply
+ * ipc belongs to none of the ipcs sent from driver.
+ * In this case, the driver must ignore the ipc.
+ */
+ if (!msg) {
+ dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
+ return;
+ }
+
+ /* get the generic reply */
+ snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, &reply,
+ sizeof(reply));
+
+ if (reply.error < 0) {
+ memcpy(msg->reply_data, &reply, sizeof(reply));
+ ret = reply.error;
+ } else if (!reply.hdr.size) {
+ /* Reply should always be >= sizeof(struct sof_ipc_reply) */
+ if (msg->reply_size)
+ dev_err(sdev->dev,
+ "empty reply received, expected %zu bytes\n",
+ msg->reply_size);
+ else
+ dev_err(sdev->dev, "empty reply received\n");
+
+ ret = -EINVAL;
+ } else if (msg->reply_size > 0) {
+ if (reply.hdr.size == msg->reply_size) {
+ ret = 0;
+ } else if (reply.hdr.size < msg->reply_size) {
+ dev_dbg(sdev->dev,
+ "reply size (%u) is less than expected (%zu)\n",
+ reply.hdr.size, msg->reply_size);
+
+ msg->reply_size = reply.hdr.size;
+ ret = 0;
+ } else {
+ dev_err(sdev->dev,
+ "reply size (%u) exceeds the buffer size (%zu)\n",
+ reply.hdr.size, msg->reply_size);
+ ret = -EINVAL;
+ }
+
+ /* get the full message if reply.hdr.size <= msg->reply_size */
+ if (!ret)
+ snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset,
+ msg->reply_data, msg->reply_size);
+ }
+
+ msg->reply_error = ret;
+}
+EXPORT_SYMBOL(snd_sof_ipc_get_reply);
+
/* handle reply message from DSP */
void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
{
@@ -460,7 +536,7 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
if (err < 0)
sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED);
else
- sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
+ sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK);
/* wake up firmware loader */
wake_up(&sdev->boot_wait);
@@ -547,7 +623,8 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
if (spcm->pcm.compress)
snd_sof_compr_fragment_elapsed(stream->cstream);
- else if (!stream->substream->runtime->no_period_wakeup)
+ else if (stream->substream->runtime &&
+ !stream->substream->runtime->no_period_wakeup)
/* only inform ALSA for period_wakeup mode */
snd_sof_pcm_period_elapsed(stream->substream);
}
@@ -645,11 +722,6 @@ static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type,
sparams->src = (u8 *)src->chanv;
sparams->dst = (u8 *)dst->chanv;
break;
- case SOF_CTRL_TYPE_VALUE_COMP_GET:
- case SOF_CTRL_TYPE_VALUE_COMP_SET:
- sparams->src = (u8 *)src->compv;
- sparams->dst = (u8 *)dst->compv;
- break;
case SOF_CTRL_TYPE_DATA_GET:
case SOF_CTRL_TYPE_DATA_SET:
sparams->src = (u8 *)src->data->data;
@@ -669,7 +741,7 @@ static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type,
static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
struct sof_ipc_ctrl_data *cdata,
struct sof_ipc_ctrl_data_params *sparams,
- bool send)
+ bool set)
{
struct sof_ipc_ctrl_data *partdata;
size_t send_bytes;
@@ -684,7 +756,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
if (!partdata)
return -ENOMEM;
- if (send)
+ if (set)
err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata,
sparams);
else
@@ -713,7 +785,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
msg_bytes -= send_bytes;
partdata->elems_remaining = msg_bytes;
- if (send)
+ if (set)
memcpy(sparams->dst, sparams->src + offset, send_bytes);
err = sof_ipc_tx_message_unlocked(sdev->ipc,
@@ -725,7 +797,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
if (err < 0)
break;
- if (!send)
+ if (!set)
memcpy(sparams->dst + offset, sparams->src, send_bytes);
offset += pl_size;
@@ -740,11 +812,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
/*
* IPC get()/set() for kcontrols.
*/
-int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
- u32 ipc_cmd,
- enum sof_ipc_ctrl_type ctrl_type,
- enum sof_ipc_ctrl_cmd ctrl_cmd,
- bool send)
+int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set)
{
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
@@ -752,9 +820,11 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
struct sof_ipc_ctrl_data_params sparams;
+ enum sof_ipc_ctrl_type ctrl_type;
struct snd_sof_widget *swidget;
bool widget_found = false;
size_t send_bytes;
+ u32 ipc_cmd;
int err;
list_for_each_entry(swidget, &sdev->widget_list, list) {
@@ -782,7 +852,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
/* write/read value header via mmaped region */
send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) *
cdata->num_elems;
- if (send)
+ if (set)
err = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM,
scontrol->readback_offset,
cdata->chanv, send_bytes);
@@ -794,12 +864,25 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
if (err)
dev_err_once(sdev->dev, "error: %s TYPE_IRAM failed\n",
- send ? "write to" : "read from");
+ set ? "write to" : "read from");
return err;
}
+ /*
+ * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the
+ * direction
+ * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently
+ * for ctrl_type
+ */
+ if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
+ ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA;
+ ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET;
+ } else {
+ ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE;
+ ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET;
+ }
+
cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
- cdata->cmd = ctrl_cmd;
cdata->type = ctrl_type;
cdata->comp_id = scontrol->comp_id;
cdata->msg_index = 0;
@@ -813,13 +896,6 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
sparams.elems = scontrol->num_channels;
break;
- case SOF_CTRL_TYPE_VALUE_COMP_GET:
- case SOF_CTRL_TYPE_VALUE_COMP_SET:
- sparams.msg_bytes = scontrol->num_channels *
- sizeof(struct sof_ipc_ctrl_value_comp);
- sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
- sparams.elems = scontrol->num_channels;
- break;
case SOF_CTRL_TYPE_DATA_GET:
case SOF_CTRL_TYPE_DATA_SET:
sparams.msg_bytes = cdata->data->size;
@@ -858,7 +934,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
return -EINVAL;
}
- err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, send);
+ err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, set);
if (err < 0)
dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n",