Lines Matching +full:dsp +full:- +full:ctrl
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
17 #include "sof-priv.h"
18 #include "sof-audio.h"
209 struct snd_sof_dev *sdev = ipc->sdev; in tx_wait_done()
210 struct sof_ipc_cmd_hdr *hdr = msg->msg_data; in tx_wait_done()
213 /* wait for DSP IPC completion */ in tx_wait_done()
214 ret = wait_event_timeout(msg->waitq, msg->ipc_complete, in tx_wait_done()
215 msecs_to_jiffies(sdev->ipc_timeout)); in tx_wait_done()
218 dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", in tx_wait_done()
219 hdr->cmd, hdr->size); in tx_wait_done()
220 snd_sof_handle_fw_exception(ipc->sdev); in tx_wait_done()
221 ret = -ETIMEDOUT; in tx_wait_done()
223 ret = msg->reply_error; in tx_wait_done()
225 dev_err(sdev->dev, "error: ipc error for 0x%x size %zu\n", in tx_wait_done()
226 hdr->cmd, msg->reply_size); in tx_wait_done()
228 ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); in tx_wait_done()
229 if (msg->reply_size) in tx_wait_done()
230 /* copy the data returned from DSP */ in tx_wait_done()
231 memcpy(reply_data, msg->reply_data, in tx_wait_done()
232 msg->reply_size); in tx_wait_done()
239 /* send IPC message from host to DSP */
244 struct snd_sof_dev *sdev = ipc->sdev; in sof_ipc_tx_message_unlocked()
248 if (ipc->disable_ipc_tx) in sof_ipc_tx_message_unlocked()
249 return -ENODEV; in sof_ipc_tx_message_unlocked()
252 * The spin-lock is also still needed to protect message objects against in sof_ipc_tx_message_unlocked()
255 spin_lock_irq(&sdev->ipc_lock); in sof_ipc_tx_message_unlocked()
258 msg = &ipc->msg; in sof_ipc_tx_message_unlocked()
260 msg->header = header; in sof_ipc_tx_message_unlocked()
261 msg->msg_size = msg_bytes; in sof_ipc_tx_message_unlocked()
262 msg->reply_size = reply_bytes; in sof_ipc_tx_message_unlocked()
263 msg->reply_error = 0; in sof_ipc_tx_message_unlocked()
267 memcpy(msg->msg_data, msg_data, msg_bytes); in sof_ipc_tx_message_unlocked()
269 sdev->msg = msg; in sof_ipc_tx_message_unlocked()
274 msg->ipc_complete = false; in sof_ipc_tx_message_unlocked()
276 spin_unlock_irq(&sdev->ipc_lock); in sof_ipc_tx_message_unlocked()
279 dev_err_ratelimited(sdev->dev, in sof_ipc_tx_message_unlocked()
285 ipc_log_header(sdev->dev, "ipc tx", msg->header); in sof_ipc_tx_message_unlocked()
294 /* send IPC message from host to DSP */
304 /* ensure the DSP is in D0 before sending a new IPC */ in sof_ipc_tx_message()
305 ret = snd_sof_dsp_set_power_state(ipc->sdev, &target_state); in sof_ipc_tx_message()
307 dev_err(ipc->sdev->dev, "error: resuming DSP %d\n", ret); in sof_ipc_tx_message()
317 * send IPC message from host to DSP without modifying the DSP state.
318 * This will be used for IPC's that can be handled by the DSP
319 * even in a low-power D0 substate.
329 return -ENOBUFS; in sof_ipc_tx_message_no_pm()
332 mutex_lock(&ipc->tx_mutex); in sof_ipc_tx_message_no_pm()
337 mutex_unlock(&ipc->tx_mutex); in sof_ipc_tx_message_no_pm()
343 /* handle reply message from DSP */
346 struct snd_sof_ipc_msg *msg = &sdev->ipc->msg; in snd_sof_ipc_reply()
348 if (msg->ipc_complete) { in snd_sof_ipc_reply()
349 dev_dbg(sdev->dev, in snd_sof_ipc_reply()
356 msg->ipc_complete = true; in snd_sof_ipc_reply()
357 wake_up(&msg->waitq); in snd_sof_ipc_reply()
361 /* DSP firmware has sent host a message */
370 ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); in snd_sof_ipc_msgs_rx()
378 dev_err(sdev->dev, "error: ipc reply unknown\n"); in snd_sof_ipc_msgs_rx()
382 if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) { in snd_sof_ipc_msgs_rx()
383 err = sof_ops(sdev)->fw_ready(sdev, cmd); in snd_sof_ipc_msgs_rx()
385 sdev->fw_state = SOF_FW_BOOT_READY_FAILED; in snd_sof_ipc_msgs_rx()
387 sdev->fw_state = SOF_FW_BOOT_COMPLETE; in snd_sof_ipc_msgs_rx()
390 wake_up(&sdev->boot_wait); in snd_sof_ipc_msgs_rx()
406 dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd); in snd_sof_ipc_msgs_rx()
410 ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); in snd_sof_ipc_msgs_rx()
429 dev_err(sdev->dev, "error: unhandled trace message %x\n", in ipc_trace_message()
441 struct snd_soc_component *scomp = sdev->component; in ipc_period_elapsed()
449 dev_err(sdev->dev, in ipc_period_elapsed()
455 stream = &spcm->stream[direction]; in ipc_period_elapsed()
456 snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); in ipc_period_elapsed()
458 dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", in ipc_period_elapsed()
461 memcpy(&stream->posn, &posn, sizeof(posn)); in ipc_period_elapsed()
464 if (!stream->substream->runtime->no_period_wakeup) in ipc_period_elapsed()
465 snd_sof_pcm_period_elapsed(stream->substream); in ipc_period_elapsed()
468 /* DSP notifies host of an XRUN within FW */
471 struct snd_soc_component *scomp = sdev->component; in ipc_xrun()
479 dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n", in ipc_xrun()
484 stream = &spcm->stream[direction]; in ipc_xrun()
485 snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); in ipc_xrun()
487 dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", in ipc_xrun()
491 /* stop PCM on XRUN - used for pipeline debug */ in ipc_xrun()
492 memcpy(&stream->posn, &posn, sizeof(posn)); in ipc_xrun()
493 snd_pcm_stop_xrun(stream->substream); in ipc_xrun()
497 /* stream notifications from DSP FW */
512 dev_err(sdev->dev, "error: unhandled stream message %x\n", in ipc_stream_message()
518 /* get stream position IPC - use faster MMIO method if available on platform */
530 stream.comp_id = spcm->stream[direction].comp_id; in snd_sof_ipc_stream_posn()
532 /* send IPC to the DSP */ in snd_sof_ipc_stream_posn()
533 err = sof_ipc_tx_message(sdev->ipc, in snd_sof_ipc_stream_posn()
537 dev_err(sdev->dev, "error: failed to get stream %d position\n", in snd_sof_ipc_stream_posn()
554 sparams->src = (u8 *)src->chanv; in sof_get_ctrl_copy_params()
555 sparams->dst = (u8 *)dst->chanv; in sof_get_ctrl_copy_params()
559 sparams->src = (u8 *)src->compv; in sof_get_ctrl_copy_params()
560 sparams->dst = (u8 *)dst->compv; in sof_get_ctrl_copy_params()
564 sparams->src = (u8 *)src->data->data; in sof_get_ctrl_copy_params()
565 sparams->dst = (u8 *)dst->data->data; in sof_get_ctrl_copy_params()
568 return -EINVAL; in sof_get_ctrl_copy_params()
572 sparams->pl_size = SOF_IPC_MSG_MAX_SIZE - sparams->hdr_bytes; in sof_get_ctrl_copy_params()
573 sparams->num_msg = DIV_ROUND_UP(sparams->msg_bytes, sparams->pl_size); in sof_get_ctrl_copy_params()
594 return -ENOMEM; in sof_set_get_large_ctrl_data()
597 err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata, in sof_set_get_large_ctrl_data()
600 err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata, in sof_set_get_large_ctrl_data()
607 msg_bytes = sparams->msg_bytes; in sof_set_get_large_ctrl_data()
608 pl_size = sparams->pl_size; in sof_set_get_large_ctrl_data()
611 memcpy(partdata, cdata, sparams->hdr_bytes); in sof_set_get_large_ctrl_data()
614 mutex_lock(&sdev->ipc->tx_mutex); in sof_set_get_large_ctrl_data()
617 for (i = 0; i < sparams->num_msg; i++) { in sof_set_get_large_ctrl_data()
619 partdata->num_elems = send_bytes; in sof_set_get_large_ctrl_data()
620 partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes; in sof_set_get_large_ctrl_data()
621 partdata->msg_index = i; in sof_set_get_large_ctrl_data()
622 msg_bytes -= send_bytes; in sof_set_get_large_ctrl_data()
623 partdata->elems_remaining = msg_bytes; in sof_set_get_large_ctrl_data()
626 memcpy(sparams->dst, sparams->src + offset, send_bytes); in sof_set_get_large_ctrl_data()
628 err = sof_ipc_tx_message_unlocked(sdev->ipc, in sof_set_get_large_ctrl_data()
629 partdata->rhdr.hdr.cmd, in sof_set_get_large_ctrl_data()
631 partdata->rhdr.hdr.size, in sof_set_get_large_ctrl_data()
633 partdata->rhdr.hdr.size); in sof_set_get_large_ctrl_data()
638 memcpy(sparams->dst + offset, sparams->src, send_bytes); in sof_set_get_large_ctrl_data()
643 mutex_unlock(&sdev->ipc->tx_mutex); in sof_set_get_large_ctrl_data()
658 struct snd_soc_component *scomp = scontrol->scomp; in snd_sof_ipc_set_get_comp_data()
659 struct sof_ipc_ctrl_data *cdata = scontrol->control_data; in snd_sof_ipc_set_get_comp_data()
661 struct sof_ipc_fw_ready *ready = &sdev->fw_ready; in snd_sof_ipc_set_get_comp_data()
662 struct sof_ipc_fw_version *v = &ready->version; in snd_sof_ipc_set_get_comp_data()
668 if (scontrol->readback_offset != 0) { in snd_sof_ipc_set_get_comp_data()
671 cdata->num_elems; in snd_sof_ipc_set_get_comp_data()
673 snd_sof_dsp_block_write(sdev, sdev->mmio_bar, in snd_sof_ipc_set_get_comp_data()
674 scontrol->readback_offset, in snd_sof_ipc_set_get_comp_data()
675 cdata->chanv, send_bytes); in snd_sof_ipc_set_get_comp_data()
678 snd_sof_dsp_block_read(sdev, sdev->mmio_bar, in snd_sof_ipc_set_get_comp_data()
679 scontrol->readback_offset, in snd_sof_ipc_set_get_comp_data()
680 cdata->chanv, send_bytes); in snd_sof_ipc_set_get_comp_data()
684 cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; in snd_sof_ipc_set_get_comp_data()
685 cdata->cmd = ctrl_cmd; in snd_sof_ipc_set_get_comp_data()
686 cdata->type = ctrl_type; in snd_sof_ipc_set_get_comp_data()
687 cdata->comp_id = scontrol->comp_id; in snd_sof_ipc_set_get_comp_data()
688 cdata->msg_index = 0; in snd_sof_ipc_set_get_comp_data()
691 switch (cdata->type) { in snd_sof_ipc_set_get_comp_data()
694 sparams.msg_bytes = scontrol->num_channels * in snd_sof_ipc_set_get_comp_data()
697 sparams.elems = scontrol->num_channels; in snd_sof_ipc_set_get_comp_data()
701 sparams.msg_bytes = scontrol->num_channels * in snd_sof_ipc_set_get_comp_data()
704 sparams.elems = scontrol->num_channels; in snd_sof_ipc_set_get_comp_data()
708 sparams.msg_bytes = cdata->data->size; in snd_sof_ipc_set_get_comp_data()
711 sparams.elems = cdata->data->size; in snd_sof_ipc_set_get_comp_data()
714 return -EINVAL; in snd_sof_ipc_set_get_comp_data()
717 cdata->rhdr.hdr.size = sparams.msg_bytes + sparams.hdr_bytes; in snd_sof_ipc_set_get_comp_data()
718 cdata->num_elems = sparams.elems; in snd_sof_ipc_set_get_comp_data()
719 cdata->elems_remaining = 0; in snd_sof_ipc_set_get_comp_data()
722 if (cdata->rhdr.hdr.size <= SOF_IPC_MSG_MAX_SIZE) { in snd_sof_ipc_set_get_comp_data()
723 err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata, in snd_sof_ipc_set_get_comp_data()
724 cdata->rhdr.hdr.size, cdata, in snd_sof_ipc_set_get_comp_data()
725 cdata->rhdr.hdr.size); in snd_sof_ipc_set_get_comp_data()
728 dev_err(sdev->dev, "error: set/get ctrl ipc comp %d\n", in snd_sof_ipc_set_get_comp_data()
729 cdata->comp_id); in snd_sof_ipc_set_get_comp_data()
735 dev_dbg(sdev->dev, "large ipc size %u, control size %u\n", in snd_sof_ipc_set_get_comp_data()
736 cdata->rhdr.hdr.size, scontrol->size); in snd_sof_ipc_set_get_comp_data()
739 if (v->abi_version < SOF_ABI_VER(3, 3, 0)) { in snd_sof_ipc_set_get_comp_data()
740 dev_err(sdev->dev, "error: incompatible FW ABI version\n"); in snd_sof_ipc_set_get_comp_data()
741 return -EINVAL; in snd_sof_ipc_set_get_comp_data()
747 dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n", in snd_sof_ipc_set_get_comp_data()
748 cdata->comp_id); in snd_sof_ipc_set_get_comp_data()
762 sdev->dsp_box.offset = dspbox; in snd_sof_dsp_mailbox_init()
763 sdev->dsp_box.size = dspbox_size; in snd_sof_dsp_mailbox_init()
764 sdev->host_box.offset = hostbox; in snd_sof_dsp_mailbox_init()
765 sdev->host_box.size = hostbox_size; in snd_sof_dsp_mailbox_init()
772 struct sof_ipc_fw_ready *ready = &sdev->fw_ready; in snd_sof_ipc_valid()
773 struct sof_ipc_fw_version *v = &ready->version; in snd_sof_ipc_valid()
775 dev_info(sdev->dev, in snd_sof_ipc_valid()
776 "Firmware info: version %d:%d:%d-%s\n", v->major, v->minor, in snd_sof_ipc_valid()
777 v->micro, v->tag); in snd_sof_ipc_valid()
778 dev_info(sdev->dev, in snd_sof_ipc_valid()
780 SOF_ABI_VERSION_MAJOR(v->abi_version), in snd_sof_ipc_valid()
781 SOF_ABI_VERSION_MINOR(v->abi_version), in snd_sof_ipc_valid()
782 SOF_ABI_VERSION_PATCH(v->abi_version), in snd_sof_ipc_valid()
785 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) { in snd_sof_ipc_valid()
786 dev_err(sdev->dev, "error: incompatible FW ABI version\n"); in snd_sof_ipc_valid()
787 return -EINVAL; in snd_sof_ipc_valid()
790 if (v->abi_version > SOF_ABI_VERSION) { in snd_sof_ipc_valid()
792 dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n"); in snd_sof_ipc_valid()
794 dev_err(sdev->dev, "error: FW ABI is more recent than kernel\n"); in snd_sof_ipc_valid()
795 return -EINVAL; in snd_sof_ipc_valid()
799 if (ready->flags & SOF_IPC_INFO_BUILD) { in snd_sof_ipc_valid()
800 dev_info(sdev->dev, in snd_sof_ipc_valid()
801 "Firmware debug build %d on %s-%s - options:\n" in snd_sof_ipc_valid()
805 v->build, v->date, v->time, in snd_sof_ipc_valid()
806 (ready->flags & SOF_IPC_INFO_GDB) ? in snd_sof_ipc_valid()
808 (ready->flags & SOF_IPC_INFO_LOCKS) ? in snd_sof_ipc_valid()
810 (ready->flags & SOF_IPC_INFO_LOCKSV) ? in snd_sof_ipc_valid()
815 memcpy(&sdev->fw_version, v, sizeof(*v)); in snd_sof_ipc_valid()
826 ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); in snd_sof_ipc_init()
830 mutex_init(&ipc->tx_mutex); in snd_sof_ipc_init()
831 ipc->sdev = sdev; in snd_sof_ipc_init()
832 msg = &ipc->msg; in snd_sof_ipc_init()
835 msg->ipc_complete = true; in snd_sof_ipc_init()
837 /* pre-allocate message data */ in snd_sof_ipc_init()
838 msg->msg_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, in snd_sof_ipc_init()
840 if (!msg->msg_data) in snd_sof_ipc_init()
843 msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, in snd_sof_ipc_init()
845 if (!msg->reply_data) in snd_sof_ipc_init()
848 init_waitqueue_head(&msg->waitq); in snd_sof_ipc_init()
856 struct snd_sof_ipc *ipc = sdev->ipc; in snd_sof_ipc_free()
862 mutex_lock(&ipc->tx_mutex); in snd_sof_ipc_free()
863 ipc->disable_ipc_tx = true; in snd_sof_ipc_free()
864 mutex_unlock(&ipc->tx_mutex); in snd_sof_ipc_free()