diff options
Diffstat (limited to 'sound/soc/sof/amd')
-rw-r--r-- | sound/soc/sof/amd/Kconfig | 13 | ||||
-rw-r--r-- | sound/soc/sof/amd/Makefile | 3 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp-common.c | 4 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp-dsp-offset.h | 3 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp-ipc.c | 49 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp-loader.c | 47 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp-probes.c | 147 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp.c | 194 | ||||
-rw-r--r-- | sound/soc/sof/amd/acp.h | 44 | ||||
-rw-r--r-- | sound/soc/sof/amd/pci-rmb.c | 2 | ||||
-rw-r--r-- | sound/soc/sof/amd/pci-rn.c | 2 | ||||
-rw-r--r-- | sound/soc/sof/amd/pci-vangogh.c | 16 | ||||
-rw-r--r-- | sound/soc/sof/amd/vangogh.c | 19 |
13 files changed, 446 insertions, 97 deletions
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 9b7fd8a23034..f2faa08f0c0e 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -2,7 +2,7 @@ # This file is provided under a dual BSD/GPLv2 license. When using or # redistributing this file, you may do so under either license. # -# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. config SND_SOC_SOF_AMD_TOPLEVEL tristate "SOF support for AMD audio DSPs" @@ -21,6 +21,7 @@ config SND_SOC_SOF_AMD_COMMON select SND_SOC_SOF_PCI_DEV select SND_AMD_ACP_CONFIG select SND_SOC_SOF_XTENSA + select SND_SOC_SOF_ACP_PROBES select SND_SOC_ACPI if ACPI help This option is not user-selectable but automatically handled by @@ -38,7 +39,8 @@ config SND_SOC_SOF_AMD_VANGOGH depends on SND_SOC_SOF_PCI select SND_SOC_SOF_AMD_COMMON help - Select this option for SOF support on AMD Vangogh platform + Select this option for SOF support + on AMD Vangogh platform. Say Y if you want to enable SOF on Vangogh. If unsure select "N". @@ -51,4 +53,11 @@ config SND_SOC_SOF_AMD_REMBRANDT Say Y if you want to enable SOF on Rembrandt. If unsure select "N". +config SND_SOC_SOF_ACP_PROBES + tristate + select SND_SOC_SOF_DEBUG_PROBES + help + This option is not user-selectable but automatically handled by + 'select' statements at a higher level + endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index f32106d28c45..f3b375e67a6f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -2,9 +2,10 @@ # This file is provided under a dual BSD/GPLv2 license. When using or # redistributing this file, you may do so under either license. # -# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o +snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) = acp-probes.o snd-sof-amd-renoir-objs := pci-rn.o renoir.o snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o snd-sof-amd-vangogh-objs := pci-vangogh.o vangogh.o diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index df36b411a12e..3a0c7688dcfe 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -196,6 +196,10 @@ struct snd_sof_dsp_ops sof_acp_common_ops = { .dbg_dump = amd_sof_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, .dsp_arch_ops = &sof_xtensa_arch_ops, + + /* probe client device registation */ + .register_ipc_clients = acp_probes_register, + .unregister_ipc_clients = acp_probes_unregister, }; EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 879e95627d35..a913f1cc4c80 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -3,7 +3,7 @@ * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * - * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> */ @@ -91,7 +91,6 @@ #define ACP_SHA_PSP_ACK 0x1C74 #define ACP_SCRATCH_REG_0 0x10000 -#define ACP5X_DSP_FUSION_RUNSTALL 0x0414 #define ACP6X_DSP_FUSION_RUNSTALL 0x0644 /* Cache window registers */ diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 1f614eff2a68..93dd14f06d1d 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -130,6 +130,13 @@ static void acp_dsp_ipc_get_reply(struct snd_sof_dev *sdev) memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { + /* + * To support an IPC tx_message with a + * reply_size set to zero. + */ + if (!msg->reply_size) + goto out; + /* reply correct size ? */ if (reply.hdr.size != msg->reply_size && !(reply.hdr.cmd & SOF_IPC_GLB_PROBE)) { @@ -148,6 +155,8 @@ out: irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + struct acp_dev_data *adata = sdev->pdata->hw_pdata; unsigned int dsp_msg_write = sdev->debug_box.offset + offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); unsigned int dsp_ack_write = sdev->debug_box.offset + @@ -161,6 +170,8 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, sdev->dsp_box.offset + sizeof(status), true); + status = 0; + acp_mailbox_write(sdev, sdev->dsp_box.offset, &status, sizeof(status)); return IRQ_HANDLED; } snd_sof_ipc_msgs_rx(sdev); @@ -177,22 +188,46 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); if (dsp_ack) { - spin_lock_irq(&sdev->ipc_lock); /* handle immediate reply from DSP core */ acp_dsp_ipc_get_reply(sdev); snd_sof_ipc_reply(sdev, 0); /* set the done bit */ acp_dsp_ipc_dsp_done(sdev); - spin_unlock_irq(&sdev->ipc_lock); ipc_irq = true; } acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32)); if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, sdev->dsp_oops_offset, true); + status = 0; + acp_mailbox_write(sdev, sdev->debug_box.offset, &status, sizeof(status)); return IRQ_HANDLED; } + if (desc->probe_reg_offset) { + u32 val; + u32 posn; + + /* Probe register consists of two parts + * (0-30) bit has cumulative position value + * 31 bit is a synchronization flag between DSP and CPU + * for the position update + */ + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->probe_reg_offset); + if (val & PROBE_STATUS_BIT) { + posn = val & ~PROBE_STATUS_BIT; + if (adata->probe_stream) { + /* Probe related posn value is of 31 bits limited to 2GB + * once wrapped DSP won't send posn interrupt. + */ + adata->probe_stream->cstream_posn = posn; + snd_compr_fragment_elapsed(adata->probe_stream->cstream); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->probe_reg_offset, posn); + ipc_irq = true; + } + } + } + if (!ipc_irq) dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); @@ -209,7 +244,12 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sp acp_mailbox_read(sdev, offset, p, sz); } else { struct snd_pcm_substream *substream = sps->substream; - struct acp_dsp_stream *stream = substream->runtime->private_data; + struct acp_dsp_stream *stream; + + if (!substream || !substream->runtime) + return -ESTRPIPE; + + stream = substream->runtime->private_data; if (!stream) return -ESTRPIPE; @@ -222,9 +262,10 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sp EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON); int acp_set_stream_data_offset(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, size_t posn_offset) { + struct snd_pcm_substream *substream = sps->substream; struct acp_dsp_stream *stream = substream->runtime->private_data; /* check for unaligned offset or overflow */ diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 8c1003ca8860..a427673cfb03 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. // // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> @@ -160,7 +160,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) adata = sdev->pdata->hw_pdata; if (adata->signed_fw_image) - size_fw = adata->fw_bin_size - FW_SIGNATURE; + size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; else size_fw = adata->fw_bin_size; @@ -207,6 +207,7 @@ EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON); int acp_sof_dsp_run(struct snd_sof_dev *sdev) { + struct acp_dev_data *adata = sdev->pdata->hw_pdata; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); int val; @@ -215,7 +216,7 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val); /* Some platforms won't support fusion DSP,keep offset zero for no support */ - if (desc->fusion_dsp_offset) { + if (desc->fusion_dsp_offset && adata->enable_fw_debug) { snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN); val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset); dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val); @@ -224,53 +225,33 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON); -int acp_sof_load_firmware(struct snd_sof_dev *sdev) +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; struct acp_dev_data *adata = plat_data->hw_pdata; - const char *fw_filename; - const char *fw_datafilename; int ret; - adata->signed_fw_image = true; - fw_filename = kasprintf(GFP_KERNEL, "%s/%s", - plat_data->fw_filename_prefix, - "sof-vangogh-code.bin"); - - ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev); - + ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev); if (ret < 0) { - dev_err(sdev->dev, - "error: sof firmware file is missing, you might need to\n"); - dev_err(sdev->dev, - "download it from https://github.com/thesofproject/sof-bin/\n"); - + dev_err(sdev->dev, "sof signed firmware code bin is missing\n"); + return ret; } else { - dev_dbg(sdev->dev, "request_firmware %s successful\n", - fw_filename); + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin); } ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0, (void *)sdev->basefw.fw->data, sdev->basefw.fw->size); - fw_datafilename = kasprintf(GFP_KERNEL, "%s/%s", - plat_data->fw_filename_prefix, - "sof-vangogh-data.bin"); - - ret = request_firmware(&adata->fw_dbin, fw_datafilename, sdev->dev); - + ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev); if (ret < 0) { - dev_err(sdev->dev, - "error: sof firmware file is missing, you might need to\n"); - dev_err(sdev->dev, - "download it from https://github.com/thesofproject/sof-bin/\n"); + dev_err(sdev->dev, "sof signed firmware data bin is missing\n"); + return ret; } else { - dev_dbg(sdev->dev, "request_firmware %s successful\n", - fw_filename); + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin); } ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, (void *)adata->fw_dbin->data, adata->fw_dbin->size); return ret; } -EXPORT_SYMBOL_NS(acp_sof_load_firmware, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c new file mode 100644 index 000000000000..778cf1a8b610 --- /dev/null +++ b/sound/soc/sof/amd/acp-probes.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. +// +// Authors: V Sujith Kumar Reddy <Vsujithkumar.Reddy@amd.com> + +/* + * Probe interface for generic AMD audio ACP DSP block + */ + +#include <linux/module.h> +#include <sound/soc.h> +#include "../sof-priv.h" +#include "../sof-client-probes.h" +#include "../sof-client.h" +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +static int acp_probes_compr_startup(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai, u32 *stream_id) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + + adata = sdev->pdata->hw_pdata; + stream = acp_dsp_stream_get(sdev, 0); + if (!stream) + return -ENODEV; + + stream->cstream = cstream; + cstream->runtime->private_data = stream; + + adata->probe_stream = stream; + *stream_id = stream->stream_tag; + + return 0; +} + +static int acp_probes_compr_shutdown(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream = cstream->runtime->private_data; + struct acp_dev_data *adata; + int ret; + + ret = acp_dsp_stream_put(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "Failed to release probe compress stream\n"); + return ret; + } + + adata = sdev->pdata->hw_pdata; + stream->cstream = NULL; + cstream->runtime->private_data = NULL; + adata->probe_stream = NULL; + + return 0; +} + +static int acp_probes_compr_set_params(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream = cstream->runtime->private_data; + unsigned int buf_offset, index; + u32 size; + int ret; + + stream->dmab = cstream->runtime->dma_buffer_p; + stream->num_pages = PFN_UP(cstream->runtime->dma_bytes); + size = cstream->runtime->buffer_size; + + ret = acp_dsp_stream_config(sdev, stream); + if (ret < 0) { + acp_dsp_stream_put(sdev, stream); + return ret; + } + + /* write buffer size of stream in scratch memory */ + + buf_offset = sdev->debug_box.offset + + offsetof(struct scratch_reg_conf, buf_size); + index = stream->stream_tag - 1; + buf_offset = buf_offset + index * 4; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size); + + return 0; +} + +static int acp_probes_compr_trigger(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + int cmd, struct snd_soc_dai *dai) +{ + /* Nothing to do here, as it is a mandatory callback just defined */ + return 0; +} + +static int acp_probes_compr_pointer(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai) +{ + struct acp_dsp_stream *stream = cstream->runtime->private_data; + struct snd_soc_pcm_stream *pstream; + + pstream = &dai->driver->capture; + tstamp->copied_total = stream->cstream_posn; + tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates); + + return 0; +} + +/* SOF client implementation */ +static const struct sof_probes_host_ops acp_probes_ops = { + .startup = acp_probes_compr_startup, + .shutdown = acp_probes_compr_shutdown, + .set_params = acp_probes_compr_set_params, + .trigger = acp_probes_compr_trigger, + .pointer = acp_probes_compr_pointer, +}; + +int acp_probes_register(struct snd_sof_dev *sdev) +{ + return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops, + sizeof(acp_probes_ops)); +} +EXPORT_SYMBOL_NS(acp_probes_register, SND_SOC_SOF_AMD_COMMON); + +void acp_probes_unregister(struct snd_sof_dev *sdev) +{ + sof_client_dev_unregister(sdev, "acp-probes", 0); +} +EXPORT_SYMBOL_NS(acp_probes_unregister, SND_SOC_SOF_AMD_COMMON); + +MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); + diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 8563a60235b6..5638af72a3fe 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. // // Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com> // Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> @@ -16,10 +16,35 @@ #include <linux/module.h> #include <linux/pci.h> +#include <linux/fs.h> +#include <asm/segment.h> +#include <asm/uaccess.h> +#include <linux/buffer_head.h> + #include "../ops.h" #include "acp.h" #include "acp-dsp-offset.h" +#define SECURED_FIRMWARE 1 + +static bool enable_fw_debug; +module_param(enable_fw_debug, bool, 0444); +MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); + +const struct dmi_system_id acp_sof_quirk_table[] = { + { + /* Valve Jupiter device */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), + }, + .driver_data = (void *)SECURED_FIRMWARE, + }, + {} +}; +EXPORT_SYMBOL_GPL(acp_sof_quirk_table); + static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) { pci_write_config_dword(dev, 0x60, smn_addr); @@ -217,6 +242,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, unsigned int image_length) { struct snd_sof_dev *sdev = adata->dev; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int tx_count, fw_qualifier, val; int ret; @@ -238,7 +264,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); + if (adata->signed_fw_image) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length); @@ -252,9 +280,12 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, return ret; } - ret = psp_send_cmd(adata, MBOX_ACP_SHA_DMA_COMMAND); - if (ret) - return ret; + /* psp_send_cmd only required for renoir platform (rev - 3) */ + if (desc->rev == 3) { + ret = psp_send_cmd(adata, MBOX_ACP_SHA_DMA_COMMAND); + if (ret) + return ret; + } ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER, fw_qualifier, fw_qualifier & DSP_FW_RUN_ENABLE, @@ -319,15 +350,9 @@ static irqreturn_t acp_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); - unsigned int val, count = ACP_HW_SEM_RETRY_COUNT; - - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); - if (val & ACP_SHA_STAT) { - /* Clear SHA interrupt raised by PSP */ - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, val); - return IRQ_HANDLED; - } + unsigned int count = ACP_HW_SEM_RETRY_COUNT; + spin_lock_irq(&sdev->ipc_lock); while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) { /* Wait until acquired HW Semaphore lock or timeout */ count--; @@ -340,6 +365,7 @@ static irqreturn_t acp_irq_thread(int irq, void *context) sof_ops(sdev)->irq_thread(irq, sdev); /* Unlock or Release HW Semaphore */ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0); + spin_unlock_irq(&sdev->ipc_lock); return IRQ_HANDLED; }; @@ -352,9 +378,9 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) unsigned int val; val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); - if (val) { - val |= ACP_DSP_TO_HOST_IRQ; - snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val); + if (val & ACP_DSP_TO_HOST_IRQ) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, + ACP_DSP_TO_HOST_IRQ); return IRQ_WAKE_THREAD; } @@ -409,6 +435,9 @@ static int acp_reset(struct snd_sof_dev *sdev) dev_err(sdev->dev, "timeout in releasing reset\n"); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); + if (desc->ext_intr_enb) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01); + return ret; } @@ -446,7 +475,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_resume(struct snd_sof_dev *sdev) { - const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); int ret; ret = acp_init(sdev); @@ -455,51 +483,106 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev) return ret; } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK); - ret = acp_memory_init(sdev); return ret; } EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); -static void acp_set_window_offset(struct snd_sof_dev *sdev, - struct pci_dev *pci) +static int acp_get_oem_strings(struct snd_sof_dev *sdev) { - switch (pci->revision) { - case 0x50: - sdev->dsp_box.offset = 0; - sdev->dsp_box.size = BOX_SIZE_1024; - - sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size; - sdev->host_box.size = BOX_SIZE_1024; + const struct dmi_device *dev = NULL; + struct file *fp; + struct acp_oem_str *oem_strings; + int line = 0; + int Max_left_ch_id = 0x01000006; + int Max_right_ch_id = 0x02000006; + int Max_amb_temp_id = 0x03000008; + char *Max_amb_temp_val; + char str[5][30]; + static unsigned int dsm_calib_data[18]; + + dsm_calib_data[0] = 0x03; + dsm_calib_data[1] = 0x044; + dsm_calib_data[2] = 0x464f53; // hdr magic id + dsm_calib_data[3] = 0x1; // IPC type - 0 for IPC3 and 1 for IPC4 + dsm_calib_data[4] = 0x20; // Size of payload + dsm_calib_data[5] = 0x3017000; // ABI version + /* reserved[4] */ + dsm_calib_data[6] = 0x0; + dsm_calib_data[7] = 0x0; + dsm_calib_data[8] = 0x0; + dsm_calib_data[9] = 0x0; + dsm_calib_data[10] = 0x18; // data blob size + dsm_calib_data[11] = 0x18; + + oem_strings = devm_kcalloc(sdev->dev, MAX_OEM_STRINGS, sizeof(oem_strings), GFP_KERNEL); + if (!oem_strings) + return -ENOMEM; - sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; - sdev->debug_box.size = BOX_SIZE_1024; + pr_err("DEBUG: %s ########### Trying to OEM strings \n", __func__); + + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { + if (sscanf(dev->name, "%s", str[line]) <= 5) { + switch (line) { + case 0: + oem_strings[MAX_OEM_STRINGS - line].name = str[line]; + break; + case 1: + oem_strings[MAX_OEM_STRINGS - line].name = str[line]; + break; + case 2: + oem_strings[MAX_OEM_STRINGS - line].name = str[line]; + break; + case 3: + oem_strings[MAX_OEM_STRINGS - line].name = str[line]; + break; + case 4: + oem_strings[MAX_OEM_STRINGS - line].name = str[line]; + break; + default: + break; + } + ++line; + } + } + for (int i=1; i<=MAX_OEM_STRINGS; i++) + pr_err("DEBUG: oem_str[%d][%s] \n", i, oem_strings[i]); - sdev->dsp_oops_offset = sdev->debug_box.offset + sdev->debug_box.size; + dsm_calib_data[12] = Max_left_ch_id; + dsm_calib_data[14] = Max_right_ch_id; + dsm_calib_data[16] = Max_amb_temp_id; - sdev->stream_box.offset = sdev->dsp_oops_offset + BOX_SIZE_1024; - sdev->stream_box.size = BOX_SIZE_1024; - break; - default: - sdev->dsp_box.offset = 0; - sdev->dsp_box.size = BOX_SIZE_512; + sscanf(&oem_strings[1].name[13], "%x", &dsm_calib_data[13]); + // dsm_calib_data[13] = CHANGE_ENDIANNESS(dsm_calib_data[13]); - sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size; - sdev->host_box.size = BOX_SIZE_512; + Max_amb_temp_val = devm_kasprintf(sdev->dev, GFP_KERNEL,"%0.8s", &oem_strings[3].name[2]); + sscanf(Max_amb_temp_val, "%x", &dsm_calib_data[17]); + // dsm_calib_data[17] = CHANGE_ENDIANNESS(dsm_calib_data[17]); - sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; - sdev->debug_box.size = BOX_SIZE_1024; + sscanf(&oem_strings[3].name[13], "%x", &dsm_calib_data[15]); + // dsm_calib_data[15] = CHANGE_ENDIANNESS(dsm_calib_data[15]); - break; + fp = filp_open("/lib/firmware/amd/sof/dsmcalib.bin", O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp)) { + pr_err("DEBUG: failed to create file \n"); + return -1; } + dev_err(sdev->dev,"DEBUG: /lib/firmware/amd/sof/dsmcalib.bin created \n"); + + kernel_write(fp, &dsm_calib_data, 19 * sizeof(int), 0); + filp_close(fp, NULL); + + return 0; } + int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; struct acp_dev_data *adata; const struct sof_amd_acp_desc *chip; + const struct dmi_system_id *dmi_id; unsigned int addr; int ret; @@ -551,7 +634,32 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) if (ret < 0) goto free_ipc_irq; - acp_set_window_offset(sdev, pci); + sdev->dsp_box.offset = 0; + sdev->dsp_box.size = BOX_SIZE_512; + + sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size; + sdev->host_box.size = BOX_SIZE_512; + + sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; + sdev->debug_box.size = BOX_SIZE_1024; + + adata->signed_fw_image = false; + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) { + adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->signed_fw_image = dmi_id->driver_data; + + dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, + adata->fw_data_bin); + + acp_get_oem_strings(sdev); + } + adata->enable_fw_debug = enable_fw_debug; acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 20d8d576a81b..8abf64017c7f 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -3,7 +3,7 @@ * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * - * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> */ @@ -11,9 +11,15 @@ #ifndef __SOF_AMD_ACP_H #define __SOF_AMD_ACP_H +#include <linux/dmi.h> + #include "../sof-priv.h" #include "../sof-audio.h" +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/uaccess.h> + #define ACP_MAX_STREAM 8 #define ACP_DSP_BAR 0 @@ -58,6 +64,7 @@ #define ACP_DSP_TO_HOST_IRQ 0x04 #define ACP_RN_PCI_ID 0x01 +#define ACP_VANGOGH_PCI_ID 0x50 #define ACP_RMB_PCI_ID 0x6F #define HOST_BRIDGE_CZN 0x1630 @@ -80,8 +87,16 @@ #define AMD_STACK_DUMP_SIZE 32 #define SRAM1_SIZE 0x13A000 +#define PROBE_STATUS_BIT BIT(31) + +#define ACP_FIRMWARE_SIGNATURE 0x100 + +#define MAX_OEM_STRINGS 0x05 +#define CHANGE_ENDIANNESS(val) ((((uint32_t)(val) & 0xff000000) >> 24) \ + | (((uint32_t)(val) & 0x00ff0000) >> 8) \ + | (((uint32_t)(val) & 0x0000ff00) << 8) \ + | (((uint32_t)(val) & 0x000000ff) << 24)) -#define FW_SIGNATURE 0x100 enum clock_source { ACP_CLOCK_96M = 0, @@ -161,18 +176,23 @@ struct acp_dsp_stream { int active; unsigned int reg_offset; size_t posn_offset; + struct snd_compr_stream *cstream; + u64 cstream_posn; }; struct sof_amd_acp_desc { unsigned int rev; + const char *name; unsigned int host_bridge_id; u32 pgfsm_base; + u32 ext_intr_enb; u32 ext_intr_stat; u32 dsp_intr_base; u32 sram_pte_offset; u32 hw_semaphore_offset; u32 acp_clkmux_sel; u32 fusion_dsp_offset; + u32 probe_reg_offset; }; /* Common device data struct for ACP devices */ @@ -183,16 +203,24 @@ struct acp_dev_data { struct platform_device *dmic_dev; unsigned int fw_bin_size; unsigned int fw_data_bin_size; + const char *fw_code_bin; + const char *fw_data_bin; u32 fw_bin_page_count; dma_addr_t sha_dma_addr; u8 *bin_buf; dma_addr_t dma_addr; u8 *data_buf; + bool signed_fw_image; struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; struct pci_dev *smn_dev; - bool signed_fw_image; + struct acp_dsp_stream *probe_stream; + bool enable_fw_debug; +}; + +struct acp_oem_str { + const char *name; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -212,7 +240,7 @@ int amd_sof_acp_remove(struct snd_sof_dev *sdev); /* DSP Loader callbacks */ int acp_sof_dsp_run(struct snd_sof_dev *sdev); int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev); -int acp_sof_load_firmware(struct snd_sof_dev *sdev); +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev); int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type); /* Block IO callbacks */ @@ -226,7 +254,7 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context); int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, void *p, size_t sz); int acp_set_stream_data_offset(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, + struct snd_sof_pcm_stream *sps, size_t posn_offset); int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); @@ -283,4 +311,10 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata return desc->chip_info; } + +int acp_probes_register(struct snd_sof_dev *sdev); +void acp_probes_unregister(struct snd_sof_dev *sdev); + +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; +extern const struct dmi_system_id acp_sof_quirk_table[]; #endif diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c index 58b3092425f1..9935e457b467 100644 --- a/sound/soc/sof/amd/pci-rmb.c +++ b/sound/soc/sof/amd/pci-rmb.c @@ -25,6 +25,7 @@ #define ACP6x_REG_START 0x1240000 #define ACP6x_REG_END 0x125C000 +#define ACP6X_FUTURE_REG_ACLK_0 0x1854 static const struct sof_amd_acp_desc rembrandt_chip_info = { .rev = 6, @@ -36,6 +37,7 @@ static const struct sof_amd_acp_desc rembrandt_chip_info = { .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0, .acp_clkmux_sel = ACP6X_CLKMUX_SEL, .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL, + .probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0, }; static const struct sof_dev_desc rembrandt_desc = { diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 7409e21ce5aa..c72d5d8aff8e 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -25,6 +25,7 @@ #define ACP3x_REG_START 0x1240000 #define ACP3x_REG_END 0x125C000 +#define ACP3X_FUTURE_REG_ACLK_0 0x1860 static const struct sof_amd_acp_desc renoir_chip_info = { .rev = 3, @@ -35,6 +36,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = { .sram_pte_offset = ACP3X_SRAM_PTE_OFFSET, .hw_semaphore_offset = ACP3X_AXI2DAGB_SEM_0, .acp_clkmux_sel = ACP3X_CLKMUX_SEL, + .probe_reg_offset = ACP3X_FUTURE_REG_ACLK_0, }; static const struct sof_dev_desc renoir_desc = { diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c index b6fd8c535cf3..d8be42fbcb6d 100644 --- a/sound/soc/sof/amd/pci-vangogh.c +++ b/sound/soc/sof/amd/pci-vangogh.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2022 Advanced Micro Devices, Inc. All rights reserved. +// Copyright(c) 2023 Advanced Micro Devices, Inc. All rights reserved. // // Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com> @@ -23,11 +23,11 @@ #include "acp.h" #include "acp-dsp-offset.h" -#define ACP5x_REG_START 0x1240000 -#define ACP5x_REG_END 0x125C000 +#define ACP5X_FUTURE_REG_ACLK_0 0x1864 static const struct sof_amd_acp_desc vangogh_chip_info = { .rev = 5, + .name = "vangogh", .host_bridge_id = HOST_BRIDGE_VGH, .pgfsm_base = ACP5X_PGFSM_BASE, .ext_intr_stat = ACP5X_EXT_INTR_STAT, @@ -35,11 +35,11 @@ static const struct sof_amd_acp_desc vangogh_chip_info = { .sram_pte_offset = ACP5X_SRAM_PTE_OFFSET, .hw_semaphore_offset = ACP5X_AXI2DAGB_SEM_0, .acp_clkmux_sel = ACP5X_CLKMUX_SEL, - .fusion_dsp_offset = ACP5X_DSP_FUSION_RUNSTALL, + .probe_reg_offset = ACP5X_FUTURE_REG_ACLK_0, }; static const struct sof_dev_desc vangogh_desc = { - .machines = snd_soc_acpi_amd_vgh_sof_machines, + .machines = snd_soc_acpi_amd_vangogh_sof_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -65,6 +65,9 @@ static int acp_pci_vgh_probe(struct pci_dev *pci, const struct pci_device_id *pc { unsigned int flag; + if (pci->revision != ACP_VANGOGH_PCI_ID) + return -ENODEV; + flag = snd_amd_acp_find_config(pci); if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) return -ENODEV; @@ -91,6 +94,9 @@ static struct pci_driver snd_sof_pci_amd_vgh_driver = { .id_table = vgh_pci_ids, .probe = acp_pci_vgh_probe, .remove = acp_pci_vgh_remove, + .driver = { + .pm = &sof_pci_pm, + }, }; module_pci_driver(snd_sof_pci_amd_vgh_driver); diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c index 8c5dd990df6c..de15d21aa6d9 100644 --- a/sound/soc/sof/amd/vangogh.c +++ b/sound/soc/sof/amd/vangogh.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2022 Advanced Micro Devices, Inc. +// Copyright(c) 2023 Advanced Micro Devices, Inc. // // Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com> @@ -123,6 +123,16 @@ static struct snd_soc_dai_driver vangogh_sof_dai[] = { .rate_min = 8000, .rate_max = 96000, }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS-Virtual controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, }, }; @@ -132,12 +142,17 @@ EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); int sof_vangogh_ops_init(struct snd_sof_dev *sdev) { + const struct dmi_system_id *dmi_id; + /* common defaults */ memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); sof_vangogh_ops.drv = vangogh_sof_dai; sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); - sof_vangogh_ops.load_firmware = acp_sof_load_firmware; + + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) + sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; return 0; } |