269 lines · c
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 or4// redistributing this file, you may do so under either license.5//6// Copyright(c) 2022 Advanced Micro Devices, Inc.7//8// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>9// V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>10 11/* ACP-specific Common code */12 13#include "../sof-priv.h"14#include "../sof-audio.h"15#include "../ops.h"16#include "acp.h"17#include "acp-dsp-offset.h"18#include <sound/sof/xtensa.h>19 20/**21 * amd_sof_ipc_dump() - This function is called when IPC tx times out.22 * @sdev: SOF device.23 */24void amd_sof_ipc_dump(struct snd_sof_dev *sdev)25{26 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);27 u32 base = desc->dsp_intr_base;28 u32 dsp_msg_write = sdev->debug_box.offset +29 offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);30 u32 dsp_ack_write = sdev->debug_box.offset +31 offsetof(struct scratch_ipc_conf, sof_dsp_ack_write);32 u32 host_msg_write = sdev->debug_box.offset +33 offsetof(struct scratch_ipc_conf, sof_host_msg_write);34 u32 host_ack_write = sdev->debug_box.offset +35 offsetof(struct scratch_ipc_conf, sof_host_ack_write);36 u32 dsp_msg, dsp_ack, host_msg, host_ack, irq_stat;37 38 dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write);39 dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);40 host_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_msg_write);41 host_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_ack_write);42 irq_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);43 44 dev_err(sdev->dev,45 "dsp_msg = %#x dsp_ack = %#x host_msg = %#x host_ack = %#x irq_stat = %#x\n",46 dsp_msg, dsp_ack, host_msg, host_ack, irq_stat);47}48 49/**50 * amd_get_registers() - This function is called in case of DSP oops51 * in order to gather information about the registers, filename and52 * linenumber and stack.53 * @sdev: SOF device.54 * @xoops: Stores information about registers.55 * @panic_info: Stores information about filename and line number.56 * @stack: Stores the stack dump.57 * @stack_words: Size of the stack dump.58 */59static void amd_get_registers(struct snd_sof_dev *sdev,60 struct sof_ipc_dsp_oops_xtensa *xoops,61 struct sof_ipc_panic_info *panic_info,62 u32 *stack, size_t stack_words)63{64 u32 offset = sdev->dsp_oops_offset;65 66 /* first read registers */67 acp_mailbox_read(sdev, offset, xoops, sizeof(*xoops));68 69 /* then get panic info */70 if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {71 dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",72 xoops->arch_hdr.totalsize);73 return;74 }75 76 offset += xoops->arch_hdr.totalsize;77 acp_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));78 79 /* then get the stack */80 offset += sizeof(*panic_info);81 acp_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32));82}83 84/**85 * amd_sof_dump() - This function is called when a panic message is86 * received from the firmware.87 * @sdev: SOF device.88 * @flags: parameter not used but required by ops prototype89 */90void amd_sof_dump(struct snd_sof_dev *sdev, u32 flags)91{92 struct sof_ipc_dsp_oops_xtensa xoops;93 struct sof_ipc_panic_info panic_info;94 u32 stack[AMD_STACK_DUMP_SIZE];95 u32 status;96 97 /* Get information about the panic status from the debug box area.98 * Compute the trace point based on the status.99 */100 if (sdev->dsp_oops_offset > sdev->debug_box.offset) {101 acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32));102 } else {103 /* Read DSP Panic status from dsp_box.104 * As window information for exception box offset and size is not available105 * before FW_READY106 */107 acp_mailbox_read(sdev, sdev->dsp_box.offset, &status, sizeof(u32));108 sdev->dsp_oops_offset = sdev->dsp_box.offset + sizeof(status);109 }110 111 /* Get information about the registers, the filename and line112 * number and the stack.113 */114 amd_get_registers(sdev, &xoops, &panic_info, stack, AMD_STACK_DUMP_SIZE);115 116 /* Print the information to the console */117 sof_print_oops_and_stack(sdev, KERN_ERR, status, status, &xoops,118 &panic_info, stack, AMD_STACK_DUMP_SIZE);119}120 121#if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE)122static int amd_sof_sdw_get_slave_info(struct snd_sof_dev *sdev)123{124 struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;125 126 return sdw_amd_get_slave_info(acp_data->sdw);127}128 129static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *sdev)130{131 struct snd_soc_acpi_mach *mach;132 const struct snd_soc_acpi_link_adr *link;133 struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;134 int ret, i;135 136 if (acp_data->info.count) {137 ret = amd_sof_sdw_get_slave_info(sdev);138 if (ret) {139 dev_info(sdev->dev, "failed to read slave information\n");140 return NULL;141 }142 for (mach = sdev->pdata->desc->alt_machines; mach; mach++) {143 if (!mach->links)144 break;145 link = mach->links;146 for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {147 if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,148 acp_data->sdw->ids,149 acp_data->sdw->num_slaves))150 break;151 }152 if (i == acp_data->info.count || !link->num_adr)153 break;154 }155 if (mach && mach->link_mask) {156 mach->mach_params.subsystem_rev = acp_data->pci_rev;157 mach->mach_params.links = mach->links;158 mach->mach_params.link_mask = mach->link_mask;159 mach->mach_params.platform = dev_name(sdev->dev);160 return mach;161 }162 }163 dev_info(sdev->dev, "No SoundWire machine driver found\n");164 return NULL;165}166 167#else168static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *sdev)169{170 return NULL;171}172#endif173 174struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)175{176 struct snd_sof_pdata *sof_pdata = sdev->pdata;177 struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;178 const struct sof_dev_desc *desc = sof_pdata->desc;179 struct snd_soc_acpi_mach *mach = NULL;180 181 if (desc->machines)182 mach = snd_soc_acpi_find_machine(desc->machines);183 if (!mach) {184 mach = amd_sof_sdw_machine_select(sdev);185 if (!mach) {186 dev_warn(sdev->dev, "No matching ASoC machine driver found\n");187 return NULL;188 }189 }190 191 mach->mach_params.subsystem_rev = acp_data->pci_rev;192 sof_pdata->tplg_filename = mach->sof_tplg_filename;193 sof_pdata->fw_filename = mach->fw_filename;194 195 return mach;196}197 198/* AMD Common DSP ops */199const struct snd_sof_dsp_ops sof_acp_common_ops = {200 /* probe and remove */201 .probe = amd_sof_acp_probe,202 .remove = amd_sof_acp_remove,203 204 /* Register IO */205 .write = sof_io_write,206 .read = sof_io_read,207 208 /* Block IO */209 .block_read = acp_dsp_block_read,210 .block_write = acp_dsp_block_write,211 212 /*Firmware loading */213 .load_firmware = snd_sof_load_firmware_memcpy,214 .pre_fw_run = acp_dsp_pre_fw_run,215 .get_bar_index = acp_get_bar_index,216 217 /* DSP core boot */218 .run = acp_sof_dsp_run,219 220 /*IPC */221 .send_msg = acp_sof_ipc_send_msg,222 .ipc_msg_data = acp_sof_ipc_msg_data,223 .set_stream_data_offset = acp_set_stream_data_offset,224 .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset,225 .get_window_offset = acp_sof_ipc_get_window_offset,226 .irq_thread = acp_sof_ipc_irq_thread,227 228 /* stream callbacks */229 .pcm_open = acp_pcm_open,230 .pcm_close = acp_pcm_close,231 .pcm_hw_params = acp_pcm_hw_params,232 .pcm_pointer = acp_pcm_pointer,233 234 .hw_info = SNDRV_PCM_INFO_MMAP |235 SNDRV_PCM_INFO_MMAP_VALID |236 SNDRV_PCM_INFO_INTERLEAVED |237 SNDRV_PCM_INFO_PAUSE |238 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,239 240 /* Machine driver callbacks */241 .machine_select = amd_sof_machine_select,242 .machine_register = sof_machine_register,243 .machine_unregister = sof_machine_unregister,244 245 /* Trace Logger */246 .trace_init = acp_sof_trace_init,247 .trace_release = acp_sof_trace_release,248 249 /* PM */250 .suspend = amd_sof_acp_suspend,251 .resume = amd_sof_acp_resume,252 253 .ipc_dump = amd_sof_ipc_dump,254 .dbg_dump = amd_sof_dump,255 .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,256 .dsp_arch_ops = &sof_xtensa_arch_ops,257 258 /* probe client device registation */259 .register_ipc_clients = acp_probes_register,260 .unregister_ipc_clients = acp_probes_unregister,261};262EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON);263 264MODULE_LICENSE("Dual BSD/GPL");265MODULE_DESCRIPTION("ACP SOF COMMON Driver");266MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);267MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);268MODULE_IMPORT_NS(SOUNDWIRE_AMD_INIT);269