| 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
| 2 | // |
| 3 | // This file is provided under a dual BSD/GPLv2 license. When using or |
| 4 | // redistributing this file, you may do so under either license. |
| 5 | // |
| 6 | // Copyright(c) 2022 MediaTek Inc. All rights reserved. |
| 7 | // |
| 8 | // Author: YC Hung <yc.hung@mediatek.com> |
| 9 | |
| 10 | /* |
| 11 | * Common helpers for the audio DSP on MediaTek platforms |
| 12 | */ |
| 13 | |
| 14 | #include <linux/module.h> |
| 15 | #include <sound/asound.h> |
| 16 | #include <sound/sof/xtensa.h> |
| 17 | #include "../ops.h" |
| 18 | #include "../sof-audio.h" |
| 19 | #include "adsp_helper.h" |
| 20 | #include "mtk-adsp-common.h" |
| 21 | |
| 22 | /** |
| 23 | * mtk_adsp_get_registers() - This function is called in case of DSP oops |
| 24 | * in order to gather information about the registers, filename and |
| 25 | * linenumber and stack. |
| 26 | * @sdev: SOF device |
| 27 | * @xoops: Stores information about registers. |
| 28 | * @panic_info: Stores information about filename and line number. |
| 29 | * @stack: Stores the stack dump. |
| 30 | * @stack_words: Size of the stack dump. |
| 31 | */ |
| 32 | static void mtk_adsp_get_registers(struct snd_sof_dev *sdev, |
| 33 | struct sof_ipc_dsp_oops_xtensa *xoops, |
| 34 | struct sof_ipc_panic_info *panic_info, |
| 35 | u32 *stack, size_t stack_words) |
| 36 | { |
| 37 | u32 offset = sdev->dsp_oops_offset; |
| 38 | |
| 39 | /* first read registers */ |
| 40 | sof_mailbox_read(sdev, offset, message: xoops, bytes: sizeof(*xoops)); |
| 41 | |
| 42 | /* then get panic info */ |
| 43 | if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { |
| 44 | dev_err(sdev->dev, "invalid header size 0x%x\n" , |
| 45 | xoops->arch_hdr.totalsize); |
| 46 | return; |
| 47 | } |
| 48 | offset += xoops->arch_hdr.totalsize; |
| 49 | sof_mailbox_read(sdev, offset, message: panic_info, bytes: sizeof(*panic_info)); |
| 50 | |
| 51 | /* then get the stack */ |
| 52 | offset += sizeof(*panic_info); |
| 53 | sof_mailbox_read(sdev, offset, message: stack, bytes: stack_words * sizeof(u32)); |
| 54 | } |
| 55 | |
| 56 | /** |
| 57 | * mtk_adsp_dump() - This function is called when a panic message is |
| 58 | * received from the firmware. |
| 59 | * @sdev: SOF device |
| 60 | * @flags: parameter not used but required by ops prototype |
| 61 | */ |
| 62 | void mtk_adsp_dump(struct snd_sof_dev *sdev, u32 flags) |
| 63 | { |
| 64 | char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; |
| 65 | struct sof_ipc_dsp_oops_xtensa xoops; |
| 66 | struct sof_ipc_panic_info panic_info = {}; |
| 67 | u32 stack[MTK_ADSP_STACK_DUMP_SIZE]; |
| 68 | u32 status; |
| 69 | |
| 70 | /* Get information about the panic status from the debug box area. |
| 71 | * Compute the trace point based on the status. |
| 72 | */ |
| 73 | sof_mailbox_read(sdev, offset: sdev->debug_box.offset + 0x4, message: &status, bytes: 4); |
| 74 | |
| 75 | /* Get information about the registers, the filename and line |
| 76 | * number and the stack. |
| 77 | */ |
| 78 | mtk_adsp_get_registers(sdev, xoops: &xoops, panic_info: &panic_info, stack, |
| 79 | MTK_ADSP_STACK_DUMP_SIZE); |
| 80 | |
| 81 | /* Print the information to the console */ |
| 82 | sof_print_oops_and_stack(sdev, level, panic_code: status, tracep_code: status, oops: &xoops, panic_info: &panic_info, |
| 83 | stack, MTK_ADSP_STACK_DUMP_SIZE); |
| 84 | } |
| 85 | EXPORT_SYMBOL(mtk_adsp_dump); |
| 86 | |
| 87 | /** |
| 88 | * mtk_adsp_send_msg - Send message to Audio DSP |
| 89 | * @sdev: SOF device |
| 90 | * @msg: SOF IPC Message to send |
| 91 | */ |
| 92 | int mtk_adsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) |
| 93 | { |
| 94 | struct adsp_priv *priv = sdev->pdata->hw_pdata; |
| 95 | |
| 96 | sof_mailbox_write(sdev, offset: sdev->host_box.offset, message: msg->msg_data, |
| 97 | bytes: msg->msg_size); |
| 98 | |
| 99 | return mtk_adsp_ipc_send(ipc: priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ); |
| 100 | } |
| 101 | EXPORT_SYMBOL(mtk_adsp_send_msg); |
| 102 | |
| 103 | /** |
| 104 | * mtk_adsp_handle_reply - Handle reply from the Audio DSP through Mailbox |
| 105 | * @ipc: ADSP IPC handle |
| 106 | */ |
| 107 | void mtk_adsp_handle_reply(struct mtk_adsp_ipc *ipc) |
| 108 | { |
| 109 | struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); |
| 110 | unsigned long flags; |
| 111 | |
| 112 | spin_lock_irqsave(&priv->sdev->ipc_lock, flags); |
| 113 | snd_sof_ipc_process_reply(sdev: priv->sdev, msg_id: 0); |
| 114 | spin_unlock_irqrestore(lock: &priv->sdev->ipc_lock, flags); |
| 115 | } |
| 116 | EXPORT_SYMBOL(mtk_adsp_handle_reply); |
| 117 | |
| 118 | /** |
| 119 | * mtk_adsp_handle_request - Handle request from the Audio DSP through Mailbox |
| 120 | * @ipc: ADSP IPC handle |
| 121 | */ |
| 122 | void mtk_adsp_handle_request(struct mtk_adsp_ipc *ipc) |
| 123 | { |
| 124 | struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); |
| 125 | u32 panic_code; |
| 126 | int ret; |
| 127 | |
| 128 | /* Read the message from the debug box. */ |
| 129 | sof_mailbox_read(sdev: priv->sdev, offset: priv->sdev->debug_box.offset + 4, |
| 130 | message: &panic_code, bytes: sizeof(panic_code)); |
| 131 | |
| 132 | /* Check to see if the message is a panic code 0x0dead*** */ |
| 133 | if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { |
| 134 | snd_sof_dsp_panic(sdev: priv->sdev, offset: panic_code, non_recoverable: true); |
| 135 | } else { |
| 136 | snd_sof_ipc_msgs_rx(sdev: priv->sdev); |
| 137 | |
| 138 | /* Tell DSP cmd is done */ |
| 139 | ret = mtk_adsp_ipc_send(ipc: priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP); |
| 140 | if (ret) |
| 141 | dev_err(priv->dev, "request send ipc failed" ); |
| 142 | } |
| 143 | } |
| 144 | EXPORT_SYMBOL(mtk_adsp_handle_request); |
| 145 | |
| 146 | /** |
| 147 | * mtk_adsp_get_bar_index - Map section type with BAR idx |
| 148 | * @sdev: SOF device |
| 149 | * @type: Section type as described by snd_sof_fw_blk_type |
| 150 | * |
| 151 | * MediaTek Audio DSPs have a 1:1 match between type and BAR idx |
| 152 | */ |
| 153 | int mtk_adsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) |
| 154 | { |
| 155 | return type; |
| 156 | } |
| 157 | EXPORT_SYMBOL(mtk_adsp_get_bar_index); |
| 158 | |
| 159 | /** |
| 160 | * mtk_adsp_stream_pcm_hw_params - Platform specific host stream hw params |
| 161 | * @sdev: SOF device |
| 162 | * @substream: PCM Substream |
| 163 | * @params: hw params |
| 164 | * @platform_params: Platform specific SOF stream parameters |
| 165 | */ |
| 166 | int mtk_adsp_stream_pcm_hw_params(struct snd_sof_dev *sdev, |
| 167 | struct snd_pcm_substream *substream, |
| 168 | struct snd_pcm_hw_params *params, |
| 169 | struct snd_sof_platform_stream_params *platform_params) |
| 170 | { |
| 171 | platform_params->cont_update_posn = 1; |
| 172 | return 0; |
| 173 | } |
| 174 | EXPORT_SYMBOL(mtk_adsp_stream_pcm_hw_params); |
| 175 | |
| 176 | /** |
| 177 | * mtk_adsp_stream_pcm_pointer - Get host stream pointer |
| 178 | * @sdev: SOF device |
| 179 | * @substream: PCM substream |
| 180 | */ |
| 181 | snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_sof_dev *sdev, |
| 182 | struct snd_pcm_substream *substream) |
| 183 | { |
| 184 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
| 185 | struct snd_soc_component *scomp = sdev->component; |
| 186 | struct snd_sof_pcm_stream *stream; |
| 187 | struct sof_ipc_stream_posn posn; |
| 188 | struct snd_sof_pcm *spcm; |
| 189 | snd_pcm_uframes_t pos; |
| 190 | int ret; |
| 191 | |
| 192 | spcm = snd_sof_find_spcm_dai(scomp, rtd); |
| 193 | if (!spcm) { |
| 194 | dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n" , |
| 195 | rtd->dai_link->id); |
| 196 | return 0; |
| 197 | } |
| 198 | |
| 199 | stream = &spcm->stream[substream->stream]; |
| 200 | ret = snd_sof_ipc_msg_data(sdev, sps: stream, p: &posn, sz: sizeof(posn)); |
| 201 | if (ret < 0) { |
| 202 | dev_warn(sdev->dev, "failed to read stream position: %d\n" , ret); |
| 203 | return 0; |
| 204 | } |
| 205 | |
| 206 | memcpy(&stream->posn, &posn, sizeof(posn)); |
| 207 | pos = spcm->stream[substream->stream].posn.host_posn; |
| 208 | pos = bytes_to_frames(runtime: substream->runtime, size: pos); |
| 209 | |
| 210 | return pos; |
| 211 | } |
| 212 | EXPORT_SYMBOL(mtk_adsp_stream_pcm_pointer); |
| 213 | |
| 214 | MODULE_LICENSE("Dual BSD/GPL" ); |
| 215 | MODULE_DESCRIPTION("SOF helpers for MTK ADSP platforms" ); |
| 216 | |