ASoC: SOF: amd: Add Probe functionality support for amd platforms.
authorV sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Thu, 13 Jul 2023 12:57:07 +0000 (18:27 +0530)
committerMark Brown <broonie@kernel.org>
Mon, 17 Jul 2023 05:15:35 +0000 (06:15 +0100)
This patch consist of probe client device registration,stream tag
and dma channel configuration for SOF firmware.

Signed-off-by: V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Link: https://lore.kernel.org/r/20230713125709.418851-2-vsujithkumar.reddy@amd.corp-partner.google.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/amd/Kconfig
sound/soc/sof/amd/Makefile
sound/soc/sof/amd/acp-common.c
sound/soc/sof/amd/acp-ipc.c
sound/soc/sof/amd/acp-probes.c [new file with mode: 0644]
sound/soc/sof/amd/acp.h

index 1cb92d6..7dbc8df 100644 (file)
@@ -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
@@ -42,4 +43,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
index 5626d13..ef9f7df 100644 (file)
@@ -5,6 +5,7 @@
 # Copyright(c) 2021 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
 
index df36b41..3a0c768 100644 (file)
@@ -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);
 
index 8a0fc63..81a2c09 100644 (file)
@@ -155,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 +
@@ -200,6 +202,30 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
                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");
 
diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c
new file mode 100644 (file)
index 0000000..778cf1a
--- /dev/null
@@ -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);
+
index c3659db..72fa0af 100644 (file)
@@ -77,6 +77,7 @@
 #define AMD_STACK_DUMP_SIZE                    32
 
 #define SRAM1_SIZE                             0x13A000
+#define PROBE_STATUS_BIT                       BIT(31)
 
 enum clock_source {
        ACP_CLOCK_96M = 0,
@@ -156,6 +157,8 @@ 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 {
@@ -168,6 +171,7 @@ struct sof_amd_acp_desc {
        u32 hw_semaphore_offset;
        u32 acp_clkmux_sel;
        u32 fusion_dsp_offset;
+       u32 probe_reg_offset;
 };
 
 /* Common device data struct for ACP devices */
@@ -186,6 +190,7 @@ struct acp_dev_data {
        struct acp_dsp_stream stream_buf[ACP_MAX_STREAM];
        struct acp_dsp_stream *dtrace_stream;
        struct pci_dev *smn_dev;
+       struct acp_dsp_stream *probe_stream;
 };
 
 void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
@@ -273,4 +278,8 @@ 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);
+
 #endif