blob: 023701d4f2fbac1e15bcafea757d63b9c68f3e26 [file] [log] [blame]
From d6c5925b4c467f5c45029f98145f00b16b0c1557 Mon Sep 17 00:00:00 2001
From: V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Date: Fri, 1 Jul 2022 12:43:29 +0530
Subject: [PATCH] CHROMIUM: ASOC: SOF: amd : Implementation of sof host stream
pointer callback function
This patch adds pointer callback implementation for acp pcm driver.
BUG=b:236819380
TEST=Tested on skyrim
Change-Id: I97e52b608e7a9a39746733869d9bd0579faee7bb
Signed-off-by: V sujith kumar Reddy <vsujithkumar.reddy@amd.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3735265
Reviewed-by: Yu-Hsuan Hsu <yuhsuan@chromium.org>
Tested-by: Yu-Hsuan Hsu <yuhsuan@chromium.org>
Commit-Queue: Yu-Hsuan Hsu <yuhsuan@chromium.org>
---
sound/soc/sof/amd/acp-common.c | 1 +
sound/soc/sof/amd/acp-dsp-offset.h | 18 ++++++
sound/soc/sof/amd/acp-pcm.c | 95 ++++++++++++++++++++++++++++++
sound/soc/sof/amd/acp.h | 14 +++++
4 files changed, 128 insertions(+)
diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c
index bd6c1b198736c031b1454e49206653c6bd5603e6..8ce4c89569338d1b483c7ee18c73f55aed7d605b 100644
--- a/sound/soc/sof/amd/acp-common.c
+++ b/sound/soc/sof/amd/acp-common.c
@@ -187,6 +187,7 @@ struct snd_sof_dsp_ops sof_acp_common_ops = {
.pcm_open = acp_pcm_open,
.pcm_close = acp_pcm_close,
.pcm_hw_params = acp_pcm_hw_params,
+ .pcm_pointer = acp_pcm_pointer,
.hw_info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index 920155dee819b508c21116034ec3b45e8d56240e..f13ec6b5b14885e016b10d6e0f975e77d9d349f2 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -89,4 +89,22 @@
/* Cache window registers */
#define ACP_DSP0_CACHE_OFFSET0 0x0420
#define ACP_DSP0_CACHE_SIZE0 0x0424
+
+#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x2018
+#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x201C
+#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x203C
+#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x2040
+
+#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x2060
+#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x2064
+#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x2084
+#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x2088
+
+#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x3AA8
+#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x3AAC
+#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x3ACC
+#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x3AD0
+
+#define ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH 0x2C18
+#define ACP_WOV_RX_LINEARPOSITIONCNTR_LOW 0x2C1C
#endif
diff --git a/sound/soc/sof/amd/acp-pcm.c b/sound/soc/sof/amd/acp-pcm.c
index 727c3a784a204f105c185c704b23c7c95933c9a2..abedb037bb9c36ee40a078b0613c7006b3f14314 100644
--- a/sound/soc/sof/amd/acp-pcm.c
+++ b/sound/soc/sof/amd/acp-pcm.c
@@ -15,6 +15,7 @@
#include "../ops.h"
#include "acp.h"
#include "acp-dsp-offset.h"
+#include "../sof-audio.h"
int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -84,3 +85,97 @@ int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
return acp_dsp_stream_put(sdev, stream);
}
EXPORT_SYMBOL_NS(acp_pcm_close, SND_SOC_SOF_AMD_COMMON);
+
+static const struct acp_pcm_table pcm_dev[] = {
+ {I2S_BT, "I2SBT"},
+ {I2S_SP, "I2SSP"},
+ {PDM_DMIC, "DMIC"},
+ {I2S_HS, "I2SHS"},
+};
+
+static enum acp_pcm_types get_id_from_list(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pcm_dev); i++) {
+ if (!strcmp(name, pcm_dev[i].pcm_name))
+ return pcm_dev[i].pcm_index;
+ }
+
+ return PCM_NONE;
+}
+
+static u64 acp_get_byte_count(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
+ enum acp_pcm_types pcm_id)
+{
+ u64 bytescount, low = 0, high = 0;
+ u32 reg1 = 0, reg2 = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (pcm_id) {
+ case I2S_BT:
+ reg1 = ACP_BT_TX_LINEARPOSITIONCNTR_HIGH;
+ reg2 = ACP_BT_TX_LINEARPOSITIONCNTR_LOW;
+ break;
+ case I2S_SP:
+ reg1 = ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH;
+ reg2 = ACP_I2S_TX_LINEARPOSITIONCNTR_LOW;
+ break;
+ case I2S_HS:
+ reg1 = ACP_HS_TX_LINEARPOSITIONCNTR_HIGH;
+ reg2 = ACP_HS_TX_LINEARPOSITIONCNTR_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (pcm_id) {
+ case I2S_BT:
+ reg1 = ACP_BT_RX_LINEARPOSITIONCNTR_HIGH;
+ reg2 = ACP_BT_RX_LINEARPOSITIONCNTR_LOW;
+ break;
+ case I2S_SP:
+ reg1 = ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH;
+ reg2 = ACP_I2S_RX_LINEARPOSITIONCNTR_LOW;
+ break;
+ case I2S_HS:
+ reg1 = ACP_HS_RX_LINEARPOSITIONCNTR_HIGH;
+ reg2 = ACP_HS_RX_LINEARPOSITIONCNTR_LOW;
+ break;
+ case PDM_DMIC:
+ reg1 = ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH;
+ reg2 = ACP_WOV_RX_LINEARPOSITIONCNTR_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ high = snd_sof_dsp_read(sdev, ACP_DSP_BAR, reg1);
+ low = snd_sof_dsp_read(sdev, ACP_DSP_BAR, reg2);
+
+ bytescount = (high << 32) | low;
+ return bytescount;
+}
+
+snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_component *scomp = sdev->component;
+ enum acp_pcm_types pcm_id = PCM_NONE;
+ struct snd_sof_pcm *spcm;
+ u32 pos, buffersize;
+ u64 bytescount;
+
+ spcm = snd_sof_find_spcm_dai(scomp, rtd);
+ pcm_id = get_id_from_list(spcm->pcm.pcm_name);
+
+ bytescount = acp_get_byte_count(sdev, substream, pcm_id);
+ if (bytescount < 0)
+ return -EINVAL;
+ buffersize = frames_to_bytes(substream->runtime, substream->runtime->buffer_size);
+ pos = do_div(bytescount, buffersize);
+
+ return bytes_to_frames(substream->runtime, pos);
+}
+EXPORT_SYMBOL_NS(acp_pcm_pointer, SND_SOC_SOF_AMD_COMMON);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 39165ebf684b68e6f9a37a46b12d1b4e59dfd1c7..55d1975b5bb1e3b4ebced19de7fdcbcd44cb4c2e 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -185,6 +185,19 @@ struct acp_dev_data {
struct pci_dev *smn_dev;
};
+enum acp_pcm_types {
+ I2S_BT = 0,
+ I2S_SP,
+ PDM_DMIC,
+ I2S_HS,
+ PCM_NONE,
+};
+
+struct acp_pcm_table {
+ u8 pcm_index;
+ char *pcm_name;
+};
+
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
void memcpy_from_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *dst, size_t bytes);
@@ -238,6 +251,7 @@ int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_sof_platform_stream_params *platform_params);
+snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream);
extern struct snd_sof_dsp_ops sof_acp_common_ops;
--
2.38.3