linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RESEND v13 00/10] Add support for audio on SC7280 based targets
@ 2022-02-14 14:58 Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 01/10] ASoC: qcom: SC7280: Update config for building codec dma drivers Srinivasa Rao Mandadapu
                   ` (9 more replies)
  0 siblings, 10 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu

This patch set is to add support for Audio over wcd codec,
digital mics, through digital codecs and without ADSP.

Changes Since V12:
    -- Fix arguments type mismatch.
Changes Since V11:
    -- Fix kernel robot issue on arguments type mismatch.
Changes Since V10:
    -- Split bulk clock voting to individual clock voting as per use case in cdc-dma driver.
    -- Add missing codec dma clocks.
    -- Update rxtx lpm buffer size.
Changes Since V9:
    -- Change individual clock voting to bulk clock voting of lpass-sc7280 platform driver.
    -- Remove redundant clocks in lpass variant structure.
    -- Add mclk for MI2S based headset path.
    -- Remove unused lpass variant structure members in lpass header.
Changes Since V8:
    -- Fix errors in sc7280 lpass cpu dt-bindings.
    -- Move to quicinc domain email id's.
Changes Since V7:
    -- Fix indentation errors.
    -- Bisect patches to avoid interdependency.
Changes Since V6:
    -- Split cdc dma regmap config macros.
    -- Add write dma reg fields for i2s path.
    -- Add helper function to distinguish rxtx and va dma ports.
    -- Optimizing clock and reg name in cpu dt-bindings.
    -- Update buffer management for cdc dma path.
    -- Remove Kconfig fields of machine driver.
Changes Since V5:
    -- Include MI2S primary node to snd_soc_dai_driver in lpass-sc7280 platform driver.
    -- Move dependency patch list to corresponding patch.
    -- Add support for missing cdc-dma ports.
    -- Change if/else conditional statements to switch cases.
    -- Add missing error handlings.
    -- Typo errors fix.
Changes Since V4:
    -- Remove unused variable in lpass-sc7280 platform driver.
Changes Since V3:
    -- Remove redundant power domain controls. As power domains can be configured from dtsi.
Changes Since V2:
    -- Split lpass sc7280 cpu driver patch and create regmap config patch.
    -- Create patches based on latest kernel tip.
    -- Add helper function to get dma control and lpaif handle.
    -- Remove unused variables.
Changes Since V1:
    -- Typo errors fix
    -- CPU driver readable/writable apis optimization.
    -- Add Missing config patch
    -- Add Common api for repeated dmactl initialization.

Srinivasa Rao Mandadapu (10):
  ASoC: qcom: SC7280: Update config for building codec dma drivers
  ASoC: qcom: Move lpass_pcm_data structure to lpass header
  ASoC: qcom: lpass: Add dma fields for codec dma lpass interface
  ASoC: qcom: Add helper function to get dma control and lpaif handle
  ASoC: qcom: Add register definition for codec rddma and wrdma
  ASoC: qcom: Add regmap config support for codec dma driver
  ASoC: qcom: Add support for codec dma driver
  ASoC: qcom: Add lpass CPU driver for codec dma control
  ASoC: dt-bindings: Add SC7280 lpass cpu bindings
  ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio

 .../devicetree/bindings/sound/qcom,lpass-cpu.yaml  |  75 ++-
 sound/soc/qcom/Kconfig                             |  11 +
 sound/soc/qcom/Makefile                            |   4 +
 sound/soc/qcom/lpass-cdc-dma.c                     | 304 ++++++++++
 sound/soc/qcom/lpass-cpu.c                         | 244 +++++++-
 sound/soc/qcom/lpass-lpaif-reg.h                   | 127 ++++-
 sound/soc/qcom/lpass-platform.c                    | 617 ++++++++++++++++++---
 sound/soc/qcom/lpass-sc7280.c                      | 447 +++++++++++++++
 sound/soc/qcom/lpass.h                             | 145 +++++
 9 files changed, 1887 insertions(+), 87 deletions(-)
 create mode 100644 sound/soc/qcom/lpass-cdc-dma.c
 create mode 100644 sound/soc/qcom/lpass-sc7280.c

-- 
2.7.4


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [RESEND v13 01/10] ASoC: qcom: SC7280: Update config for building codec dma drivers
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 02/10] ASoC: qcom: Move lpass_pcm_data structure to lpass header Srinivasa Rao Mandadapu
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add configuration for building SC7280 audio codec dma drivers.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
---
 sound/soc/qcom/Kconfig  | 11 +++++++++++
 sound/soc/qcom/Makefile |  4 ++++
 2 files changed, 15 insertions(+)

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index dd5949e..52db003 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -20,6 +20,10 @@ config SND_SOC_LPASS_PLATFORM
 	tristate
 	select REGMAP_MMIO
 
+config SND_SOC_LPASS_CDC_DMA
+	tristate
+	select REGMAP_MMIO
+
 config SND_SOC_LPASS_IPQ806X
 	tristate
 	select SND_SOC_LPASS_CPU
@@ -36,6 +40,13 @@ config SND_SOC_LPASS_SC7180
 	select SND_SOC_LPASS_PLATFORM
 	select SND_SOC_LPASS_HDMI
 
+config SND_SOC_LPASS_SC7280
+	tristate
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+	select SND_SOC_LPASS_HDMI
+	select SND_SOC_LPASS_CDC_DMA
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	depends on GPIOLIB
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 625aec6..8b7b876 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,18 +1,22 @@
 # SPDX-License-Identifier: GPL-2.0
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
+snd-soc-lpass-cdc-dma-objs := lpass-cdc-dma.o
 snd-soc-lpass-hdmi-objs := lpass-hdmi.o
 snd-soc-lpass-platform-objs := lpass-platform.o
 snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
 snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 snd-soc-lpass-sc7180-objs := lpass-sc7180.o
+snd-soc-lpass-sc7280-objs := lpass-sc7280.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
+obj-$(CONFIG_SND_SOC_LPASS_CDC_DMA) += snd-soc-lpass-cdc-dma.o
 obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
 obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
 obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o
+obj-$(CONFIG_SND_SOC_LPASS_SC7280) += snd-soc-lpass-sc7280.o
 
 # Machine
 snd-soc-storm-objs := storm.o
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 02/10] ASoC: qcom: Move lpass_pcm_data structure to lpass header
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 01/10] ASoC: qcom: SC7280: Update config for building codec dma drivers Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 03/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface Srinivasa Rao Mandadapu
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Declare lpass_pcm_data structure in lpass header file instead of
platform source file to make common use of it by other drivers

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 5 -----
 sound/soc/qcom/lpass.h          | 5 +++++
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a59e9d2..a44162c 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -18,11 +18,6 @@
 
 #define DRV_NAME "lpass-platform"
 
-struct lpass_pcm_data {
-	int dma_ch;
-	int i2s_port;
-};
-
 #define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
 
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index c0f0247..f0d21cd 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -257,6 +257,11 @@ struct lpass_variant {
 	int num_clks;
 };
 
+struct lpass_pcm_data {
+	int dma_ch;
+	int i2s_port;
+};
+
 /* register the platform driver from the CPU DAI driver */
 int asoc_qcom_lpass_platform_register(struct platform_device *);
 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 03/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 01/10] ASoC: qcom: SC7280: Update config for building codec dma drivers Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 02/10] ASoC: qcom: Move lpass_pcm_data structure to lpass header Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-15  1:05   ` Stephen Boyd
  2022-02-14 14:58 ` [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle Srinivasa Rao Mandadapu
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add lpass interface memebers to support audio path over codec dma.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index f0d21cd..7cc3763 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -20,6 +20,17 @@
 #define LPASS_MAX_MI2S_PORTS			(8)
 #define LPASS_MAX_DMA_CHANNELS			(8)
 #define LPASS_MAX_HDMI_DMA_CHANNELS		(4)
+#define LPASS_MAX_CDC_DMA_CHANNELS		(8)
+#define LPASS_MAX_VA_CDC_DMA_CHANNELS		(8)
+#define LPASS_CDC_DMA_INTF_ONE_CHANNEL		(0x01)
+#define LPASS_CDC_DMA_INTF_TWO_CHANNEL		(0x03)
+#define LPASS_CDC_DMA_INTF_FOUR_CHANNEL		(0x0F)
+#define LPASS_CDC_DMA_INTF_SIX_CHANNEL		(0x3F)
+#define LPASS_CDC_DMA_INTF_EIGHT_CHANNEL	(0xFF)
+
+#define LPASS_MAX_CDC_CLKS			(9)
+#define LPASS_ACTIVE_PDS			(4)
+#define LPASS_PROXY_PDS			(8)
 
 #define QCOM_REGMAP_FIELD_ALLOC(d, m, f, mf)    \
 	do { \
@@ -51,6 +62,12 @@ struct lpaif_dmactl {
 	struct regmap_field *burst8;
 	struct regmap_field *burst16;
 	struct regmap_field *dynburst;
+	struct regmap_field *codec_enable;
+	struct regmap_field *codec_pack;
+	struct regmap_field *codec_intf;
+	struct regmap_field *codec_fs_sel;
+	struct regmap_field *codec_channel;
+	struct regmap_field *codec_fs_delay;
 };
 
 /* Both the CPU DAI and platform drivers will access this data */
@@ -65,6 +82,8 @@ struct lpass_data {
 	/* MI2S bit clock (derived from system clock by a divider */
 	struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
 
+	struct clk *cdc_dma_clks[LPASS_MAX_CDC_CLKS];
+
 	/* MI2S SD lines to use for playback/capture */
 	unsigned int mi2s_playback_sd_mode[LPASS_MAX_MI2S_PORTS];
 	unsigned int mi2s_capture_sd_mode[LPASS_MAX_MI2S_PORTS];
@@ -73,38 +92,61 @@ struct lpass_data {
 	bool mi2s_was_prepared[LPASS_MAX_MI2S_PORTS];
 
 	int hdmi_port_enable;
+	int codec_dma_enable;
 
 	/* low-power audio interface (LPAIF) registers */
 	void __iomem *lpaif;
 	void __iomem *hdmiif;
+	void __iomem *rxtx_lpaif;
+	void __iomem *va_lpaif;
+
+	u32 rxtx_cdc_dma_lpm_buf;
+	u32 va_cdc_dma_lpm_buf;
 
 	/* regmap backed by the low-power audio interface (LPAIF) registers */
 	struct regmap *lpaif_map;
 	struct regmap *hdmiif_map;
+	struct regmap *rxtx_lpaif_map;
+	struct regmap *va_lpaif_map;
 
 	/* interrupts from the low-power audio interface (LPAIF) */
 	int lpaif_irq;
 	int hdmiif_irq;
+	int rxtxif_irq;
+	int vaif_irq;
+
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
 
 	/* bit map to keep track of static channel allocations */
 	unsigned long dma_ch_bit_map;
 	unsigned long hdmi_dma_ch_bit_map;
+	unsigned long rxtx_dma_ch_bit_map;
+	unsigned long va_dma_ch_bit_map;
 
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
 	struct snd_pcm_substream *hdmi_substream[LPASS_MAX_HDMI_DMA_CHANNELS];
+	struct snd_pcm_substream *rxtx_substream[LPASS_MAX_CDC_DMA_CHANNELS];
+	struct snd_pcm_substream *va_substream[LPASS_MAX_CDC_DMA_CHANNELS];
 
 	/* SOC specific clock list */
 	struct clk_bulk_data *clks;
 	int num_clks;
+	struct clk_bulk_data *cdc_clks;
+	int cdc_num_clks;
 
 	/* Regmap fields of I2SCTL & DMACTL registers bitfields */
 	struct lpaif_i2sctl *i2sctl;
 	struct lpaif_dmactl *rd_dmactl;
 	struct lpaif_dmactl *wr_dmactl;
 	struct lpaif_dmactl *hdmi_rd_dmactl;
+
+	/* Regmap fields of CODEC DMA CTRL registers*/
+	struct lpaif_dmactl *rxtx_rd_dmactl;
+	struct lpaif_dmactl *rxtx_wr_dmactl;
+	struct lpaif_dmactl *va_wr_dmactl;
+
 	/* Regmap fields of HDMI_CTRL registers*/
 	struct regmap_field *hdmitx_legacy_en;
 	struct regmap_field *hdmitx_parity_calc_en;
@@ -131,6 +173,24 @@ struct lpass_variant {
 	u32	wrdma_reg_base;
 	u32	wrdma_reg_stride;
 	u32	wrdma_channels;
+	u32	rxtx_irq_reg_base;
+	u32	rxtx_irq_reg_stride;
+	u32	rxtx_irq_ports;
+	u32	rxtx_rdma_reg_base;
+	u32	rxtx_rdma_reg_stride;
+	u32	rxtx_rdma_channels;
+	u32	rxtx_wrdma_reg_base;
+	u32	rxtx_wrdma_reg_stride;
+	u32	rxtx_wrdma_channels;
+	u32	va_irq_reg_base;
+	u32	va_irq_reg_stride;
+	u32	va_irq_ports;
+	u32	va_rdma_reg_base;
+	u32	va_rdma_reg_stride;
+	u32	va_rdma_channels;
+	u32	va_wrdma_reg_base;
+	u32	va_wrdma_reg_stride;
+	u32	va_wrdma_channels;
 	u32	i2sctrl_reg_base;
 	u32	i2sctrl_reg_stride;
 	u32	i2s_ports;
@@ -234,12 +294,66 @@ struct lpass_variant {
 	struct reg_field wrdma_enable;
 	struct reg_field wrdma_dyncclk;
 
+	/*CDC RXTX RD_DMA */
+	struct reg_field rxtx_rdma_intf;
+	struct reg_field rxtx_rdma_bursten;
+	struct reg_field rxtx_rdma_wpscnt;
+	struct reg_field rxtx_rdma_fifowm;
+	struct reg_field rxtx_rdma_enable;
+	struct reg_field rxtx_rdma_dyncclk;
+	struct reg_field rxtx_rdma_burst8;
+	struct reg_field rxtx_rdma_burst16;
+	struct reg_field rxtx_rdma_dynburst;
+	struct reg_field rxtx_rdma_codec_enable;
+	struct reg_field rxtx_rdma_codec_pack;
+	struct reg_field rxtx_rdma_codec_intf;
+	struct reg_field rxtx_rdma_codec_fs_sel;
+	struct reg_field rxtx_rdma_codec_ch;
+	struct reg_field rxtx_rdma_codec_fs_delay;
+
+	/*CDC RXTX WR_DMA */
+	struct reg_field rxtx_wrdma_intf;
+	struct reg_field rxtx_wrdma_bursten;
+	struct reg_field rxtx_wrdma_wpscnt;
+	struct reg_field rxtx_wrdma_fifowm;
+	struct reg_field rxtx_wrdma_enable;
+	struct reg_field rxtx_wrdma_dyncclk;
+	struct reg_field rxtx_wrdma_burst8;
+	struct reg_field rxtx_wrdma_burst16;
+	struct reg_field rxtx_wrdma_dynburst;
+	struct reg_field rxtx_wrdma_codec_enable;
+	struct reg_field rxtx_wrdma_codec_pack;
+	struct reg_field rxtx_wrdma_codec_intf;
+	struct reg_field rxtx_wrdma_codec_fs_sel;
+	struct reg_field rxtx_wrdma_codec_ch;
+	struct reg_field rxtx_wrdma_codec_fs_delay;
+
+	/*CDC VA WR_DMA */
+	struct reg_field va_wrdma_intf;
+	struct reg_field va_wrdma_bursten;
+	struct reg_field va_wrdma_wpscnt;
+	struct reg_field va_wrdma_fifowm;
+	struct reg_field va_wrdma_enable;
+	struct reg_field va_wrdma_dyncclk;
+	struct reg_field va_wrdma_burst8;
+	struct reg_field va_wrdma_burst16;
+	struct reg_field va_wrdma_dynburst;
+	struct reg_field va_wrdma_codec_enable;
+	struct reg_field va_wrdma_codec_pack;
+	struct reg_field va_wrdma_codec_intf;
+	struct reg_field va_wrdma_codec_fs_sel;
+	struct reg_field va_wrdma_codec_ch;
+	struct reg_field va_wrdma_codec_fs_delay;
+
 	/**
 	 * on SOCs like APQ8016 the channel control bits start
 	 * at different offset to ipq806x
 	 **/
 	u32	dmactl_audif_start;
 	u32	wrdma_channel_start;
+	u32	rxtx_wrdma_channel_start;
+	u32	va_wrdma_channel_start;
+
 	/* SOC specific initialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
@@ -251,10 +365,12 @@ struct lpass_variant {
 	int num_dai;
 	const char * const *dai_osr_clk_names;
 	const char * const *dai_bit_clk_names;
+	const char * const *cdc_dma_clk_names;
 
 	/* SOC specific clocks configuration */
 	const char **clk_name;
 	int num_clks;
+	int cdc_dma_num_clks;
 };
 
 struct lpass_pcm_data {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
                   ` (2 preceding siblings ...)
  2022-02-14 14:58 ` [RESEND v13 03/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-15  1:10   ` Stephen Boyd
  2022-02-14 14:58 ` [RESEND v13 05/10] ASoC: qcom: Add register definition for codec rddma and wrdma Srinivasa Rao Mandadapu
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add support function to get dma control and lpaif handle to avoid
repeated code in platform driver

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 113 +++++++++++++++++++++++-----------------
 1 file changed, 66 insertions(+), 47 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a44162c..5d77240 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -177,6 +177,49 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 	return 0;
 }
 
+static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,
+				     struct snd_soc_component *component,
+				     struct lpaif_dmactl **dmactl, int *id, struct regmap **map)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct lpass_pcm_data *pcm_data = rt->private_data;
+	struct lpass_variant *v = drvdata->variant;
+	int dir = substream->stream;
+	unsigned int dai_id = cpu_dai->driver->id;
+	struct lpaif_dmactl *l_dmactl = NULL;
+	struct regmap *l_map = NULL;
+	int l_id = 0;
+
+	switch (dai_id) {
+	case MI2S_PRIMARY ... MI2S_QUINARY:
+		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+			l_id = pcm_data->dma_ch;
+			l_dmactl = drvdata->rd_dmactl;
+		} else {
+			l_dmactl = drvdata->wr_dmactl;
+			l_id = pcm_data->dma_ch - v->wrdma_channel_start;
+		}
+		l_map = drvdata->lpaif_map;
+		break;
+	case LPASS_DP_RX:
+		l_id = pcm_data->dma_ch;
+		l_dmactl = drvdata->hdmi_rd_dmactl;
+		l_map = drvdata->hdmiif_map;
+		break;
+	default:
+		break;
+	}
+	if (dmactl)
+		*dmactl = l_dmactl;
+	if (id)
+		*id = l_id;
+	if (map)
+		*map = l_map;
+}
+
 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 					   struct snd_pcm_substream *substream,
 					   struct snd_pcm_hw_params *params)
@@ -191,21 +234,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	struct lpaif_dmactl *dmactl;
-	int id, dir = substream->stream;
+	int id;
 	int bitwidth;
 	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		id = pcm_data->dma_ch;
-		if (dai_id == LPASS_DP_RX)
-			dmactl = drvdata->hdmi_rd_dmactl;
-		else
-			dmactl = drvdata->rd_dmactl;
-
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
+	__lpass_get_lpaif_handle(substream, component, &dmactl, &id, NULL);
+	if (!dmactl) {
+		dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
+		return -EINVAL;
 	}
 
 	bitwidth = snd_pcm_format_width(format);
@@ -350,10 +387,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
 	struct regmap *map;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-	if (dai_id == LPASS_DP_RX)
-		map = drvdata->hdmiif_map;
-	else
-		map = drvdata->lpaif_map;
+	__lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
+	if (!map) {
+		dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
+		return -EINVAL;
+	}
 
 	reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
 	ret = regmap_write(map, reg, 0);
@@ -379,22 +417,12 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 	int ret, id, ch, dir = substream->stream;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-
 	ch = pcm_data->dma_ch;
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		if (dai_id == LPASS_DP_RX) {
-			dmactl = drvdata->hdmi_rd_dmactl;
-			map = drvdata->hdmiif_map;
-		} else {
-			dmactl = drvdata->rd_dmactl;
-			map = drvdata->lpaif_map;
-		}
 
-		id = pcm_data->dma_ch;
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-		map = drvdata->lpaif_map;
+	__lpass_get_lpaif_handle(substream, component, &dmactl, &id, &map);
+	if (!dmactl) {
+		dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
+		return -EINVAL;
 	}
 
 	ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
@@ -444,25 +472,15 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 	struct lpaif_dmactl *dmactl;
 	struct regmap *map;
 	int ret, ch, id;
-	int dir = substream->stream;
 	unsigned int reg_irqclr = 0, val_irqclr = 0;
 	unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
 	unsigned int dai_id = cpu_dai->driver->id;
 
 	ch = pcm_data->dma_ch;
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		id = pcm_data->dma_ch;
-		if (dai_id == LPASS_DP_RX) {
-			dmactl = drvdata->hdmi_rd_dmactl;
-			map = drvdata->hdmiif_map;
-		} else {
-			dmactl = drvdata->rd_dmactl;
-			map = drvdata->lpaif_map;
-		}
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-		map = drvdata->lpaif_map;
+	__lpass_get_lpaif_handle(substream, component, &dmactl, &id, &map);
+	if (!dmactl) {
+		dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
+		return -EINVAL;
 	}
 
 	switch (cmd) {
@@ -597,10 +615,11 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	struct regmap *map;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-	if (dai_id == LPASS_DP_RX)
-		map = drvdata->hdmiif_map;
-	else
-		map = drvdata->lpaif_map;
+	__lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
+	if (!map) {
+		dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
+		return -EINVAL;
+	}
 
 	ch = pcm_data->dma_ch;
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 05/10] ASoC: qcom: Add register definition for codec rddma and wrdma
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
                   ` (3 preceding siblings ...)
  2022-02-14 14:58 ` [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-15  1:12   ` Stephen Boyd
  2022-02-14 14:58 ` [RESEND v13 06/10] ASoC: qcom: Add regmap config support for codec dma driver Srinivasa Rao Mandadapu
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

This patch adds register definitions for codec read dma and write dma
lpass interface.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-lpaif-reg.h | 127 +++++++++++++++++++++++++++++++++++++--
 sound/soc/qcom/lpass.h           |  23 +++++++
 2 files changed, 144 insertions(+), 6 deletions(-)

diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index 2eb03ad..6d9d9d1 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -74,6 +74,21 @@
 #define LPAIF_IRQSTAT_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
 #define LPAIF_IRQCLEAR_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
 
+/* LPAIF RXTX IRQ */
+#define LPAIF_RXTX_IRQ_REG_ADDR(v, addr, port) \
+		(v->rxtx_irq_reg_base + (addr) + v->rxtx_irq_reg_stride * (port))
+
+#define LPAIF_RXTX_IRQEN_REG(v, port) LPAIF_RXTX_IRQ_REG_ADDR(v, 0x0, port)
+#define LPAIF_RXTX_IRQSTAT_REG(v, port) LPAIF_RXTX_IRQ_REG_ADDR(v, 0x4, port)
+#define LPAIF_RXTX_IRQCLEAR_REG(v, port) LPAIF_RXTX_IRQ_REG_ADDR(v, 0xC, port)
+
+/* LPAIF VA IRQ */
+#define LPAIF_VA_IRQ_REG_ADDR(v, addr, port) \
+		(v->va_irq_reg_base + (addr) + v->va_irq_reg_stride * (port))
+
+#define LPAIF_VA_IRQEN_REG(v, port) LPAIF_VA_IRQ_REG_ADDR(v, 0x0, port)
+#define LPAIF_VA_IRQSTAT_REG(v, port) LPAIF_VA_IRQ_REG_ADDR(v, 0x4, port)
+#define LPAIF_VA_IRQCLEAR_REG(v, port) LPAIF_VA_IRQ_REG_ADDR(v, 0xC, port)
 
 #define LPASS_HDMITX_APP_IRQ_REG_ADDR(v, addr)  \
 	((v->hdmi_irq_reg_base) + (addr))
@@ -139,12 +154,112 @@
 		(LPAIF_INTFDMA_REG(v, chan, reg, dai_id)) : \
 		LPAIF_WRDMA##reg##_REG(v, chan))
 
-#define LPAIF_DMACTL_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CTL, dai_id)
-#define LPAIF_DMABASE_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BASE, dai_id)
-#define	LPAIF_DMABUFF_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BUFF, dai_id)
-#define LPAIF_DMACURR_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CURR, dai_id)
-#define	LPAIF_DMAPER_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PER, dai_id)
-#define	LPAIF_DMAPERCNT_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PERCNT, dai_id)
+#define LPAIF_DMACTL_REG(v, chan, dir, dai_id) \
+	(is_cdc_dma_port(dai_id) ? \
+	__LPAIF_CDC_DMA_REG(v, chan, dir, CTL, dai_id) : \
+	__LPAIF_DMA_REG(v, chan, dir, CTL, dai_id))
+#define LPAIF_DMABASE_REG(v, chan, dir, dai_id) \
+	(is_cdc_dma_port(dai_id) ? \
+	__LPAIF_CDC_DMA_REG(v, chan, dir, BASE, dai_id) : \
+	__LPAIF_DMA_REG(v, chan, dir, BASE, dai_id))
+#define LPAIF_DMABUFF_REG(v, chan, dir, dai_id) \
+	(is_cdc_dma_port(dai_id) ? \
+	__LPAIF_CDC_DMA_REG(v, chan, dir, BUFF, dai_id) : \
+	__LPAIF_DMA_REG(v, chan, dir, BUFF, dai_id))
+#define LPAIF_DMACURR_REG(v, chan, dir, dai_id) \
+	(is_cdc_dma_port(dai_id) ? \
+	__LPAIF_CDC_DMA_REG(v, chan, dir, CURR, dai_id) : \
+	__LPAIF_DMA_REG(v, chan, dir, CURR, dai_id))
+#define LPAIF_DMAPER_REG(v, chan, dir, dai_id)  \
+	(is_cdc_dma_port(dai_id) ? \
+	__LPAIF_CDC_DMA_REG(v, chan, dir, PER, dai_id) : \
+	__LPAIF_DMA_REG(v, chan, dir, PER, dai_id))
+#define LPAIF_DMAPERCNT_REG(v, chan, dir, dai_id) \
+	(is_cdc_dma_port(dai_id) ? \
+	__LPAIF_CDC_DMA_REG(v, chan, dir, PERCNT, dai_id) : \
+	__LPAIF_DMA_REG(v, chan, dir, PERCNT, dai_id))
+
+#define LPAIF_CDC_RDMA_REG_ADDR(v, addr, chan, dai_id) \
+	(is_rxtx_cdc_dma_port(dai_id) ? \
+	(v->rxtx_rdma_reg_base + (addr) + v->rxtx_rdma_reg_stride * (chan)) : \
+	(v->va_rdma_reg_base + (addr) + v->va_rdma_reg_stride * (chan)))
+
+#define LPAIF_CDC_RXTX_RDMACTL_REG(v, chan, dai_id) \
+		LPAIF_CDC_RDMA_REG_ADDR(v, 0x00, (chan), dai_id)
+#define LPAIF_CDC_RXTX_RDMABASE_REG(v, chan, dai_id) \
+		LPAIF_CDC_RDMA_REG_ADDR(v, 0x04, (chan), dai_id)
+#define LPAIF_CDC_RXTX_RDMABUFF_REG(v, chan, dai_id) \
+		LPAIF_CDC_RDMA_REG_ADDR(v, 0x08, (chan), dai_id)
+#define LPAIF_CDC_RXTX_RDMACURR_REG(v, chan, dai_id) \
+		LPAIF_CDC_RDMA_REG_ADDR(v, 0x0C, (chan), dai_id)
+#define LPAIF_CDC_RXTX_RDMAPER_REG(v, chan, dai_id) \
+		LPAIF_CDC_RDMA_REG_ADDR(v, 0x10, (chan), dai_id)
+#define LPAIF_CDC_RXTX_RDMA_INTF_REG(v, chan, dai_id) \
+	LPAIF_CDC_RDMA_REG_ADDR(v, 0x50, (chan), dai_id)
+
+#define LPAIF_CDC_VA_RDMACTL_REG(v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x00, (chan), dai_id)
+#define LPAIF_CDC_VA_RDMABASE_REG(v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x04, (chan), dai_id)
+#define LPAIF_CDC_VA_RDMABUFF_REG(v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x08, (chan), dai_id)
+#define LPAIF_CDC_VA_RDMACURR_REG(v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x0C, (chan), dai_id)
+#define LPAIF_CDC_VA_RDMAPER_REG(v, chan, dai_id) LPAIF_CDC_RDMA_REG_ADDR(v, 0x10, (chan), dai_id)
+#define LPAIF_CDC_VA_RDMA_INTF_REG(v, chan, dai_id) \
+	LPAIF_CDC_RDMA_REG_ADDR(v, 0x50, (chan), dai_id)
+
+#define LPAIF_CDC_WRDMA_REG_ADDR(v, addr, chan, dai_id) \
+	(is_rxtx_cdc_dma_port(dai_id) ? \
+	(v->rxtx_wrdma_reg_base + (addr) + \
+		v->rxtx_wrdma_reg_stride * (chan - v->rxtx_wrdma_channel_start)) : \
+	(v->va_wrdma_reg_base + (addr) + \
+		v->va_wrdma_reg_stride * (chan - v->va_wrdma_channel_start)))
+
+#define LPAIF_CDC_RXTX_WRDMACTL_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x00, (chan), dai_id)
+#define LPAIF_CDC_RXTX_WRDMABASE_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x04, (chan), dai_id)
+#define LPAIF_CDC_RXTX_WRDMABUFF_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x08, (chan), dai_id)
+#define LPAIF_CDC_RXTX_WRDMACURR_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x0C, (chan), dai_id)
+#define LPAIF_CDC_RXTX_WRDMAPER_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x10, (chan), dai_id)
+#define LPAIF_CDC_RXTX_WRDMA_INTF_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x50, (chan), dai_id)
+
+#define LPAIF_CDC_VA_WRDMACTL_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x00, (chan), dai_id)
+#define LPAIF_CDC_VA_WRDMABASE_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x04, (chan), dai_id)
+#define LPAIF_CDC_VA_WRDMABUFF_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x08, (chan), dai_id)
+#define LPAIF_CDC_VA_WRDMACURR_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x0C, (chan), dai_id)
+#define LPAIF_CDC_VA_WRDMAPER_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x10, (chan), dai_id)
+#define LPAIF_CDC_VA_WRDMA_INTF_REG(v, chan, dai_id) \
+	LPAIF_CDC_WRDMA_REG_ADDR(v, 0x50, (chan), dai_id)
+
+#define __LPAIF_CDC_RDDMA_REG(v, chan, dir, reg, dai_id) \
+		(is_rxtx_cdc_dma_port(dai_id) ? LPAIF_CDC_RXTX_RDMA##reg##_REG(v, chan, dai_id) : \
+			LPAIF_CDC_VA_RDMA##reg##_REG(v, chan, dai_id))
+
+#define __LPAIF_CDC_WRDMA_REG(v, chan, dir, reg, dai_id) \
+		(is_rxtx_cdc_dma_port(dai_id) ? LPAIF_CDC_RXTX_WRDMA##reg##_REG(v, chan, dai_id) : \
+			LPAIF_CDC_VA_WRDMA##reg##_REG(v, chan, dai_id))
+
+#define __LPAIF_CDC_DMA_REG(v, chan, dir, reg, dai_id) \
+		((dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
+			__LPAIF_CDC_RDDMA_REG(v, chan, dir, reg, dai_id) : \
+			__LPAIF_CDC_WRDMA_REG(v, chan, dir, reg, dai_id))
+
+#define LPAIF_CDC_INTF_REG(v, chan, dir, dai_id) \
+		((dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
+		LPAIF_CDC_RDMA_INTF_REG(v, chan, dai_id) : \
+		LPAIF_CDC_WRDMA_INTF_REG(v, chan, dai_id))
+
+#define LPAIF_INTF_REG(v, chan, dir, dai_id) \
+		(is_cdc_dma_port(dai_id) ? \
+		LPAIF_CDC_INTF_REG(v, chan, dir, dai_id) : \
+		LPAIF_DMACTL_REG(v, chan, dir, dai_id))
 
 #define LPAIF_DMACTL_BURSTEN_SINGLE	0
 #define LPAIF_DMACTL_BURSTEN_INCR4	1
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 7cc3763..e059c4a 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -39,6 +39,29 @@
 			return -EINVAL;         \
 	} while (0)
 
+static inline bool is_cdc_dma_port(int dai_id)
+{
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline bool is_rxtx_cdc_dma_port(int dai_id)
+{
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		return true;
+	default:
+		return false;
+	}
+}
+
 struct lpaif_i2sctl {
 	struct regmap_field *loopback;
 	struct regmap_field *spken;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 06/10] ASoC: qcom: Add regmap config support for codec dma driver
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
                   ` (4 preceding siblings ...)
  2022-02-14 14:58 ` [RESEND v13 05/10] ASoC: qcom: Add register definition for codec rddma and wrdma Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 07/10] ASoC: qcom: Add " Srinivasa Rao Mandadapu
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Update regmap configuration for supporting headset playback and
capture and DMIC capture using codec dma interface

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 185 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 3bd9eb3..4fb9669 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -28,6 +28,8 @@
 #define LPASS_CPU_I2S_SD2_3_MASK	GENMASK(3, 2)
 #define LPASS_CPU_I2S_SD0_1_2_MASK	GENMASK(2, 0)
 #define LPASS_CPU_I2S_SD0_1_2_3_MASK	GENMASK(3, 0)
+#define LPASS_REG_READ 1
+#define LPASS_REG_WRITE 0
 
 /*
  * Channel maps for Quad channel playbacks on MI2S Secondary
@@ -798,6 +800,189 @@ static struct regmap_config lpass_hdmi_regmap_config = {
 	.cache_type = REGCACHE_FLAT,
 };
 
+static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->rxtx_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
+			return true;
+		if (reg == LPAIF_RXTX_IRQEN_REG(v, i))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_rdma_channels; ++i) {
+		if (reg == LPAIF_CDC_RXTX_RDMACTL_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RXTX_RDMABASE_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RXTX_RDMABUFF_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_RXTX_RDMAPER_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RXTX_RDMA_INTF_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_RXTX_WRDMACTL_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_RXTX_WRDMABASE_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_RXTX_WRDMABUFF_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_RXTX_WRDMAPER_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_RXTX_WRDMA_INTF_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+	}
+	return false;
+}
+
+static bool lpass_rxtx_regmap_writeable(struct device *dev, unsigned int reg)
+{
+	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
+{
+	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->rxtx_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_rdma_channels; ++i)
+		if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+
+	for (i = 0; i < v->rxtx_wrdma_channels; ++i)
+		if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+
+	return false;
+}
+
+static bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->va_irq_ports; ++i) {
+		if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
+			return true;
+		if (reg == LPAIF_VA_IRQEN_REG(v, i))
+			return true;
+		if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
+			return true;
+	}
+
+	for (i = 0; i < v->va_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_VA_WRDMACTL_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_VA_WRDMABASE_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_VA_WRDMABUFF_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_VA_WRDMAPER_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_VA_WRDMA_INTF_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+	return false;
+}
+
+static bool lpass_va_regmap_writeable(struct device *dev, unsigned int reg)
+{
+	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
+{
+	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+static bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->va_irq_ports; ++i) {
+		if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
+			return true;
+		if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
+			return true;
+	}
+
+	for (i = 0; i < v->va_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+
+	return false;
+}
+
+static struct regmap_config lpass_rxtx_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.writeable_reg = lpass_rxtx_regmap_writeable,
+	.readable_reg = lpass_rxtx_regmap_readable,
+	.volatile_reg = lpass_rxtx_regmap_volatile,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static struct regmap_config lpass_va_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.writeable_reg = lpass_va_regmap_writeable,
+	.readable_reg = lpass_va_regmap_readable,
+	.volatile_reg = lpass_va_regmap_volatile,
+	.cache_type = REGCACHE_FLAT,
+};
+
 static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
 						struct device_node *node,
 						const char *name)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 07/10] ASoC: qcom: Add support for codec dma driver
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
                   ` (5 preceding siblings ...)
  2022-02-14 14:58 ` [RESEND v13 06/10] ASoC: qcom: Add regmap config support for codec dma driver Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-15  1:27   ` Stephen Boyd
                     ` (2 more replies)
  2022-02-14 14:58 ` [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control Srinivasa Rao Mandadapu
                   ` (2 subsequent siblings)
  9 siblings, 3 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Upadate lpass cpu and platform driver to support audio over codec dma
in ADSP bypass use case.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reported-by: kernel test robot <lkp@intel.com>
---
 sound/soc/qcom/lpass-cpu.c      |  59 ++++-
 sound/soc/qcom/lpass-platform.c | 499 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 537 insertions(+), 21 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 4fb9669..a5a46bc 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -1042,7 +1042,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
 		}
 		if (id == LPASS_DP_RX) {
 			data->hdmi_port_enable = 1;
-		} else {
+		} else if (is_cdc_dma_port(id))
+			data->codec_dma_enable = 1;
+		else {
 			data->mi2s_playback_sd_mode[id] =
 				of_lpass_cpu_parse_sd_lines(dev, node,
 							    "qcom,playback-sd-lines");
@@ -1057,6 +1059,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata;
 	struct device_node *dsp_of_node;
+	struct resource *res;
 	struct lpass_variant *variant;
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *match;
@@ -1082,6 +1085,58 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 
 	of_lpass_cpu_parse_dai_data(dev, drvdata);
 
+	drvdata->num_clks =  variant->num_clks;
+	if (drvdata->codec_dma_enable) {
+		drvdata->rxtx_lpaif =
+				devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
+		if (IS_ERR(drvdata->rxtx_lpaif))
+			return PTR_ERR(drvdata->rxtx_lpaif);
+
+		drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
+		if (IS_ERR(drvdata->va_lpaif))
+			return PTR_ERR(drvdata->va_lpaif);
+
+		lpass_rxtx_regmap_config.max_register = LPAIF_CDC_RXTX_WRDMAPER_REG(variant,
+					variant->rxtx_wrdma_channels +
+					variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
+
+		drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
+					&lpass_rxtx_regmap_config);
+		if (IS_ERR(drvdata->rxtx_lpaif_map)) {
+			dev_err(dev, "error initializing rxtx regmap: %ld\n",
+				PTR_ERR(drvdata->rxtx_lpaif_map));
+			return PTR_ERR(drvdata->rxtx_lpaif_map);
+		}
+		lpass_va_regmap_config.max_register = LPAIF_CDC_VA_WRDMAPER_REG(variant,
+					variant->va_wrdma_channels +
+					variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
+
+		drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
+					&lpass_va_regmap_config);
+		if (IS_ERR(drvdata->va_lpaif_map)) {
+			dev_err(dev, "error initializing va regmap: %ld\n",
+				PTR_ERR(drvdata->va_lpaif_map));
+			return PTR_ERR(drvdata->va_lpaif_map);
+		}
+		drvdata->cdc_clks = devm_kcalloc(dev, variant->cdc_dma_num_clks,
+					sizeof(*drvdata->cdc_clks), GFP_KERNEL);
+		drvdata->cdc_num_clks = variant->cdc_dma_num_clks;
+
+		for (i = 0; i < drvdata->cdc_num_clks; i++)
+			drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
+
+		ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, drvdata->cdc_clks);
+		if (ret) {
+			dev_err(dev, "Failed to get clocks %d\n", ret);
+			return ret;
+		}
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
+		drvdata->rxtx_cdc_dma_lpm_buf = res->start;
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
+		drvdata->va_cdc_dma_lpm_buf = res->start;
+	}
 	drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
 	if (IS_ERR(drvdata->lpaif))
 		return PTR_ERR(drvdata->lpaif);
@@ -1124,7 +1179,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 
 	for (i = 0; i < variant->num_dai; i++) {
 		dai_id = variant->dai_driver[i].id;
-		if (dai_id == LPASS_DP_RX)
+		if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
 			continue;
 
 		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 5d77240..12b8d40 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -20,6 +20,9 @@
 
 #define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
+#define LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE (8 * 1024)
+#define LPASS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
+#define LPASS_CDC_DMA_REGISTER_FIELDS_MAX 15
 
 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.info			=	SNDRV_PCM_INFO_MMAP |
@@ -45,6 +48,99 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.fifo_size		=	0,
 };
 
+static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	SNDRV_PCM_RATE_8000_192000,
+	.rate_min		=	8000,
+	.rate_max		=	192000,
+	.channels_min		=	1,
+	.channels_max		=	8,
+	.buffer_bytes_max	=	LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
+	.period_bytes_max	=	LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.period_bytes_min	=	LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.periods_min		=	LPASS_PLATFORM_PERIODS,
+	.periods_max		=	LPASS_PLATFORM_PERIODS,
+	.fifo_size		=	0,
+};
+
+static const struct snd_pcm_hardware lpass_platform_va_hardware = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	SNDRV_PCM_RATE_8000_192000,
+	.rate_min		=	8000,
+	.rate_max		=	192000,
+	.channels_min		=	1,
+	.channels_max		=	8,
+	.buffer_bytes_max	=	LPASS_VA_CDC_DMA_LPM_BUFF_SIZE,
+	.period_bytes_max	=	LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.period_bytes_min	=	LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.periods_min		=	LPASS_PLATFORM_PERIODS,
+	.periods_max		=	LPASS_PLATFORM_PERIODS,
+	.fifo_size		=	0,
+};
+
+static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
+					 struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
+	int rval;
+
+	rd_dmactl = devm_kzalloc(dev, sizeof(*rd_dmactl), GFP_KERNEL);
+	if (rd_dmactl == NULL)
+		return -ENOMEM;
+
+	wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
+	if (wr_dmactl == NULL)
+		return -ENOMEM;
+
+	drvdata->rxtx_rd_dmactl = rd_dmactl;
+	drvdata->rxtx_wr_dmactl = wr_dmactl;
+
+	rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
+					    &v->rxtx_rdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
+	if (rval)
+		return rval;
+
+	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+					    &v->rxtx_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
+}
+
+static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
+					 struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	struct lpaif_dmactl *wr_dmactl;
+
+	wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
+	if (wr_dmactl == NULL)
+		return -ENOMEM;
+
+	drvdata->va_wr_dmactl = wr_dmactl;
+	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+					    &v->va_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
+}
+
+
 static int lpass_platform_alloc_dmactl_fields(struct device *dev,
 					 struct regmap *map)
 {
@@ -123,25 +219,55 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 		return dma_ch;
 	}
 
-	if (cpu_dai->driver->id == LPASS_DP_RX) {
-		map = drvdata->hdmiif_map;
-		drvdata->hdmi_substream[dma_ch] = substream;
-	} else {
+	switch (dai_id) {
+	case MI2S_PRIMARY ... MI2S_QUINARY:
 		map = drvdata->lpaif_map;
 		drvdata->substream[dma_ch] = substream;
+		break;
+	case LPASS_DP_RX:
+		map = drvdata->hdmiif_map;
+		drvdata->hdmi_substream[dma_ch] = substream;
+		break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		map = drvdata->rxtx_lpaif_map;
+		drvdata->rxtx_substream[dma_ch] = substream;
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		map = drvdata->va_lpaif_map;
+		drvdata->va_substream[dma_ch] = substream;
+		break;
+	default:
+		break;
 	}
+
 	data->dma_ch = dma_ch;
-	ret = regmap_write(map,
-			LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
-	if (ret) {
-		dev_err(soc_runtime->dev,
-			"error writing to rdmactl reg: %d\n", ret);
-		return ret;
+	switch (dai_id) {
+	case MI2S_PRIMARY ... MI2S_QUINARY:
+	case LPASS_DP_RX:
+		ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
+		if (ret) {
+			kfree(data);
+			dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret);
+			return ret;
+		}
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
+		runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
+		break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
+		runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
+		runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
+		snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+		break;
+	default:
+		break;
 	}
-	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
-
-	runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
-
 	ret = snd_pcm_hw_constraint_integer(runtime,
 			SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0) {
@@ -166,10 +292,25 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 	unsigned int dai_id = cpu_dai->driver->id;
 
 	data = runtime->private_data;
-	if (dai_id == LPASS_DP_RX)
-		drvdata->hdmi_substream[data->dma_ch] = NULL;
-	else
+
+	switch (dai_id) {
+	case MI2S_PRIMARY ... MI2S_QUINARY:
 		drvdata->substream[data->dma_ch] = NULL;
+		break;
+	case LPASS_DP_RX:
+		drvdata->hdmi_substream[data->dma_ch] = NULL;
+		break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		drvdata->rxtx_substream[data->dma_ch] = NULL;
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		drvdata->va_substream[data->dma_ch] = NULL;
+		break;
+	default:
+		break;
+	}
+
 	if (v->free_dma_channel)
 		v->free_dma_channel(drvdata, data->dma_ch, dai_id);
 
@@ -209,9 +350,25 @@ static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,
 		l_dmactl = drvdata->hdmi_rd_dmactl;
 		l_map = drvdata->hdmiif_map;
 		break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+		l_id = pcm_data->dma_ch;
+		l_dmactl = drvdata->rxtx_rd_dmactl;
+		l_map = drvdata->rxtx_lpaif_map;
+		break;
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
+		l_dmactl = drvdata->rxtx_wr_dmactl;
+		l_map = drvdata->rxtx_lpaif_map;
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
+		l_dmactl = drvdata->va_wr_dmactl;
+		l_map = drvdata->va_lpaif_map;
+		break;
 	default:
 		break;
 	}
+
 	if (dmactl)
 		*dmactl = l_dmactl;
 	if (id)
@@ -299,6 +456,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 		}
 
 		break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
+		break;
 	default:
 		dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
 		break;
@@ -387,6 +548,9 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
 	struct regmap *map;
 	unsigned int dai_id = cpu_dai->driver->id;
 
+	if (is_cdc_dma_port(dai_id))
+		return 0;
+
 	__lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
 	if (!map) {
 		dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
@@ -449,6 +613,14 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 		return ret;
 	}
 
+	if (is_cdc_dma_port(dai_id)) {
+		ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
+		if (ret) {
+			dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",
+				ret, id);
+			return ret;
+		}
+	}
 	ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
@@ -532,6 +704,35 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 			val_mask = LPAIF_IRQ_ALL(ch);
 			val_irqen = LPAIF_IRQ_ALL(ch);
 			break;
+		case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+		case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+			break;
+		case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+			reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+			break;
 		default:
 			dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
 			return -EINVAL;
@@ -583,6 +784,37 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 			val_mask = LPAIF_IRQ_ALL(ch);
 			val_irqen = 0;
 			break;
+		case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+		case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+
+			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+			break;
+		case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+
+			reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+			break;
 		default:
 			dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
 			return -EINVAL;
@@ -642,6 +874,39 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	return bytes_to_frames(substream->runtime, curr_addr - base_addr);
 }
 
+static int lpass_platform_cdc_dma_mmap(struct snd_soc_component *component,
+				       struct snd_pcm_substream *substream,
+				       struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long size, offset;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	size = vma->vm_end - vma->vm_start;
+	offset = vma->vm_pgoff << PAGE_SHIFT;
+	return io_remap_pfn_range(vma, vma->vm_start,
+			(runtime->dma_addr + offset) >> PAGE_SHIFT,
+			size, vma->vm_page_prot);
+
+}
+
+static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
+				      struct snd_pcm_substream *substream,
+				      struct vm_area_struct *vma)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	unsigned int dai_id = cpu_dai->driver->id;
+	int err;
+
+	if (is_cdc_dma_port(dai_id))
+		err = lpass_platform_cdc_dma_mmap(component, substream, vma);
+	else
+		err = snd_pcm_lib_default_mmap(substream, vma);
+
+	return err;
+}
+
 static irqreturn_t lpass_dma_interrupt_handler(
 			struct snd_pcm_substream *substream,
 			struct lpass_data *drvdata,
@@ -674,6 +939,17 @@ static irqreturn_t lpass_dma_interrupt_handler(
 		reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
 		val = 0;
 	break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		map = drvdata->rxtx_lpaif_map;
+		reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+		val = 0;
+	break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		map = drvdata->va_lpaif_map;
+		reg = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+		val = 0;
+	break;
 	default:
 	dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
 	return -EINVAL;
@@ -781,18 +1057,122 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
 				return rv;
 		}
 	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->rxtx_lpaif_map,
+			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
+	if (rv)
+		return IRQ_NONE;
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->rxtx_substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
 
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->va_lpaif_map,
+			LPAIF_VA_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
+	if (rv)
+		return IRQ_NONE;
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->va_substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,
+						  struct snd_pcm *pcm, int dai_id)
+{
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int ret;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+		substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	else
+		substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+
+	ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	buf = &substream->dma_buffer;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+
+	/* Assign Codec DMA buffer pointers */
+	buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
+		break;
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
+		buf->addr = drvdata->va_cdc_dma_lpm_buf;
+		break;
+	default:
+		break;
+	}
+
+	buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
+
+	return 0;
+}
+
 static int lpass_platform_pcm_new(struct snd_soc_component *component,
 				  struct snd_soc_pcm_runtime *soc_runtime)
 {
 	struct snd_pcm *pcm = soc_runtime->pcm;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	unsigned int dai_id = cpu_dai->driver->id;
+
 	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 
-	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
-					    component->dev, size);
+	/*
+	 * Lpass codec dma can access only lpass lpm hardware memory.
+	 * ioremap is for HLOS to access hardware memory.
+	 */
+	if (is_cdc_dma_port(dai_id))
+		return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
+	else
+		return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+						component->dev, size);
 }
 
 static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
@@ -827,6 +1207,31 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
 	return regcache_sync(map);
 }
 
+static int lpass_platform_copy(struct snd_soc_component *component,
+			       struct snd_pcm_substream *substream, int channel,
+			       unsigned long pos, void __user *buf, unsigned long bytes)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	unsigned int dai_id = component->id;
+	int ret = 0;
+
+	void __iomem *dma_buf = rt->dma_area + pos +
+				channel * (rt->dma_bytes / rt->channels);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (is_cdc_dma_port(dai_id))
+			ret = copy_from_user_toio(dma_buf, buf, bytes);
+		else
+			ret = copy_from_user((void __force *)dma_buf, buf, bytes);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (is_cdc_dma_port(dai_id))
+			ret = copy_to_user_fromio(buf, dma_buf, bytes);
+		else
+			ret = copy_to_user(buf, (void __force *)dma_buf, bytes);
+	}
+
+	return ret;
+}
 
 static const struct snd_soc_component_driver lpass_component_driver = {
 	.name		= DRV_NAME,
@@ -837,9 +1242,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
 	.prepare	= lpass_platform_pcmops_prepare,
 	.trigger	= lpass_platform_pcmops_trigger,
 	.pointer	= lpass_platform_pcmops_pointer,
+	.mmap		= lpass_platform_pcmops_mmap,
 	.pcm_construct	= lpass_platform_pcm_new,
 	.suspend		= lpass_platform_pcmops_suspend,
 	.resume			= lpass_platform_pcmops_resume,
+	.copy_user		= lpass_platform_copy,
 
 };
 
@@ -877,6 +1284,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (drvdata->codec_dma_enable) {
+		ret = regmap_write(drvdata->rxtx_lpaif_map,
+			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
+		if (ret) {
+			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
+			return ret;
+		}
+		ret = regmap_write(drvdata->va_lpaif_map,
+			LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
+		if (ret) {
+			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
+			return ret;
+		}
+		drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
+		if (drvdata->rxtxif_irq < 0)
+			return -ENODEV;
+
+		ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
+				lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,
+				"lpass-irq-rxtxif", drvdata);
+		if (ret) {
+			dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
+			return ret;
+		}
+
+		ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
+						 drvdata->rxtx_lpaif_map);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"error initializing rxtx dmactl fields: %d\n", ret);
+			return ret;
+		}
+
+		drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");
+		if (drvdata->vaif_irq < 0)
+			return -ENODEV;
+
+		ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
+				lpass_platform_vaif_irq, IRQF_TRIGGER_RISING,
+				"lpass-irq-vaif", drvdata);
+		if (ret) {
+			dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
+			return ret;
+		}
+
+		ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
+						 drvdata->va_lpaif_map);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"error initializing va dmactl fields: %d\n", ret);
+			return ret;
+		}
+	}
+
 	if (drvdata->hdmi_port_enable) {
 		drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
 		if (drvdata->hdmiif_irq < 0)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
                   ` (6 preceding siblings ...)
  2022-02-14 14:58 ` [RESEND v13 07/10] ASoC: qcom: Add " Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-15  1:33   ` Stephen Boyd
  2022-02-14 14:58 ` [RESEND v13 09/10] ASoC: dt-bindings: Add SC7280 lpass cpu bindings Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 10/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio Srinivasa Rao Mandadapu
  9 siblings, 1 reply; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add lpass cpu driver to support audio over codec dma for
ADSP bypass usecase.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cdc-dma.c | 304 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/qcom/lpass.h         |   1 +
 2 files changed, 305 insertions(+)
 create mode 100644 sound/soc/qcom/lpass-cdc-dma.c

diff --git a/sound/soc/qcom/lpass-cdc-dma.c b/sound/soc/qcom/lpass-cdc-dma.c
new file mode 100644
index 0000000..4a50baa
--- /dev/null
+++ b/sound/soc/qcom/lpass-cdc-dma.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021 The Linux Foundation. All rights reserved.
+ *
+ * lpass-cdc-dma.c -- ALSA SoC CDC DMA CPU DAI driver for QTi LPASS
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+#define CODEC_MEM_FREQ_NORMAL 153600000
+
+enum codec_dma_interfaces {
+	LPASS_CDC_DMA_INTERFACE1 = 1,
+	LPASS_CDC_DMA_INTERFACE2,
+	LPASS_CDC_DMA_INTERFACE3,
+	LPASS_CDC_DMA_INTERFACE4,
+	LPASS_CDC_DMA_INTERFACE5,
+	LPASS_CDC_DMA_INTERFACE6,
+	LPASS_CDC_DMA_INTERFACE7,
+	LPASS_CDC_DMA_INTERFACE8,
+	LPASS_CDC_DMA_INTERFACE9,
+	LPASS_CDC_DMA_INTERFACE10,
+};
+
+static void __lpass_get_dmactl_handle(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
+				      struct lpaif_dmactl **dmactl, int *id)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct lpass_pcm_data *pcm_data = rt->private_data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int dai_id = cpu_dai->driver->id;
+
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+		*dmactl = drvdata->rxtx_rd_dmactl;
+		*id = pcm_data->dma_ch;
+		break;
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		*dmactl = drvdata->rxtx_wr_dmactl;
+		*id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		*dmactl = drvdata->va_wr_dmactl;
+		*id = pcm_data->dma_ch - v->va_wrdma_channel_start;
+		break;
+	default:
+		dev_err(soc_runtime->dev, "invalid dai id for dma ctl: %d\n", dai_id);
+		break;
+	}
+}
+
+static int __lpass_get_codec_dma_intf_type(int dai_id)
+{
+	int ret;
+
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_TX0:
+	case LPASS_CDC_DMA_VA_TX0:
+		ret = LPASS_CDC_DMA_INTERFACE1;
+		break;
+	case LPASS_CDC_DMA_RX1:
+	case LPASS_CDC_DMA_TX1:
+	case LPASS_CDC_DMA_VA_TX1:
+		ret = LPASS_CDC_DMA_INTERFACE2;
+		break;
+	case LPASS_CDC_DMA_RX2:
+	case LPASS_CDC_DMA_TX2:
+	case LPASS_CDC_DMA_VA_TX2:
+		ret = LPASS_CDC_DMA_INTERFACE3;
+		break;
+	case LPASS_CDC_DMA_RX3:
+	case LPASS_CDC_DMA_TX3:
+	case LPASS_CDC_DMA_VA_TX3:
+		ret = LPASS_CDC_DMA_INTERFACE4;
+		break;
+	case LPASS_CDC_DMA_RX4:
+	case LPASS_CDC_DMA_TX4:
+	case LPASS_CDC_DMA_VA_TX4:
+		ret = LPASS_CDC_DMA_INTERFACE5;
+		break;
+	case LPASS_CDC_DMA_RX5:
+	case LPASS_CDC_DMA_TX5:
+	case LPASS_CDC_DMA_VA_TX5:
+		ret = LPASS_CDC_DMA_INTERFACE6;
+		break;
+	case LPASS_CDC_DMA_RX6:
+	case LPASS_CDC_DMA_TX6:
+	case LPASS_CDC_DMA_VA_TX6:
+		ret = LPASS_CDC_DMA_INTERFACE7;
+		break;
+	case LPASS_CDC_DMA_RX7:
+	case LPASS_CDC_DMA_TX7:
+	case LPASS_CDC_DMA_VA_TX7:
+		ret = LPASS_CDC_DMA_INTERFACE8;
+		break;
+	case LPASS_CDC_DMA_RX8:
+	case LPASS_CDC_DMA_TX8:
+	case LPASS_CDC_DMA_VA_TX8:
+		ret = LPASS_CDC_DMA_INTERFACE9;
+		break;
+	case LPASS_CDC_DMA_RX9:
+		ret  = LPASS_CDC_DMA_INTERFACE10;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int __lpass_platform_codec_intf_init(struct snd_soc_dai *dai,
+					    struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	struct lpaif_dmactl *dmactl = NULL;
+	struct device *dev = soc_runtime->dev;
+	int ret, id, codec_intf;
+	unsigned int dai_id = cpu_dai->driver->id;
+
+	codec_intf = __lpass_get_codec_dma_intf_type(dai_id);
+	if (codec_intf < 0) {
+		dev_err(dev, "failed to get codec_intf: %d\n", codec_intf);
+		return codec_intf;
+	}
+
+	__lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
+	if (!dmactl) {
+		dev_err(dev, "failed to get dmactl handle for dai_id: %d\n", dai_id);
+		return -EINVAL;
+	}
+
+	ret = regmap_fields_write(dmactl->codec_intf, id, codec_intf);
+	if (ret) {
+		dev_err(dev, "error writing to dmactl codec_intf reg field: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_fields_write(dmactl->codec_fs_sel, id, 0x0);
+	if (ret) {
+		dev_err(dev, "error writing to dmactl codec_fs_sel reg field: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_fields_write(dmactl->codec_fs_delay, id, 0x0);
+	if (ret) {
+		dev_err(dev, "error writing to dmactl codec_fs_delay reg field: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_fields_write(dmactl->codec_pack, id, 0x1);
+	if (ret) {
+		dev_err(dev, "error writing to dmactl codec_pack reg field: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_fields_write(dmactl->codec_enable, id, LPAIF_DMACTL_ENABLE_ON);
+	if (ret) {
+		dev_err(dev, "error writing to dmactl codec_enable reg field: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int lpass_cdc_dma_daiops_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+
+	switch (dai->id) {
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		clk_set_rate(drvdata->cdc_clks[2].clk, CODEC_MEM_FREQ_NORMAL);
+		clk_prepare_enable(drvdata->cdc_clks[2].clk);
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
+		clk_set_rate(drvdata->cdc_clks[5].clk, CODEC_MEM_FREQ_NORMAL);
+		clk_prepare_enable(drvdata->cdc_clks[5].clk);
+		break;
+	default:
+		dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai->id);
+		break;
+	}
+	return 0;
+}
+
+static void lpass_cdc_dma_daiops_shutdown(struct snd_pcm_substream *substream,
+				      struct snd_soc_dai *dai)
+{
+	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+
+	switch (dai->id) {
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		clk_disable_unprepare(drvdata->cdc_clks[2].clk);
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
+		clk_disable_unprepare(drvdata->cdc_clks[5].clk);
+		break;
+	default:
+		dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai->id);
+		break;
+	}
+}
+
+static int lpass_cdc_dma_daiops_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct lpaif_dmactl *dmactl = NULL;
+	unsigned int ret, regval;
+	unsigned int channels = params_channels(params);
+	int id;
+
+	switch (channels) {
+	case 1:
+		regval = LPASS_CDC_DMA_INTF_ONE_CHANNEL;
+		break;
+	case 2:
+		regval = LPASS_CDC_DMA_INTF_TWO_CHANNEL;
+		break;
+	case 4:
+		regval = LPASS_CDC_DMA_INTF_FOUR_CHANNEL;
+		break;
+	case 6:
+		regval = LPASS_CDC_DMA_INTF_SIX_CHANNEL;
+		break;
+	case 8:
+		regval = LPASS_CDC_DMA_INTF_EIGHT_CHANNEL;
+		break;
+	default:
+		dev_err(soc_runtime->dev, "invalid PCM config\n");
+		return -EINVAL;
+	}
+
+	__lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
+	if (!dmactl) {
+		dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
+		return -EINVAL;
+	}
+	ret = regmap_fields_write(dmactl->codec_channel, id, regval);
+	if (ret) {
+		dev_err(soc_runtime->dev,
+			"error writing to dmactl codec_channel reg field: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int lpass_cdc_dma_daiops_trigger(struct snd_pcm_substream *substream,
+				    int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct lpaif_dmactl *dmactl;
+	int ret = 0, id;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		__lpass_platform_codec_intf_init(dai, substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		__lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
+		if (!dmactl) {
+			dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
+			return -EINVAL;
+		}
+		ret = regmap_fields_write(dmactl->codec_enable, id, LPAIF_DMACTL_ENABLE_OFF);
+		if (ret) {
+			dev_err(soc_runtime->dev,
+				"error writing to dmactl codec_enable reg: %d\n", ret);
+			return ret;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, cmd);
+		break;
+	}
+	return ret;
+}
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops = {
+	.startup	= lpass_cdc_dma_daiops_startup,
+	.shutdown	= lpass_cdc_dma_daiops_shutdown,
+	.hw_params	= lpass_cdc_dma_daiops_hw_params,
+	.trigger	= lpass_cdc_dma_daiops_trigger,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cdc_dma_dai_ops);
+
+MODULE_DESCRIPTION("QTi LPASS CDC DMA Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index e059c4a..d279a72 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -410,5 +410,6 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
 extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
 int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
 				struct snd_soc_dai *dai);
+extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops;
 
 #endif /* __LPASS_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 09/10] ASoC: dt-bindings: Add SC7280 lpass cpu bindings
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
                   ` (7 preceding siblings ...)
  2022-02-14 14:58 ` [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  2022-02-14 14:58 ` [RESEND v13 10/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio Srinivasa Rao Mandadapu
  9 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add bindings for sc7280 lpass cpu driver which supports
audio over i2s based speaker, soundwire based headset, msm dmics
and HDMI Port.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/sound/qcom,lpass-cpu.yaml  | 75 +++++++++++++++++++---
 1 file changed, 67 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
index 1e23c0e..2c81efb 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
@@ -22,35 +22,41 @@ properties:
       - qcom,lpass-cpu
       - qcom,apq8016-lpass-cpu
       - qcom,sc7180-lpass-cpu
+      - qcom,sc7280-lpass-cpu
 
   reg:
-    maxItems: 2
+    minItems: 2
+    maxItems: 6
     description: LPAIF core registers
 
   reg-names:
-    maxItems: 2
+    minItems: 2
+    maxItems: 6
 
   clocks:
     minItems: 3
-    maxItems: 6
+    maxItems: 7
 
   clock-names:
     minItems: 3
-    maxItems: 6
+    maxItems: 7
 
   interrupts:
-    maxItems: 2
+    minItems: 2
+    maxItems: 4
     description: LPAIF DMA buffer interrupt
 
   interrupt-names:
-    maxItems: 2
+    minItems: 2
+    maxItems: 4
 
   qcom,adsp:
     $ref: /schemas/types.yaml#/definitions/phandle
     description: Phandle for the audio DSP node
 
   iommus:
-    maxItems: 2
+    minItems: 2
+    maxItems: 3
     description: Phandle to apps_smmu node with sid mask
 
   power-domains:
@@ -69,7 +75,7 @@ patternProperties:
   "^dai-link@[0-9a-f]$":
     type: object
     description: |
-      LPASS CPU dai node for each I2S device. Bindings of each node
+      LPASS CPU dai node for each I2S device or Soundwire device. Bindings of each node
       depends on the specific driver providing the functionality and
       properties.
     properties:
@@ -174,6 +180,59 @@ allOf:
         - iommus
         - power-domains
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: qcom,sc7280-lpass-cpu
+
+    then:
+      properties:
+        clock-names:
+          oneOf:
+            - items:   #for I2S
+                - const: aon_cc_audio_hm_h
+                - const: core_cc_sysnoc_mport_core
+                - const: core_cc_ext_if1_ibit
+            - items:   #for Soundwire
+                - const: aon_cc_audio_hm_h
+                - const: audio_cc_codec_mem0
+                - const: audio_cc_codec_mem1
+                - const: audio_cc_codec_mem2
+            - items:   #for HDMI
+                - const: aon_cc_audio_hm_h
+
+        reg-names:
+          anyOf:
+            - items:   #for I2S
+                - const: lpass-lpaif
+            - items:   #for I2S and HDMI
+                - const: lpass-hdmiif
+                - const: lpass-lpaif
+            - items:   #for I2S, soundwire and HDMI
+                - const: lpass-hdmiif
+                - const: lpass-lpaif
+                - const: lpass-rxtx-cdc-dma-lpm
+                - const: lpass-rxtx-lpaif
+                - const: lpass-va-lpaif
+                - const: lpass-va-cdc-dma-lpm
+        interrupt-names:
+          anyOf:
+            - items:   #for I2S
+                - const: lpass-irq-lpaif
+            - items:   #for I2S and HDMI
+                - const: lpass-irq-lpaif
+                - const: lpass-irq-hdmi
+            - items:   #for I2S, soundwire and HDMI
+                - const: lpass-irq-lpaif
+                - const: lpass-irq-hdmi
+                - const: lpass-irq-vaif
+                - const: lpass-irq-rxtxif
+
+      required:
+        - iommus
+        - power-domains
+
 examples:
   - |
     #include <dt-bindings/sound/sc7180-lpass.h>
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [RESEND v13 10/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio
  2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
                   ` (8 preceding siblings ...)
  2022-02-14 14:58 ` [RESEND v13 09/10] ASoC: dt-bindings: Add SC7280 lpass cpu bindings Srinivasa Rao Mandadapu
@ 2022-02-14 14:58 ` Srinivasa Rao Mandadapu
  9 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-14 14:58 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, quic_plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add platform driver for configuring sc7280 lpass core I2S and
DMA configuration to support playback & capture to external codecs
connected over secondary MI2S interface and soundwire interface.

Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-sc7280.c | 447 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 447 insertions(+)
 create mode 100644 sound/soc/qcom/lpass-sc7280.c

diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
new file mode 100644
index 0000000..61a445c
--- /dev/null
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -0,0 +1,447 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ *
+ * lpass-sc7180.c -- ALSA SoC platform-machine driver for QTi LPASS
+ */
+
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/sound/sc7180-lpass.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
+	{
+		.id = MI2S_PRIMARY,
+		.name = "Primary MI2S",
+		.playback = {
+			.stream_name = "Primary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.capture = {
+			.stream_name = "Primary Capture",
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	}, {
+		.id = MI2S_SECONDARY,
+		.name = "Secondary MI2S",
+		.playback = {
+			.stream_name = "Secondary MI2S Playback",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops	= &asoc_qcom_lpass_cpu_dai_ops,
+	}, {
+		.id = LPASS_DP_RX,
+		.name = "Hdmi",
+		.playback = {
+			.stream_name = "DP Playback",
+			.formats = SNDRV_PCM_FMTBIT_S24,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_hdmi_dai_ops,
+	}, {
+		.id = LPASS_CDC_DMA_RX0,
+		.name = "CDC DMA RX",
+		.playback = {
+			.stream_name = "WCD Playback",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_cdc_dma_dai_ops,
+	}, {
+		.id = LPASS_CDC_DMA_TX3,
+		.name = "CDC DMA TX",
+		.capture = {
+			.stream_name = "WCD Capture",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 1,
+			.channels_max	= 1,
+		},
+		.ops	= &asoc_qcom_lpass_cdc_dma_dai_ops,
+	}, {
+		.id = LPASS_CDC_DMA_VA_TX0,
+		.name = "CDC DMA VA",
+		.capture = {
+			.stream_name = "DMIC Capture",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 4,
+		},
+		.ops	= &asoc_qcom_lpass_cdc_dma_dai_ops,
+	},
+};
+
+static int sc7280_lpass_alloc_dma_channel(struct lpass_data *drvdata,
+					  int direction, unsigned int dai_id)
+{
+	struct lpass_variant *v = drvdata->variant;
+	int chan = 0;
+
+	switch (dai_id) {
+	case MI2S_PRIMARY ... MI2S_QUINARY:
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
+						   v->rdma_channels);
+
+			if (chan >= v->rdma_channels)
+				return -EBUSY;
+		} else {
+			chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
+						  v->wrdma_channel_start +
+						  v->wrdma_channels,
+						  v->wrdma_channel_start);
+
+			if (chan >= v->wrdma_channel_start + v->wrdma_channels)
+				return -EBUSY;
+		}
+		set_bit(chan, &drvdata->dma_ch_bit_map);
+		break;
+	case LPASS_DP_RX:
+		chan = find_first_zero_bit(&drvdata->hdmi_dma_ch_bit_map,
+					   v->hdmi_rdma_channels);
+		if (chan >= v->hdmi_rdma_channels)
+			return -EBUSY;
+		set_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
+		break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+		chan = find_first_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
+					   v->rxtx_rdma_channels);
+		if (chan >= v->rxtx_rdma_channels)
+			return -EBUSY;
+		break;
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		chan = find_next_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
+					  v->rxtx_wrdma_channel_start +
+					  v->rxtx_wrdma_channels,
+					  v->rxtx_wrdma_channel_start);
+		if (chan >= v->rxtx_wrdma_channel_start + v->rxtx_wrdma_channels)
+			return -EBUSY;
+		set_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		chan = find_next_zero_bit(&drvdata->va_dma_ch_bit_map,
+					  v->va_wrdma_channel_start +
+					  v->va_wrdma_channels,
+					  v->va_wrdma_channel_start);
+		if (chan >= v->va_wrdma_channel_start + v->va_wrdma_channels)
+			return -EBUSY;
+		set_bit(chan, &drvdata->va_dma_ch_bit_map);
+		break;
+	default:
+		break;
+	}
+
+	return chan;
+}
+
+static int sc7280_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
+{
+	switch (dai_id) {
+	case MI2S_PRIMARY ... MI2S_QUINARY:
+		clear_bit(chan, &drvdata->dma_ch_bit_map);
+		break;
+	case LPASS_DP_RX:
+		clear_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
+		break;
+	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
+		clear_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
+		break;
+	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
+		clear_bit(chan, &drvdata->va_dma_ch_bit_map);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int sc7280_lpass_init(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct lpass_variant *variant = drvdata->variant;
+	struct device *dev = &pdev->dev;
+	int ret, i;
+
+	drvdata->clks = devm_kcalloc(dev, variant->num_clks,
+				     sizeof(*drvdata->clks), GFP_KERNEL);
+	if (!drvdata->clks)
+		return -ENOMEM;
+
+	drvdata->num_clks = variant->num_clks;
+
+	for (i = 0; i < drvdata->num_clks; i++)
+		drvdata->clks[i].id = variant->clk_name[i];
+
+	ret = devm_clk_bulk_get(dev, drvdata->num_clks, drvdata->clks);
+	if (ret) {
+		dev_err(dev, "Failed to get clocks %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks);
+	if (ret) {
+		dev_err(dev, "sc7280 clk_enable failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int sc7280_lpass_exit(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+	clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks);
+
+	return 0;
+}
+
+static struct lpass_variant sc7280_data = {
+	.i2sctrl_reg_base		= 0x1000,
+	.i2sctrl_reg_stride		= 0x1000,
+	.i2s_ports			= 3,
+	.irq_reg_base			= 0x9000,
+	.irq_reg_stride			= 0x1000,
+	.irq_ports			= 3,
+	.rdma_reg_base			= 0xC000,
+	.rdma_reg_stride		= 0x1000,
+	.rdma_channels			= 5,
+	.rxtx_rdma_reg_base		= 0xC000,
+	.rxtx_rdma_reg_stride		= 0x1000,
+	.rxtx_rdma_channels		= 8,
+	.hdmi_rdma_reg_base		= 0x64000,
+	.hdmi_rdma_reg_stride		= 0x1000,
+	.hdmi_rdma_channels		= 4,
+	.dmactl_audif_start		= 1,
+	.wrdma_reg_base			= 0x18000,
+	.wrdma_reg_stride		= 0x1000,
+	.wrdma_channel_start		= 5,
+	.wrdma_channels			= 4,
+	.rxtx_irq_reg_base		= 0x9000,
+	.rxtx_irq_reg_stride		= 0x1000,
+	.rxtx_irq_ports			= 3,
+	.rxtx_wrdma_reg_base		= 0x18000,
+	.rxtx_wrdma_reg_stride		= 0x1000,
+	.rxtx_wrdma_channel_start	= 5,
+	.rxtx_wrdma_channels		= 6,
+	.va_wrdma_reg_base		= 0x18000,
+	.va_wrdma_reg_stride		= 0x1000,
+	.va_wrdma_channel_start		= 5,
+	.va_wrdma_channels		= 3,
+	.va_irq_reg_base		= 0x9000,
+	.va_irq_reg_stride		= 0x1000,
+	.va_irq_ports			= 3,
+
+	.loopback			= REG_FIELD_ID(0x1000, 17, 17, 3, 0x1000),
+	.spken				= REG_FIELD_ID(0x1000, 16, 16, 3, 0x1000),
+	.spkmode			= REG_FIELD_ID(0x1000, 11, 15, 3, 0x1000),
+	.spkmono			= REG_FIELD_ID(0x1000, 10, 10, 3, 0x1000),
+	.micen				= REG_FIELD_ID(0x1000, 9, 9, 3, 0x1000),
+	.micmode			= REG_FIELD_ID(0x1000, 4, 8, 3, 0x1000),
+	.micmono			= REG_FIELD_ID(0x1000, 3, 3, 3, 0x1000),
+	.wssrc				= REG_FIELD_ID(0x1000, 2, 2, 3, 0x1000),
+	.bitwidth			= REG_FIELD_ID(0x1000, 0, 1, 3, 0x1000),
+
+	.rdma_dyncclk			= REG_FIELD_ID(0xC000, 21, 21, 5, 0x1000),
+	.rdma_bursten			= REG_FIELD_ID(0xC000, 20, 20, 5, 0x1000),
+	.rdma_wpscnt			= REG_FIELD_ID(0xC000, 16, 19, 5, 0x1000),
+	.rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 5, 0x1000),
+	.rdma_fifowm			= REG_FIELD_ID(0xC000, 1, 5, 5, 0x1000),
+	.rdma_enable			= REG_FIELD_ID(0xC000, 0, 0, 5, 0x1000),
+
+	.wrdma_dyncclk			= REG_FIELD_ID(0x18000, 22, 22, 4, 0x1000),
+	.wrdma_bursten			= REG_FIELD_ID(0x18000, 21, 21, 4, 0x1000),
+	.wrdma_wpscnt			= REG_FIELD_ID(0x18000, 17, 20, 4, 0x1000),
+	.wrdma_intf			= REG_FIELD_ID(0x18000, 12, 16, 4, 0x1000),
+	.wrdma_fifowm			= REG_FIELD_ID(0x18000, 1, 5, 4, 0x1000),
+	.wrdma_enable			= REG_FIELD_ID(0x18000, 0, 0, 4, 0x1000),
+
+	.rxtx_rdma_enable		= REG_FIELD_ID(0xC000, 0, 0, 7, 0x1000),
+	.rxtx_rdma_fifowm		= REG_FIELD_ID(0xC000, 1, 11, 7, 0x1000),
+	.rxtx_rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 7, 0x1000),
+	.rxtx_rdma_wpscnt		= REG_FIELD_ID(0xC000, 16, 19, 7, 0x1000),
+	.rxtx_rdma_bursten		= REG_FIELD_ID(0xC000, 20, 20, 7, 0x1000),
+	.rxtx_rdma_dyncclk		= REG_FIELD_ID(0xC000, 21, 21, 7, 0x1000),
+
+	.rxtx_rdma_codec_ch		= REG_FIELD_ID(0xC050, 0, 7, 7, 0x1000),
+	.rxtx_rdma_codec_intf		= REG_FIELD_ID(0xC050, 16, 19, 7, 0x1000),
+	.rxtx_rdma_codec_fs_delay	= REG_FIELD_ID(0xC050, 21, 24, 7, 0x1000),
+	.rxtx_rdma_codec_fs_sel		= REG_FIELD_ID(0xC050, 25, 27, 7, 0x1000),
+	.rxtx_rdma_codec_pack		= REG_FIELD_ID(0xC050, 29, 29, 5, 0x1000),
+	.rxtx_rdma_codec_enable		= REG_FIELD_ID(0xC050, 30, 30, 7, 0x1000),
+
+	.rxtx_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
+	.rxtx_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
+	.rxtx_wrdma_intf		= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
+	.rxtx_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
+	.rxtx_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
+	.rxtx_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
+
+	.rxtx_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
+	.rxtx_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
+	.rxtx_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
+	.rxtx_wrdma_codec_fs_sel	= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
+	.rxtx_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
+	.rxtx_wrdma_codec_enable	= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
+
+	.va_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
+	.va_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
+	.va_wrdma_intf			= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
+	.va_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
+	.va_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
+	.va_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
+
+	.va_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
+	.va_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
+	.va_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
+	.va_wrdma_codec_fs_sel		= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
+	.va_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
+	.va_wrdma_codec_enable		= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
+
+	.hdmi_tx_ctl_addr		= 0x1000,
+	.hdmi_legacy_addr		= 0x1008,
+	.hdmi_vbit_addr			= 0x610c0,
+	.hdmi_ch_lsb_addr		= 0x61048,
+	.hdmi_ch_msb_addr		= 0x6104c,
+	.ch_stride			= 0x8,
+	.hdmi_parity_addr		= 0x61034,
+	.hdmi_dmactl_addr		= 0x61038,
+	.hdmi_dma_stride		= 0x4,
+	.hdmi_DP_addr			= 0x610c8,
+	.hdmi_sstream_addr		= 0x6101c,
+	.hdmi_irq_reg_base		= 0x63000,
+	.hdmi_irq_ports			= 1,
+
+	.hdmi_rdma_dyncclk		= REG_FIELD_ID(0x64000, 14, 14, 4, 0x1000),
+	.hdmi_rdma_bursten		= REG_FIELD_ID(0x64000, 13, 13, 4, 0x1000),
+	.hdmi_rdma_burst8		= REG_FIELD_ID(0x64000, 15, 15, 4, 0x1000),
+	.hdmi_rdma_burst16		= REG_FIELD_ID(0x64000, 16, 16, 4, 0x1000),
+	.hdmi_rdma_dynburst		= REG_FIELD_ID(0x64000, 18, 18, 4, 0x1000),
+	.hdmi_rdma_wpscnt		= REG_FIELD_ID(0x64000, 10, 12, 4, 0x1000),
+	.hdmi_rdma_fifowm		= REG_FIELD_ID(0x64000, 1, 5, 4, 0x1000),
+	.hdmi_rdma_enable		= REG_FIELD_ID(0x64000, 0, 0, 4, 0x1000),
+
+	.sstream_en			= REG_FIELD(0x6101c, 0, 0),
+	.dma_sel			= REG_FIELD(0x6101c, 1, 2),
+	.auto_bbit_en			= REG_FIELD(0x6101c, 3, 3),
+	.layout				= REG_FIELD(0x6101c, 4, 4),
+	.layout_sp			= REG_FIELD(0x6101c, 5, 8),
+	.set_sp_on_en			= REG_FIELD(0x6101c, 10, 10),
+	.dp_audio			= REG_FIELD(0x6101c, 11, 11),
+	.dp_staffing_en			= REG_FIELD(0x6101c, 12, 12),
+	.dp_sp_b_hw_en			= REG_FIELD(0x6101c, 13, 13),
+
+	.mute				= REG_FIELD(0x610c8, 0, 0),
+	.as_sdp_cc			= REG_FIELD(0x610c8, 1, 3),
+	.as_sdp_ct			= REG_FIELD(0x610c8, 4, 7),
+	.aif_db4			= REG_FIELD(0x610c8, 8, 15),
+	.frequency			= REG_FIELD(0x610c8, 16, 21),
+	.mst_index			= REG_FIELD(0x610c8, 28, 29),
+	.dptx_index			= REG_FIELD(0x610c8, 30, 31),
+
+	.soft_reset			= REG_FIELD(0x1000, 31, 31),
+	.force_reset			= REG_FIELD(0x1000, 30, 30),
+
+	.use_hw_chs			= REG_FIELD(0x61038, 0, 0),
+	.use_hw_usr			= REG_FIELD(0x61038, 1, 1),
+	.hw_chs_sel			= REG_FIELD(0x61038, 2, 4),
+	.hw_usr_sel			= REG_FIELD(0x61038, 5, 6),
+
+	.replace_vbit			= REG_FIELD(0x610c0, 0, 0),
+	.vbit_stream			= REG_FIELD(0x610c0, 1, 1),
+
+	.legacy_en			=  REG_FIELD(0x1008, 0, 0),
+	.calc_en			=  REG_FIELD(0x61034, 0, 0),
+	.lsb_bits			=  REG_FIELD(0x61048, 0, 31),
+	.msb_bits			=  REG_FIELD(0x6104c, 0, 31),
+
+
+	.clk_name			= (const char*[]) {
+							"core_cc_sysnoc_mport_core"
+						},
+	.num_clks			= 1,
+	.cdc_dma_clk_names		= (const char*[]) {
+							"aon_cc_audio_hm_h",
+							"audio_cc_codec_mem",
+							"audio_cc_codec_mem0",
+							"audio_cc_codec_mem1",
+							"audio_cc_codec_mem2",
+							"aon_cc_va_mem0"
+							},
+	.cdc_dma_num_clks		= 6,
+	.dai_driver			= sc7280_lpass_cpu_dai_driver,
+	.num_dai			= ARRAY_SIZE(sc7280_lpass_cpu_dai_driver),
+	.dai_osr_clk_names		= (const char *[]) {
+							"audio_cc_ext_mclk0",
+							"null"
+							},
+	.dai_bit_clk_names		= (const char *[]) {
+							"core_cc_ext_if0_ibit",
+							"core_cc_ext_if1_ibit"
+							},
+	.init				= sc7280_lpass_init,
+	.exit				= sc7280_lpass_exit,
+	.alloc_dma_channel		= sc7280_lpass_alloc_dma_channel,
+	.free_dma_channel		= sc7280_lpass_free_dma_channel,
+};
+
+static const struct of_device_id sc7280_lpass_cpu_device_id[] = {
+	{.compatible = "qcom,sc7280-lpass-cpu", .data = &sc7280_data},
+	{}
+};
+MODULE_DEVICE_TABLE(of, sc7280_lpass_cpu_device_id);
+
+static struct platform_driver sc7280_lpass_cpu_platform_driver = {
+	.driver = {
+		.name = "sc7280-lpass-cpu",
+		.of_match_table = of_match_ptr(sc7280_lpass_cpu_device_id),
+	},
+	.probe = asoc_qcom_lpass_cpu_platform_probe,
+	.remove = asoc_qcom_lpass_cpu_platform_remove,
+	.shutdown = asoc_qcom_lpass_cpu_platform_shutdown,
+};
+
+module_platform_driver(sc7280_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("SC7280 LPASS CPU DRIVER");
+MODULE_LICENSE("GPL");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 03/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface
  2022-02-14 14:58 ` [RESEND v13 03/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface Srinivasa Rao Mandadapu
@ 2022-02-15  1:05   ` Stephen Boyd
  2022-02-16  4:58     ` Srinivasa Rao Mandadapu
  0 siblings, 1 reply; 28+ messages in thread
From: Stephen Boyd @ 2022-02-15  1:05 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:21)
> Add lpass interface memebers to support audio path over codec dma.
>
> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  sound/soc/qcom/lpass.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 116 insertions(+)
>
> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
> index f0d21cd..7cc3763 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h
> @@ -234,12 +294,66 @@ struct lpass_variant {
>         struct reg_field wrdma_enable;
>         struct reg_field wrdma_dyncclk;
>
> +       /*CDC RXTX RD_DMA */

Please add space after /*

> +       struct reg_field rxtx_rdma_intf;
> +       struct reg_field rxtx_rdma_bursten;
> +       struct reg_field rxtx_rdma_wpscnt;
> +       struct reg_field rxtx_rdma_fifowm;
> +       struct reg_field rxtx_rdma_enable;
> +       struct reg_field rxtx_rdma_dyncclk;
> +       struct reg_field rxtx_rdma_burst8;
> +       struct reg_field rxtx_rdma_burst16;
> +       struct reg_field rxtx_rdma_dynburst;
> +       struct reg_field rxtx_rdma_codec_enable;
> +       struct reg_field rxtx_rdma_codec_pack;
> +       struct reg_field rxtx_rdma_codec_intf;
> +       struct reg_field rxtx_rdma_codec_fs_sel;
> +       struct reg_field rxtx_rdma_codec_ch;
> +       struct reg_field rxtx_rdma_codec_fs_delay;
> +
> +       /*CDC RXTX WR_DMA */

Same

> +       struct reg_field rxtx_wrdma_intf;
> +       struct reg_field rxtx_wrdma_bursten;
> +       struct reg_field rxtx_wrdma_wpscnt;
> +       struct reg_field rxtx_wrdma_fifowm;
> +       struct reg_field rxtx_wrdma_enable;
> +       struct reg_field rxtx_wrdma_dyncclk;
> +       struct reg_field rxtx_wrdma_burst8;
> +       struct reg_field rxtx_wrdma_burst16;
> +       struct reg_field rxtx_wrdma_dynburst;
> +       struct reg_field rxtx_wrdma_codec_enable;
> +       struct reg_field rxtx_wrdma_codec_pack;
> +       struct reg_field rxtx_wrdma_codec_intf;
> +       struct reg_field rxtx_wrdma_codec_fs_sel;
> +       struct reg_field rxtx_wrdma_codec_ch;
> +       struct reg_field rxtx_wrdma_codec_fs_delay;
> +
> +       /*CDC VA WR_DMA */
> +       struct reg_field va_wrdma_intf;
> +       struct reg_field va_wrdma_bursten;
> +       struct reg_field va_wrdma_wpscnt;
> +       struct reg_field va_wrdma_fifowm;
> +       struct reg_field va_wrdma_enable;
> +       struct reg_field va_wrdma_dyncclk;
> +       struct reg_field va_wrdma_burst8;
> +       struct reg_field va_wrdma_burst16;
> +       struct reg_field va_wrdma_dynburst;
> +       struct reg_field va_wrdma_codec_enable;
> +       struct reg_field va_wrdma_codec_pack;
> +       struct reg_field va_wrdma_codec_intf;
> +       struct reg_field va_wrdma_codec_fs_sel;
> +       struct reg_field va_wrdma_codec_ch;
> +       struct reg_field va_wrdma_codec_fs_delay;
> +
>         /**

This shouldn't have two stars as it isn't kerneldoc

>          * on SOCs like APQ8016 the channel control bits start
>          * at different offset to ipq806x
>          **/
>         u32     dmactl_audif_start;
>         u32     wrdma_channel_start;
> +       u32     rxtx_wrdma_channel_start;
> +       u32     va_wrdma_channel_start;
> +
>         /* SOC specific initialization like clocks */
>         int (*init)(struct platform_device *pdev);
>         int (*exit)(struct platform_device *pdev);
> @@ -251,10 +365,12 @@ struct lpass_variant {
>         int num_dai;
>         const char * const *dai_osr_clk_names;
>         const char * const *dai_bit_clk_names;
> +       const char * const *cdc_dma_clk_names;
>
>         /* SOC specific clocks configuration */
>         const char **clk_name;
>         int num_clks;
> +       int cdc_dma_num_clks;

Why not size_t? Negative numbers are useful here?

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
  2022-02-14 14:58 ` [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle Srinivasa Rao Mandadapu
@ 2022-02-15  1:10   ` Stephen Boyd
  2022-02-16  5:11     ` Srinivasa Rao Mandadapu
  0 siblings, 1 reply; 28+ messages in thread
From: Stephen Boyd @ 2022-02-15  1:10 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:22)
> Add support function to get dma control and lpaif handle to avoid
> repeated code in platform driver
>
> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  sound/soc/qcom/lpass-platform.c | 113 +++++++++++++++++++++++-----------------
>  1 file changed, 66 insertions(+), 47 deletions(-)
>
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index a44162c..5d77240 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c
> @@ -177,6 +177,49 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>         return 0;
>  }
>
> +static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,

const?

> +                                    struct snd_soc_component *component,

const?

> +                                    struct lpaif_dmactl **dmactl, int *id, struct regmap **map)
> +{
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +       struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
> +       struct snd_pcm_runtime *rt = substream->runtime;
> +       struct lpass_pcm_data *pcm_data = rt->private_data;
> +       struct lpass_variant *v = drvdata->variant;
> +       int dir = substream->stream;
> +       unsigned int dai_id = cpu_dai->driver->id;
> +       struct lpaif_dmactl *l_dmactl = NULL;
> +       struct regmap *l_map = NULL;
> +       int l_id = 0;
> +
> +       switch (dai_id) {
> +       case MI2S_PRIMARY ... MI2S_QUINARY:
> +               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {

Please write if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) and
drop 'dir' local variable.

> +                       l_id = pcm_data->dma_ch;
> +                       l_dmactl = drvdata->rd_dmactl;
> +               } else {
> +                       l_dmactl = drvdata->wr_dmactl;
> +                       l_id = pcm_data->dma_ch - v->wrdma_channel_start;
> +               }
> +               l_map = drvdata->lpaif_map;
> +               break;
> +       case LPASS_DP_RX:
> +               l_id = pcm_data->dma_ch;
> +               l_dmactl = drvdata->hdmi_rd_dmactl;
> +               l_map = drvdata->hdmiif_map;
> +               break;
> +       default:
> +               break;
> +       }
> +       if (dmactl)
> +               *dmactl = l_dmactl;
> +       if (id)
> +               *id = l_id;
> +       if (map)
> +               *map = l_map;

Why not 'return 0' here and return -EINVAL in the default case above? Then
we can skip the checks for !map or !dmactl below and simply bail out if
it failed with an error value.

> +}
> +
>  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>                                            struct snd_pcm_substream *substream,
>                                            struct snd_pcm_hw_params *params)
> @@ -191,21 +234,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>         unsigned int channels = params_channels(params);
>         unsigned int regval;
>         struct lpaif_dmactl *dmactl;
> -       int id, dir = substream->stream;
> +       int id;
>         int bitwidth;
>         int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
>         unsigned int dai_id = cpu_dai->driver->id;
>
> -       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
> -               id = pcm_data->dma_ch;
> -               if (dai_id == LPASS_DP_RX)
> -                       dmactl = drvdata->hdmi_rd_dmactl;
> -               else
> -                       dmactl = drvdata->rd_dmactl;
> -
> -       } else {
> -               dmactl = drvdata->wr_dmactl;
> -               id = pcm_data->dma_ch - v->wrdma_channel_start;
> +       __lpass_get_lpaif_handle(substream, component, &dmactl, &id, NULL);
> +       if (!dmactl) {
> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> +               return -EINVAL;
>         }
>
>         bitwidth = snd_pcm_format_width(format);
> @@ -350,10 +387,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
>         struct regmap *map;
>         unsigned int dai_id = cpu_dai->driver->id;
>
> -       if (dai_id == LPASS_DP_RX)
> -               map = drvdata->hdmiif_map;
> -       else
> -               map = drvdata->lpaif_map;
> +       __lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
> +       if (!map) {
> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> +               return -EINVAL;
> +       }
>
>         reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
>         ret = regmap_write(map, reg, 0);
> @@ -379,22 +417,12 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
>         int ret, id, ch, dir = substream->stream;
>         unsigned int dai_id = cpu_dai->driver->id;
>
> -
>         ch = pcm_data->dma_ch;
> -       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
> -               if (dai_id == LPASS_DP_RX) {
> -                       dmactl = drvdata->hdmi_rd_dmactl;
> -                       map = drvdata->hdmiif_map;
> -               } else {
> -                       dmactl = drvdata->rd_dmactl;
> -                       map = drvdata->lpaif_map;
> -               }
>
> -               id = pcm_data->dma_ch;
> -       } else {
> -               dmactl = drvdata->wr_dmactl;
> -               id = pcm_data->dma_ch - v->wrdma_channel_start;
> -               map = drvdata->lpaif_map;
> +       __lpass_get_lpaif_handle(substream, component, &dmactl, &id, &map);
> +       if (!dmactl) {
> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> +               return -EINVAL;
>         }
>
>         ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
> @@ -444,25 +472,15 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>         struct lpaif_dmactl *dmactl;
>         struct regmap *map;
>         int ret, ch, id;
> -       int dir = substream->stream;
>         unsigned int reg_irqclr = 0, val_irqclr = 0;
>         unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
>         unsigned int dai_id = cpu_dai->driver->id;
>
>         ch = pcm_data->dma_ch;
> -       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
> -               id = pcm_data->dma_ch;
> -               if (dai_id == LPASS_DP_RX) {
> -                       dmactl = drvdata->hdmi_rd_dmactl;
> -                       map = drvdata->hdmiif_map;
> -               } else {
> -                       dmactl = drvdata->rd_dmactl;
> -                       map = drvdata->lpaif_map;
> -               }
> -       } else {
> -               dmactl = drvdata->wr_dmactl;
> -               id = pcm_data->dma_ch - v->wrdma_channel_start;
> -               map = drvdata->lpaif_map;
> +       __lpass_get_lpaif_handle(substream, component, &dmactl, &id, &map);
> +       if (!dmactl) {
> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> +               return -EINVAL;
>         }
>
>         switch (cmd) {
> @@ -597,10 +615,11 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
>         struct regmap *map;
>         unsigned int dai_id = cpu_dai->driver->id;
>
> -       if (dai_id == LPASS_DP_RX)
> -               map = drvdata->hdmiif_map;
> -       else
> -               map = drvdata->lpaif_map;
> +       __lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
> +       if (!map) {
> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> +               return -EINVAL;
> +       }
>
>         ch = pcm_data->dma_ch;
>
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 05/10] ASoC: qcom: Add register definition for codec rddma and wrdma
  2022-02-14 14:58 ` [RESEND v13 05/10] ASoC: qcom: Add register definition for codec rddma and wrdma Srinivasa Rao Mandadapu
@ 2022-02-15  1:12   ` Stephen Boyd
  2022-02-16  5:14     ` Srinivasa Rao Mandadapu
  0 siblings, 1 reply; 28+ messages in thread
From: Stephen Boyd @ 2022-02-15  1:12 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:23)
> This patch adds register definitions for codec read dma and write dma

 git grep "This patch" -- Documentation/process/

> lpass interface.
>
> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
> index 7cc3763..e059c4a 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h
> @@ -39,6 +39,29 @@
>                         return -EINVAL;         \
>         } while (0)
>
> +static inline bool is_cdc_dma_port(int dai_id)
> +{
> +       switch (dai_id) {
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               return true;
> +       default:

Drop case

> +               return false;
> +       }

return false;

would be shorter.

> +}
> +
> +static inline bool is_rxtx_cdc_dma_port(int dai_id)
> +{
> +       switch (dai_id) {
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               return true;
> +       default:
> +               return false;
> +       }

Same.

> +}
> +
>  struct lpaif_i2sctl {
>         struct regmap_field *loopback;
>         struct regmap_field *spken;

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 07/10] ASoC: qcom: Add support for codec dma driver
  2022-02-14 14:58 ` [RESEND v13 07/10] ASoC: qcom: Add " Srinivasa Rao Mandadapu
@ 2022-02-15  1:27   ` Stephen Boyd
  2022-02-16  6:53     ` Srinivasa Rao Mandadapu
  2022-02-16  6:42   ` kernel test robot
  2022-02-17 13:14   ` Dan Carpenter
  2 siblings, 1 reply; 28+ messages in thread
From: Stephen Boyd @ 2022-02-15  1:27 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:25)
> Upadate lpass cpu and platform driver to support audio over codec dma
> in ADSP bypass use case.
>
> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> Reported-by: kernel test robot <lkp@intel.com>
> ---
>  sound/soc/qcom/lpass-cpu.c      |  59 ++++-
>  sound/soc/qcom/lpass-platform.c | 499 ++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 537 insertions(+), 21 deletions(-)
>
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index 4fb9669..a5a46bc 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -1042,7 +1042,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
>                 }
>                 if (id == LPASS_DP_RX) {
>                         data->hdmi_port_enable = 1;
> -               } else {
> +               } else if (is_cdc_dma_port(id))

Please add braces if any of the other arms of the if statement have
braces

	} else if (is_cdc_dma_port(id)) {

> +                       data->codec_dma_enable = 1;
> +               else {


	} else {

>                         data->mi2s_playback_sd_mode[id] =
>                                 of_lpass_cpu_parse_sd_lines(dev, node,
>                                                             "qcom,playback-sd-lines");
> @@ -1057,6 +1059,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>  {
>         struct lpass_data *drvdata;
>         struct device_node *dsp_of_node;
> +       struct resource *res;
>         struct lpass_variant *variant;
>         struct device *dev = &pdev->dev;
>         const struct of_device_id *match;
> @@ -1082,6 +1085,58 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>
>         of_lpass_cpu_parse_dai_data(dev, drvdata);
>
> +       drvdata->num_clks =  variant->num_clks;
> +       if (drvdata->codec_dma_enable) {
> +               drvdata->rxtx_lpaif =
> +                               devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
> +               if (IS_ERR(drvdata->rxtx_lpaif))
> +                       return PTR_ERR(drvdata->rxtx_lpaif);
> +
> +               drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
> +               if (IS_ERR(drvdata->va_lpaif))
> +                       return PTR_ERR(drvdata->va_lpaif);
> +
> +               lpass_rxtx_regmap_config.max_register = LPAIF_CDC_RXTX_WRDMAPER_REG(variant,
> +                                       variant->rxtx_wrdma_channels +
> +                                       variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
> +
> +               drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
> +                                       &lpass_rxtx_regmap_config);
> +               if (IS_ERR(drvdata->rxtx_lpaif_map)) {
> +                       dev_err(dev, "error initializing rxtx regmap: %ld\n",
> +                               PTR_ERR(drvdata->rxtx_lpaif_map));

The regmap core already prints when things go wrong. Let's just use that
instead of adding another error message.

> +                       return PTR_ERR(drvdata->rxtx_lpaif_map);
> +               }
> +               lpass_va_regmap_config.max_register = LPAIF_CDC_VA_WRDMAPER_REG(variant,
> +                                       variant->va_wrdma_channels +
> +                                       variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
> +
> +               drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
> +                                       &lpass_va_regmap_config);
> +               if (IS_ERR(drvdata->va_lpaif_map)) {
> +                       dev_err(dev, "error initializing va regmap: %ld\n",
> +                               PTR_ERR(drvdata->va_lpaif_map));
> +                       return PTR_ERR(drvdata->va_lpaif_map);
> +               }
> +               drvdata->cdc_clks = devm_kcalloc(dev, variant->cdc_dma_num_clks,
> +                                       sizeof(*drvdata->cdc_clks), GFP_KERNEL);
> +               drvdata->cdc_num_clks = variant->cdc_dma_num_clks;
> +
> +               for (i = 0; i < drvdata->cdc_num_clks; i++)
> +                       drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
> +
> +               ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, drvdata->cdc_clks);

Do you care about particular clks? If not please use
devm_clk_bulk_get_all() and stop storing clk names and counts.

> +               if (ret) {
> +                       dev_err(dev, "Failed to get clocks %d\n", ret);
> +                       return ret;
> +               }
> +
> +               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
> +               drvdata->rxtx_cdc_dma_lpm_buf = res->start;
> +
> +               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
> +               drvdata->va_cdc_dma_lpm_buf = res->start;
> +       }
>         drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
>         if (IS_ERR(drvdata->lpaif))
>                 return PTR_ERR(drvdata->lpaif);
> @@ -1124,7 +1179,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>
>         for (i = 0; i < variant->num_dai; i++) {
>                 dai_id = variant->dai_driver[i].id;
> -               if (dai_id == LPASS_DP_RX)
> +               if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
>                         continue;
>
>                 drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index 5d77240..12b8d40 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c
> @@ -20,6 +20,9 @@
>
>  #define LPASS_PLATFORM_BUFFER_SIZE     (24 *  2 * 1024)
>  #define LPASS_PLATFORM_PERIODS         2
> +#define LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE (8 * 1024)
> +#define LPASS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
> +#define LPASS_CDC_DMA_REGISTER_FIELDS_MAX 15
>
>  static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>         .info                   =       SNDRV_PCM_INFO_MMAP |
> @@ -45,6 +48,99 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>         .fifo_size              =       0,
>  };
>
> +static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
> +       .info                   =       SNDRV_PCM_INFO_MMAP |
> +                                       SNDRV_PCM_INFO_MMAP_VALID |
> +                                       SNDRV_PCM_INFO_INTERLEAVED |
> +                                       SNDRV_PCM_INFO_PAUSE |
> +                                       SNDRV_PCM_INFO_RESUME,
> +       .formats                =       SNDRV_PCM_FMTBIT_S16 |
> +                                       SNDRV_PCM_FMTBIT_S24 |
> +                                       SNDRV_PCM_FMTBIT_S32,
> +       .rates                  =       SNDRV_PCM_RATE_8000_192000,
> +       .rate_min               =       8000,
> +       .rate_max               =       192000,
> +       .channels_min           =       1,
> +       .channels_max           =       8,
> +       .buffer_bytes_max       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
> +       .period_bytes_max       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
> +                                               LPASS_PLATFORM_PERIODS,
> +       .period_bytes_min       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
> +                                               LPASS_PLATFORM_PERIODS,
> +       .periods_min            =       LPASS_PLATFORM_PERIODS,
> +       .periods_max            =       LPASS_PLATFORM_PERIODS,
> +       .fifo_size              =       0,
> +};
> +
> +static const struct snd_pcm_hardware lpass_platform_va_hardware = {
> +       .info                   =       SNDRV_PCM_INFO_MMAP |
> +                                       SNDRV_PCM_INFO_MMAP_VALID |
> +                                       SNDRV_PCM_INFO_INTERLEAVED |
> +                                       SNDRV_PCM_INFO_PAUSE |
> +                                       SNDRV_PCM_INFO_RESUME,
> +       .formats                =       SNDRV_PCM_FMTBIT_S16 |
> +                                       SNDRV_PCM_FMTBIT_S24 |
> +                                       SNDRV_PCM_FMTBIT_S32,
> +       .rates                  =       SNDRV_PCM_RATE_8000_192000,
> +       .rate_min               =       8000,
> +       .rate_max               =       192000,
> +       .channels_min           =       1,
> +       .channels_max           =       8,
> +       .buffer_bytes_max       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE,
> +       .period_bytes_max       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
> +                                               LPASS_PLATFORM_PERIODS,
> +       .period_bytes_min       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
> +                                               LPASS_PLATFORM_PERIODS,
> +       .periods_min            =       LPASS_PLATFORM_PERIODS,
> +       .periods_max            =       LPASS_PLATFORM_PERIODS,
> +       .fifo_size              =       0,
> +};
> +
> +static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
> +                                        struct regmap *map)
> +{
> +       struct lpass_data *drvdata = dev_get_drvdata(dev);
> +       struct lpass_variant *v = drvdata->variant;
> +       struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
> +       int rval;
> +
> +       rd_dmactl = devm_kzalloc(dev, sizeof(*rd_dmactl), GFP_KERNEL);
> +       if (rd_dmactl == NULL)

	if (!rd_dmactl)

is kernel idiomatic. Please follow that style.

> +               return -ENOMEM;
> +
> +       wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
> +       if (wr_dmactl == NULL)
> +               return -ENOMEM;
> +
> +       drvdata->rxtx_rd_dmactl = rd_dmactl;
> +       drvdata->rxtx_wr_dmactl = wr_dmactl;
> +
> +       rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
> +                                           &v->rxtx_rdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
> +       if (rval)
> +               return rval;
> +
> +       return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
> +                                           &v->rxtx_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
> +}
> +
> +static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
> +                                        struct regmap *map)
> +{
> +       struct lpass_data *drvdata = dev_get_drvdata(dev);
> +       struct lpass_variant *v = drvdata->variant;
> +       struct lpaif_dmactl *wr_dmactl;
> +
> +       wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
> +       if (wr_dmactl == NULL)
> +               return -ENOMEM;
> +
> +       drvdata->va_wr_dmactl = wr_dmactl;
> +       return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
> +                                           &v->va_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
> +}
> +
> +
>  static int lpass_platform_alloc_dmactl_fields(struct device *dev,
>                                          struct regmap *map)
>  {
> @@ -123,25 +219,55 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
>                 return dma_ch;
>         }
>
> -       if (cpu_dai->driver->id == LPASS_DP_RX) {
> -               map = drvdata->hdmiif_map;
> -               drvdata->hdmi_substream[dma_ch] = substream;
> -       } else {
> +       switch (dai_id) {
> +       case MI2S_PRIMARY ... MI2S_QUINARY:
>                 map = drvdata->lpaif_map;
>                 drvdata->substream[dma_ch] = substream;
> +               break;
> +       case LPASS_DP_RX:
> +               map = drvdata->hdmiif_map;
> +               drvdata->hdmi_substream[dma_ch] = substream;
> +               break;
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               map = drvdata->rxtx_lpaif_map;
> +               drvdata->rxtx_substream[dma_ch] = substream;
> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               map = drvdata->va_lpaif_map;
> +               drvdata->va_substream[dma_ch] = substream;
> +               break;
> +       default:
> +               break;
>         }
> +
>         data->dma_ch = dma_ch;
> -       ret = regmap_write(map,
> -                       LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
> -       if (ret) {
> -               dev_err(soc_runtime->dev,
> -                       "error writing to rdmactl reg: %d\n", ret);
> -               return ret;
> +       switch (dai_id) {
> +       case MI2S_PRIMARY ... MI2S_QUINARY:
> +       case LPASS_DP_RX:
> +               ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
> +               if (ret) {
> +                       kfree(data);
> +                       dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret);
> +                       return ret;
> +               }
> +               snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
> +               runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
> +               break;
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
> +               runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> +               snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
> +               runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
> +               snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
> +               break;
> +       default:
> +               break;
>         }
> -       snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
> -
> -       runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
> -
>         ret = snd_pcm_hw_constraint_integer(runtime,
>                         SNDRV_PCM_HW_PARAM_PERIODS);
>         if (ret < 0) {
> @@ -166,10 +292,25 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>         unsigned int dai_id = cpu_dai->driver->id;
>
>         data = runtime->private_data;
> -       if (dai_id == LPASS_DP_RX)
> -               drvdata->hdmi_substream[data->dma_ch] = NULL;
> -       else
> +
> +       switch (dai_id) {
> +       case MI2S_PRIMARY ... MI2S_QUINARY:
>                 drvdata->substream[data->dma_ch] = NULL;
> +               break;
> +       case LPASS_DP_RX:
> +               drvdata->hdmi_substream[data->dma_ch] = NULL;
> +               break;
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               drvdata->rxtx_substream[data->dma_ch] = NULL;
> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               drvdata->va_substream[data->dma_ch] = NULL;
> +               break;
> +       default:
> +               break;
> +       }
> +
>         if (v->free_dma_channel)
>                 v->free_dma_channel(drvdata, data->dma_ch, dai_id);
>
> @@ -209,9 +350,25 @@ static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,
>                 l_dmactl = drvdata->hdmi_rd_dmactl;
>                 l_map = drvdata->hdmiif_map;
>                 break;
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +               l_id = pcm_data->dma_ch;
> +               l_dmactl = drvdata->rxtx_rd_dmactl;
> +               l_map = drvdata->rxtx_lpaif_map;
> +               break;
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
> +               l_dmactl = drvdata->rxtx_wr_dmactl;
> +               l_map = drvdata->rxtx_lpaif_map;
> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
> +               l_dmactl = drvdata->va_wr_dmactl;
> +               l_map = drvdata->va_lpaif_map;
> +               break;
>         default:
>                 break;
>         }
> +
>         if (dmactl)
>                 *dmactl = l_dmactl;
>         if (id)
> @@ -299,6 +456,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>                 }
>
>                 break;
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
> +               break;
>         default:
>                 dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
>                 break;
> @@ -387,6 +548,9 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
>         struct regmap *map;
>         unsigned int dai_id = cpu_dai->driver->id;
>
> +       if (is_cdc_dma_port(dai_id))
> +               return 0;
> +
>         __lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
>         if (!map) {
>                 dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> @@ -449,6 +613,14 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
>                 return ret;
>         }
>
> +       if (is_cdc_dma_port(dai_id)) {
> +               ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
> +               if (ret) {
> +                       dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",
> +                               ret, id);
> +                       return ret;
> +               }
> +       }
>         ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
>         if (ret) {
>                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
> @@ -532,6 +704,35 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>                         val_mask = LPAIF_IRQ_ALL(ch);
>                         val_irqen = LPAIF_IRQ_ALL(ch);
>                         break;
> +               case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +               case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
> +                       if (ret) {
> +                               dev_err(soc_runtime->dev,
> +                                       "error writing to rdmactl reg field: %d\n", ret);
> +                               return ret;
> +                       }
> +                       reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
> +
> +                       reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_mask = LPAIF_IRQ_ALL(ch);
> +                       val_irqen = LPAIF_IRQ_ALL(ch);
> +                       break;
> +               case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
> +                       if (ret) {
> +                               dev_err(soc_runtime->dev,
> +                                       "error writing to rdmactl reg field: %d\n", ret);
> +                               return ret;
> +                       }
> +                       reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
> +
> +                       reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_mask = LPAIF_IRQ_ALL(ch);
> +                       val_irqen = LPAIF_IRQ_ALL(ch);
> +                       break;
>                 default:
>                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
>                         return -EINVAL;
> @@ -583,6 +784,37 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>                         val_mask = LPAIF_IRQ_ALL(ch);
>                         val_irqen = 0;
>                         break;
> +               case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +               case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
> +                       if (ret) {
> +                               dev_err(soc_runtime->dev,
> +                                       "error writing to rdmactl reg field: %d\n", ret);
> +                               return ret;
> +                       }
> +
> +                       reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
> +
> +                       reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_mask = LPAIF_IRQ_ALL(ch);
> +                       val_irqen = LPAIF_IRQ_ALL(ch);
> +                       break;
> +               case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
> +                       if (ret) {
> +                               dev_err(soc_runtime->dev,
> +                                       "error writing to rdmactl reg field: %d\n", ret);
> +                               return ret;
> +                       }
> +
> +                       reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
> +
> +                       reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
> +                       val_mask = LPAIF_IRQ_ALL(ch);
> +                       val_irqen = LPAIF_IRQ_ALL(ch);
> +                       break;
>                 default:
>                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
>                         return -EINVAL;
> @@ -642,6 +874,39 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
>         return bytes_to_frames(substream->runtime, curr_addr - base_addr);
>  }
>
> +static int lpass_platform_cdc_dma_mmap(struct snd_soc_component *component,

'component' is not used.

> +                                      struct snd_pcm_substream *substream,
> +                                      struct vm_area_struct *vma)
> +{
> +       struct snd_pcm_runtime *runtime = substream->runtime;
> +       unsigned long size, offset;
> +
> +       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> +       size = vma->vm_end - vma->vm_start;
> +       offset = vma->vm_pgoff << PAGE_SHIFT;
> +       return io_remap_pfn_range(vma, vma->vm_start,
> +                       (runtime->dma_addr + offset) >> PAGE_SHIFT,
> +                       size, vma->vm_page_prot);
> +
> +}
> +
> +static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
> +                                     struct snd_pcm_substream *substream,
> +                                     struct vm_area_struct *vma)
> +{
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +       unsigned int dai_id = cpu_dai->driver->id;
> +       int err;
> +
> +       if (is_cdc_dma_port(dai_id))
> +               err = lpass_platform_cdc_dma_mmap(component, substream, vma);

return lpass_platform_cdc_dma_mmap(...)

> +       else

Drop else

> +               err = snd_pcm_lib_default_mmap(substream, vma);

return snd_pcm_lib_default_mmap(...)

> +
> +       return err;

err is no longer required.

> +}
> +
>  static irqreturn_t lpass_dma_interrupt_handler(
>                         struct snd_pcm_substream *substream,
>                         struct lpass_data *drvdata,
> @@ -674,6 +939,17 @@ static irqreturn_t lpass_dma_interrupt_handler(
>                 reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>                 val = 0;
>         break;
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               map = drvdata->rxtx_lpaif_map;
> +               reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
> +               val = 0;
> +       break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               map = drvdata->va_lpaif_map;
> +               reg = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
> +               val = 0;
> +       break;
>         default:
>         dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
>         return -EINVAL;
> @@ -781,18 +1057,122 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
>                                 return rv;
>                 }
>         }
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
> +{
> +       struct lpass_data *drvdata = data;
> +       struct lpass_variant *v = drvdata->variant;
> +       unsigned int irqs;
> +       int rv, chan;

Why is 'rv' int vs. irqreturn_t? Is something that isn't an irqreturn_t
type being returned from lpass_dma_interrupt_handler()? That's bad. If
the regmap read fails in the irq handler we are in pretty bad shape. I'd
say that we don't care to handle that case, or at the least, don't care
about the return value and can simply get out of this irq handler as
fast as possible.

> +
> +       rv = regmap_read(drvdata->rxtx_lpaif_map,
> +                       LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
> +       if (rv)
> +               return IRQ_NONE;
> +       /* Handle per channel interrupts */
> +       for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
> +               if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {
> +                       rv = lpass_dma_interrupt_handler(
> +                                               drvdata->rxtx_substream[chan],
> +                                               drvdata, chan, irqs);
> +                       if (rv != IRQ_HANDLED)
> +                               return rv;
> +               }
> +       }
>
>         return IRQ_HANDLED;
>  }
>
> +static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
> +{
> +       struct lpass_data *drvdata = data;
> +       struct lpass_variant *v = drvdata->variant;
> +       unsigned int irqs;
> +       int rv, chan;
> +
> +       rv = regmap_read(drvdata->va_lpaif_map,
> +                       LPAIF_VA_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
> +       if (rv)
> +               return IRQ_NONE;
> +       /* Handle per channel interrupts */
> +       for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
> +               if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {
> +                       rv = lpass_dma_interrupt_handler(
> +                                               drvdata->va_substream[chan],
> +                                               drvdata, chan, irqs);
> +                       if (rv != IRQ_HANDLED)
> +                               return rv;
> +               }
> +       }
> +       return IRQ_HANDLED;
> +}
> +
> +static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,
> +                                                 struct snd_pcm *pcm, int dai_id)
> +{
> +       struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
> +       struct snd_pcm_substream *substream;
> +       struct snd_dma_buffer *buf;
> +       int ret;
> +
> +       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
> +               substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
> +       else
> +               substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
> +
> +       ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(64));

Why isn't the dma mask setup for this device?

> +       if (ret)
> +               return ret;
> +
> +       buf = &substream->dma_buffer;
> +       buf->dev.dev = pcm->card->dev;
> +       buf->private_data = NULL;
> +
> +       /* Assign Codec DMA buffer pointers */
> +       buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
> +
> +       switch (dai_id) {
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +               buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> +               buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
> +               break;
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> +               buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
> +               buf->addr = drvdata->va_cdc_dma_lpm_buf;
> +               break;
> +       default:
> +               break;
> +       }
> +
> +       buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);

Why aren't we using the DMA mapping framework?

> +
> +       return 0;
> +}
> +
>  static int lpass_platform_pcm_new(struct snd_soc_component *component,
>                                   struct snd_soc_pcm_runtime *soc_runtime)
>  {
>         struct snd_pcm *pcm = soc_runtime->pcm;
> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +       unsigned int dai_id = cpu_dai->driver->id;
> +
>         size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
>
> -       return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
> -                                           component->dev, size);
> +       /*
> +        * Lpass codec dma can access only lpass lpm hardware memory.
> +        * ioremap is for HLOS to access hardware memory.
> +        */
> +       if (is_cdc_dma_port(dai_id))
> +               return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
> +       else
> +               return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
> +                                               component->dev, size);

else return is an anti-pattern. Please remove the else and deindent the
return.

>  }
>
>  static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
> @@ -827,6 +1207,31 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
>         return regcache_sync(map);
>  }
>
> +static int lpass_platform_copy(struct snd_soc_component *component,
> +                              struct snd_pcm_substream *substream, int channel,
> +                              unsigned long pos, void __user *buf, unsigned long bytes)
> +{
> +       struct snd_pcm_runtime *rt = substream->runtime;
> +       unsigned int dai_id = component->id;
> +       int ret = 0;
> +
> +       void __iomem *dma_buf = rt->dma_area + pos +
> +                               channel * (rt->dma_bytes / rt->channels);
> +
> +       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +               if (is_cdc_dma_port(dai_id))
> +                       ret = copy_from_user_toio(dma_buf, buf, bytes);
> +               else
> +                       ret = copy_from_user((void __force *)dma_buf, buf, bytes);
> +       } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> +               if (is_cdc_dma_port(dai_id))
> +                       ret = copy_to_user_fromio(buf, dma_buf, bytes);
> +               else
> +                       ret = copy_to_user(buf, (void __force *)dma_buf, bytes);

Having __force in here highlights the lack of DMA API usage. I guess
there's a sound dma wrapper library in sound/core/memalloc.c? Why can't
that be used?

> +       }
> +
> +       return ret;
> +}
>
>  static const struct snd_soc_component_driver lpass_component_driver = {
>         .name           = DRV_NAME,
> @@ -837,9 +1242,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
>         .prepare        = lpass_platform_pcmops_prepare,
>         .trigger        = lpass_platform_pcmops_trigger,
>         .pointer        = lpass_platform_pcmops_pointer,
> +       .mmap           = lpass_platform_pcmops_mmap,
>         .pcm_construct  = lpass_platform_pcm_new,
>         .suspend                = lpass_platform_pcmops_suspend,
>         .resume                 = lpass_platform_pcmops_resume,
> +       .copy_user              = lpass_platform_copy,
>
>  };
>
> @@ -877,6 +1284,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
>                 return ret;
>         }
>
> +       if (drvdata->codec_dma_enable) {
> +               ret = regmap_write(drvdata->rxtx_lpaif_map,
> +                       LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
> +                       return ret;
> +               }
> +               ret = regmap_write(drvdata->va_lpaif_map,
> +                       LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
> +                       return ret;
> +               }
> +               drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
> +               if (drvdata->rxtxif_irq < 0)
> +                       return -ENODEV;
> +
> +               ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
> +                               lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,

Drop flags and get it from firmware please.

> +                               "lpass-irq-rxtxif", drvdata);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
> +                       return ret;
> +               }
> +
> +               ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
> +                                                drvdata->rxtx_lpaif_map);
> +               if (ret) {
> +                       dev_err(&pdev->dev,
> +                               "error initializing rxtx dmactl fields: %d\n", ret);
> +                       return ret;
> +               }
> +
> +               drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");
> +               if (drvdata->vaif_irq < 0)
> +                       return -ENODEV;
> +
> +               ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
> +                               lpass_platform_vaif_irq, IRQF_TRIGGER_RISING,

Drop flags and get it from firmware please.

> +                               "lpass-irq-vaif", drvdata);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
> +                       return ret;
> +               }
> +
> +               ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
> +                                                drvdata->va_lpaif_map);
> +               if (ret) {
> +                       dev_err(&pdev->dev,
> +                               "error initializing va dmactl fields: %d\n", ret);
> +                       return ret;
> +               }
> +       }
> +
>         if (drvdata->hdmi_port_enable) {
>                 drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
>                 if (drvdata->hdmiif_irq < 0)
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control
  2022-02-14 14:58 ` [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control Srinivasa Rao Mandadapu
@ 2022-02-15  1:33   ` Stephen Boyd
  2022-02-16  9:42     ` Srinivasa Rao Mandadapu
  0 siblings, 1 reply; 28+ messages in thread
From: Stephen Boyd @ 2022-02-15  1:33 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:26)
> diff --git a/sound/soc/qcom/lpass-cdc-dma.c b/sound/soc/qcom/lpass-cdc-dma.c
> new file mode 100644
> index 0000000..4a50baa
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-cdc-dma.c
> @@ -0,0 +1,304 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2021 The Linux Foundation. All rights reserved.
> + *
> + * lpass-cdc-dma.c -- ALSA SoC CDC DMA CPU DAI driver for QTi LPASS
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>

export.h for EXPORT_SYMBOL usage.

> +#include <sound/soc.h>
> +#include <sound/soc-dai.h>
> +
> +#include "lpass-lpaif-reg.h"
> +#include "lpass.h"
> +
> +#define CODEC_MEM_FREQ_NORMAL 153600000

Is this in Hz? CODEC_MEM_HZ_NORMAL?

> +
> +enum codec_dma_interfaces {
> +       LPASS_CDC_DMA_INTERFACE1 = 1,
> +       LPASS_CDC_DMA_INTERFACE2,
> +       LPASS_CDC_DMA_INTERFACE3,
> +       LPASS_CDC_DMA_INTERFACE4,
> +       LPASS_CDC_DMA_INTERFACE5,
> +       LPASS_CDC_DMA_INTERFACE6,
> +       LPASS_CDC_DMA_INTERFACE7,
> +       LPASS_CDC_DMA_INTERFACE8,
> +       LPASS_CDC_DMA_INTERFACE9,
> +       LPASS_CDC_DMA_INTERFACE10,
> +};
> +
> +static void __lpass_get_dmactl_handle(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
> +                                     struct lpaif_dmactl **dmactl, int *id)
> +{
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +       struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +       struct snd_pcm_runtime *rt = substream->runtime;
> +       struct lpass_pcm_data *pcm_data = rt->private_data;
> +       struct lpass_variant *v = drvdata->variant;
> +       unsigned int dai_id = cpu_dai->driver->id;
> +
> +       switch (dai_id) {
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +               *dmactl = drvdata->rxtx_rd_dmactl;
> +               *id = pcm_data->dma_ch;
> +               break;
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               *dmactl = drvdata->rxtx_wr_dmactl;
> +               *id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> +               *dmactl = drvdata->va_wr_dmactl;
> +               *id = pcm_data->dma_ch - v->va_wrdma_channel_start;
> +               break;
> +       default:
> +               dev_err(soc_runtime->dev, "invalid dai id for dma ctl: %d\n", dai_id);
> +               break;
> +       }
> +}
> +
> +static int __lpass_get_codec_dma_intf_type(int dai_id)
> +{
> +       int ret;
> +
> +       switch (dai_id) {
> +       case LPASS_CDC_DMA_RX0:
> +       case LPASS_CDC_DMA_TX0:
> +       case LPASS_CDC_DMA_VA_TX0:
> +               ret = LPASS_CDC_DMA_INTERFACE1;
> +               break;
> +       case LPASS_CDC_DMA_RX1:
> +       case LPASS_CDC_DMA_TX1:
> +       case LPASS_CDC_DMA_VA_TX1:
> +               ret = LPASS_CDC_DMA_INTERFACE2;
> +               break;
> +       case LPASS_CDC_DMA_RX2:
> +       case LPASS_CDC_DMA_TX2:
> +       case LPASS_CDC_DMA_VA_TX2:
> +               ret = LPASS_CDC_DMA_INTERFACE3;
> +               break;
> +       case LPASS_CDC_DMA_RX3:
> +       case LPASS_CDC_DMA_TX3:
> +       case LPASS_CDC_DMA_VA_TX3:
> +               ret = LPASS_CDC_DMA_INTERFACE4;
> +               break;
> +       case LPASS_CDC_DMA_RX4:
> +       case LPASS_CDC_DMA_TX4:
> +       case LPASS_CDC_DMA_VA_TX4:
> +               ret = LPASS_CDC_DMA_INTERFACE5;
> +               break;
> +       case LPASS_CDC_DMA_RX5:
> +       case LPASS_CDC_DMA_TX5:
> +       case LPASS_CDC_DMA_VA_TX5:
> +               ret = LPASS_CDC_DMA_INTERFACE6;
> +               break;
> +       case LPASS_CDC_DMA_RX6:
> +       case LPASS_CDC_DMA_TX6:
> +       case LPASS_CDC_DMA_VA_TX6:
> +               ret = LPASS_CDC_DMA_INTERFACE7;
> +               break;
> +       case LPASS_CDC_DMA_RX7:
> +       case LPASS_CDC_DMA_TX7:
> +       case LPASS_CDC_DMA_VA_TX7:
> +               ret = LPASS_CDC_DMA_INTERFACE8;
> +               break;
> +       case LPASS_CDC_DMA_RX8:
> +       case LPASS_CDC_DMA_TX8:
> +       case LPASS_CDC_DMA_VA_TX8:
> +               ret = LPASS_CDC_DMA_INTERFACE9;
> +               break;
> +       case LPASS_CDC_DMA_RX9:
> +               ret  = LPASS_CDC_DMA_INTERFACE10;
> +               break;
> +       default:
> +               ret = -EINVAL;
> +               break;
> +       }
> +       return ret;
> +}
> +
> +static int __lpass_platform_codec_intf_init(struct snd_soc_dai *dai,
> +                                           struct snd_pcm_substream *substream)
> +{
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +       struct lpaif_dmactl *dmactl = NULL;
> +       struct device *dev = soc_runtime->dev;
> +       int ret, id, codec_intf;
> +       unsigned int dai_id = cpu_dai->driver->id;
> +
> +       codec_intf = __lpass_get_codec_dma_intf_type(dai_id);
> +       if (codec_intf < 0) {
> +               dev_err(dev, "failed to get codec_intf: %d\n", codec_intf);
> +               return codec_intf;
> +       }
> +
> +       __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
> +       if (!dmactl) {
> +               dev_err(dev, "failed to get dmactl handle for dai_id: %d\n", dai_id);
> +               return -EINVAL;
> +       }
> +
> +       ret = regmap_fields_write(dmactl->codec_intf, id, codec_intf);
> +       if (ret) {
> +               dev_err(dev, "error writing to dmactl codec_intf reg field: %d\n", ret);
> +               return ret;
> +       }
> +       ret = regmap_fields_write(dmactl->codec_fs_sel, id, 0x0);
> +       if (ret) {
> +               dev_err(dev, "error writing to dmactl codec_fs_sel reg field: %d\n", ret);
> +               return ret;
> +       }
> +       ret = regmap_fields_write(dmactl->codec_fs_delay, id, 0x0);
> +       if (ret) {
> +               dev_err(dev, "error writing to dmactl codec_fs_delay reg field: %d\n", ret);
> +               return ret;
> +       }
> +       ret = regmap_fields_write(dmactl->codec_pack, id, 0x1);
> +       if (ret) {
> +               dev_err(dev, "error writing to dmactl codec_pack reg field: %d\n", ret);
> +               return ret;
> +       }
> +       ret = regmap_fields_write(dmactl->codec_enable, id, LPAIF_DMACTL_ENABLE_ON);
> +       if (ret) {
> +               dev_err(dev, "error writing to dmactl codec_enable reg field: %d\n", ret);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static int lpass_cdc_dma_daiops_startup(struct snd_pcm_substream *substream,
> +                                   struct snd_soc_dai *dai)
> +{
> +       struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +
> +       switch (dai->id) {
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               clk_set_rate(drvdata->cdc_clks[2].clk, CODEC_MEM_FREQ_NORMAL);
> +               clk_prepare_enable(drvdata->cdc_clks[2].clk);

Where do '2' and '5' come from? Why are they part of the bulk clk array?
Why not get them separately and give them real named pointer values?

> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
> +               clk_set_rate(drvdata->cdc_clks[5].clk, CODEC_MEM_FREQ_NORMAL);
> +               clk_prepare_enable(drvdata->cdc_clks[5].clk);
> +               break;
> +       default:
> +               dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai->id);
> +               break;
> +       }
> +       return 0;
> +}
> +
> +static void lpass_cdc_dma_daiops_shutdown(struct snd_pcm_substream *substream,
> +                                     struct snd_soc_dai *dai)
> +{
> +       struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +
> +       switch (dai->id) {
> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> +               clk_disable_unprepare(drvdata->cdc_clks[2].clk);
> +               break;
> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
> +               clk_disable_unprepare(drvdata->cdc_clks[5].clk);
> +               break;
> +       default:
> +               dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai->id);
> +               break;
> +       }
> +}
> +
> +static int lpass_cdc_dma_daiops_hw_params(struct snd_pcm_substream *substream,
> +                                     struct snd_pcm_hw_params *params,
> +                                     struct snd_soc_dai *dai)
> +{
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +       struct lpaif_dmactl *dmactl = NULL;
> +       unsigned int ret, regval;
> +       unsigned int channels = params_channels(params);
> +       int id;
> +
> +       switch (channels) {
> +       case 1:
> +               regval = LPASS_CDC_DMA_INTF_ONE_CHANNEL;
> +               break;
> +       case 2:
> +               regval = LPASS_CDC_DMA_INTF_TWO_CHANNEL;
> +               break;
> +       case 4:
> +               regval = LPASS_CDC_DMA_INTF_FOUR_CHANNEL;
> +               break;
> +       case 6:
> +               regval = LPASS_CDC_DMA_INTF_SIX_CHANNEL;
> +               break;
> +       case 8:
> +               regval = LPASS_CDC_DMA_INTF_EIGHT_CHANNEL;
> +               break;
> +       default:
> +               dev_err(soc_runtime->dev, "invalid PCM config\n");
> +               return -EINVAL;
> +       }
> +
> +       __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
> +       if (!dmactl) {
> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> +               return -EINVAL;
> +       }
> +       ret = regmap_fields_write(dmactl->codec_channel, id, regval);
> +       if (ret) {
> +               dev_err(soc_runtime->dev,
> +                       "error writing to dmactl codec_channel reg field: %d\n", ret);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static int lpass_cdc_dma_daiops_trigger(struct snd_pcm_substream *substream,
> +                                   int cmd, struct snd_soc_dai *dai)
> +{
> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +       struct lpaif_dmactl *dmactl;
> +       int ret = 0, id;
> +
> +       switch (cmd) {
> +       case SNDRV_PCM_TRIGGER_START:
> +       case SNDRV_PCM_TRIGGER_RESUME:
> +       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +               __lpass_platform_codec_intf_init(dai, substream);
> +               break;
> +       case SNDRV_PCM_TRIGGER_STOP:
> +       case SNDRV_PCM_TRIGGER_SUSPEND:
> +       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +               __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
> +               if (!dmactl) {
> +                       dev_err(soc_runtime->dev, "failed to get dmactl handle\n");

This same message is in many places. I really hope it never gets printed
because finding out which line it got printed at is going to be
impossible.

> +                       return -EINVAL;
> +               }
> +               ret = regmap_fields_write(dmactl->codec_enable, id, LPAIF_DMACTL_ENABLE_OFF);
> +               if (ret) {
> +                       dev_err(soc_runtime->dev,
> +                               "error writing to dmactl codec_enable reg: %d\n", ret);
> +                       return ret;
> +               }
> +               break;
> +       default:
> +               ret = -EINVAL;
> +               dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, cmd);
> +               break;
> +       }
> +       return ret;
> +}
> +
> +const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops = {
> +       .startup        = lpass_cdc_dma_daiops_startup,
> +       .shutdown       = lpass_cdc_dma_daiops_shutdown,
> +       .hw_params      = lpass_cdc_dma_daiops_hw_params,
> +       .trigger        = lpass_cdc_dma_daiops_trigger,
> +};
> +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cdc_dma_dai_ops);
> +
> +MODULE_DESCRIPTION("QTi LPASS CDC DMA Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
> index e059c4a..d279a72 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h
> @@ -410,5 +410,6 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
>  extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
>  int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
>                                 struct snd_soc_dai *dai);
> +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops;
>
>  #endif /* __LPASS_H__ */
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 03/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface
  2022-02-15  1:05   ` Stephen Boyd
@ 2022-02-16  4:58     ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-16  4:58 UTC (permalink / raw)
  To: Stephen Boyd, agross, alsa-devel, bgoswami, bjorn.andersson,
	broonie, devicetree, judyhsiao, lgirdwood, linux-arm-msm,
	linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu


On 2/15/2022 6:35 AM, Stephen Boyd wrote:
Thanks for your time Stephen!!!
> Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:21)
>> Add lpass interface memebers to support audio path over codec dma.
>>
>> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
>> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>>   sound/soc/qcom/lpass.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 116 insertions(+)
>>
>> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
>> index f0d21cd..7cc3763 100644
>> --- a/sound/soc/qcom/lpass.h
>> +++ b/sound/soc/qcom/lpass.h
>> @@ -234,12 +294,66 @@ struct lpass_variant {
>>          struct reg_field wrdma_enable;
>>          struct reg_field wrdma_dyncclk;
>>
>> +       /*CDC RXTX RD_DMA */
> Please add space after /*
Okay. Will change it.
>
>> +       struct reg_field rxtx_rdma_intf;
>> +       struct reg_field rxtx_rdma_bursten;
>> +       struct reg_field rxtx_rdma_wpscnt;
>> +       struct reg_field rxtx_rdma_fifowm;
>> +       struct reg_field rxtx_rdma_enable;
>> +       struct reg_field rxtx_rdma_dyncclk;
>> +       struct reg_field rxtx_rdma_burst8;
>> +       struct reg_field rxtx_rdma_burst16;
>> +       struct reg_field rxtx_rdma_dynburst;
>> +       struct reg_field rxtx_rdma_codec_enable;
>> +       struct reg_field rxtx_rdma_codec_pack;
>> +       struct reg_field rxtx_rdma_codec_intf;
>> +       struct reg_field rxtx_rdma_codec_fs_sel;
>> +       struct reg_field rxtx_rdma_codec_ch;
>> +       struct reg_field rxtx_rdma_codec_fs_delay;
>> +
>> +       /*CDC RXTX WR_DMA */
> Same
Okay.
>
>> +       struct reg_field rxtx_wrdma_intf;
>> +       struct reg_field rxtx_wrdma_bursten;
>> +       struct reg_field rxtx_wrdma_wpscnt;
>> +       struct reg_field rxtx_wrdma_fifowm;
>> +       struct reg_field rxtx_wrdma_enable;
>> +       struct reg_field rxtx_wrdma_dyncclk;
>> +       struct reg_field rxtx_wrdma_burst8;
>> +       struct reg_field rxtx_wrdma_burst16;
>> +       struct reg_field rxtx_wrdma_dynburst;
>> +       struct reg_field rxtx_wrdma_codec_enable;
>> +       struct reg_field rxtx_wrdma_codec_pack;
>> +       struct reg_field rxtx_wrdma_codec_intf;
>> +       struct reg_field rxtx_wrdma_codec_fs_sel;
>> +       struct reg_field rxtx_wrdma_codec_ch;
>> +       struct reg_field rxtx_wrdma_codec_fs_delay;
>> +
>> +       /*CDC VA WR_DMA */
>> +       struct reg_field va_wrdma_intf;
>> +       struct reg_field va_wrdma_bursten;
>> +       struct reg_field va_wrdma_wpscnt;
>> +       struct reg_field va_wrdma_fifowm;
>> +       struct reg_field va_wrdma_enable;
>> +       struct reg_field va_wrdma_dyncclk;
>> +       struct reg_field va_wrdma_burst8;
>> +       struct reg_field va_wrdma_burst16;
>> +       struct reg_field va_wrdma_dynburst;
>> +       struct reg_field va_wrdma_codec_enable;
>> +       struct reg_field va_wrdma_codec_pack;
>> +       struct reg_field va_wrdma_codec_intf;
>> +       struct reg_field va_wrdma_codec_fs_sel;
>> +       struct reg_field va_wrdma_codec_ch;
>> +       struct reg_field va_wrdma_codec_fs_delay;
>> +
>>          /**
> This shouldn't have two stars as it isn't kerneldoc
Actually this not part of this patch.
>
>>           * on SOCs like APQ8016 the channel control bits start
>>           * at different offset to ipq806x
>>           **/
>>          u32     dmactl_audif_start;
>>          u32     wrdma_channel_start;
>> +       u32     rxtx_wrdma_channel_start;
>> +       u32     va_wrdma_channel_start;
>> +
>>          /* SOC specific initialization like clocks */
>>          int (*init)(struct platform_device *pdev);
>>          int (*exit)(struct platform_device *pdev);
>> @@ -251,10 +365,12 @@ struct lpass_variant {
>>          int num_dai;
>>          const char * const *dai_osr_clk_names;
>>          const char * const *dai_bit_clk_names;
>> +       const char * const *cdc_dma_clk_names;
>>
>>          /* SOC specific clocks configuration */
>>          const char **clk_name;
>>          int num_clks;
>> +       int cdc_dma_num_clks;
> Why not size_t? Negative numbers are useful here?
Okay. As negative numbers are not useful here, will change to size_t.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
  2022-02-15  1:10   ` Stephen Boyd
@ 2022-02-16  5:11     ` Srinivasa Rao Mandadapu
  2022-02-17 19:41       ` Stephen Boyd
  0 siblings, 1 reply; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-16  5:11 UTC (permalink / raw)
  To: Stephen Boyd, agross, alsa-devel, bgoswami, bjorn.andersson,
	broonie, devicetree, judyhsiao, lgirdwood, linux-arm-msm,
	linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu


On 2/15/2022 6:40 AM, Stephen Boyd wrote:
Thanks for your time Stephen!!!
> Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:22)
>> Add support function to get dma control and lpaif handle to avoid
>> repeated code in platform driver
>>
>> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
>> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>>   sound/soc/qcom/lpass-platform.c | 113 +++++++++++++++++++++++-----------------
>>   1 file changed, 66 insertions(+), 47 deletions(-)
>>
>> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
>> index a44162c..5d77240 100644
>> --- a/sound/soc/qcom/lpass-platform.c
>> +++ b/sound/soc/qcom/lpass-platform.c
>> @@ -177,6 +177,49 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>>          return 0;
>>   }
>>
>> +static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,
> const?
Okay. will add const to substream pointer.
>
>> +                                    struct snd_soc_component *component,
> const?
Here const is giving compilation errors in below code.
>
>> +                                    struct lpaif_dmactl **dmactl, int *id, struct regmap **map)
>> +{
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
>> +       struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
>> +       struct snd_pcm_runtime *rt = substream->runtime;
>> +       struct lpass_pcm_data *pcm_data = rt->private_data;
>> +       struct lpass_variant *v = drvdata->variant;
>> +       int dir = substream->stream;
>> +       unsigned int dai_id = cpu_dai->driver->id;
>> +       struct lpaif_dmactl *l_dmactl = NULL;
>> +       struct regmap *l_map = NULL;
>> +       int l_id = 0;
>> +
>> +       switch (dai_id) {
>> +       case MI2S_PRIMARY ... MI2S_QUINARY:
>> +               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
> Please write if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) and
> drop 'dir' local variable.
Okay. will change it.
>
>> +                       l_id = pcm_data->dma_ch;
>> +                       l_dmactl = drvdata->rd_dmactl;
>> +               } else {
>> +                       l_dmactl = drvdata->wr_dmactl;
>> +                       l_id = pcm_data->dma_ch - v->wrdma_channel_start;
>> +               }
>> +               l_map = drvdata->lpaif_map;
>> +               break;
>> +       case LPASS_DP_RX:
>> +               l_id = pcm_data->dma_ch;
>> +               l_dmactl = drvdata->hdmi_rd_dmactl;
>> +               l_map = drvdata->hdmiif_map;
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +       if (dmactl)
>> +               *dmactl = l_dmactl;
>> +       if (id)
>> +               *id = l_id;
>> +       if (map)
>> +               *map = l_map;
> Why not 'return 0' here and return -EINVAL in the default case above? Then
> we can skip the checks for !map or !dmactl below and simply bail out if
> it failed with an error value.

Here the check is for input params. some users call for only damctl or 
only map.

so check seems mandatory for updating only valid fields. Will remove 
default case which may never occurs.

>
>> +}
>> +
>>   static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>>                                             struct snd_pcm_substream *substream,
>>                                             struct snd_pcm_hw_params *params)
>> @@ -191,21 +234,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>>          unsigned int channels = params_channels(params);
>>          unsigned int regval;
>>          struct lpaif_dmactl *dmactl;
>> -       int id, dir = substream->stream;
>> +       int id;
>>          int bitwidth;
>>          int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
>>          unsigned int dai_id = cpu_dai->driver->id;
>>
>> -       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
>> -               id = pcm_data->dma_ch;
>> -               if (dai_id == LPASS_DP_RX)
>> -                       dmactl = drvdata->hdmi_rd_dmactl;
>> -               else
>> -                       dmactl = drvdata->rd_dmactl;
>> -
>> -       } else {
>> -               dmactl = drvdata->wr_dmactl;
>> -               id = pcm_data->dma_ch - v->wrdma_channel_start;
>> +       __lpass_get_lpaif_handle(substream, component, &dmactl, &id, NULL);
>> +       if (!dmactl) {
>> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>> +               return -EINVAL;
>>          }
>>
>>          bitwidth = snd_pcm_format_width(format);
>> @@ -350,10 +387,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
>>          struct regmap *map;
>>          unsigned int dai_id = cpu_dai->driver->id;
>>
>> -       if (dai_id == LPASS_DP_RX)
>> -               map = drvdata->hdmiif_map;
>> -       else
>> -               map = drvdata->lpaif_map;
>> +       __lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
>> +       if (!map) {
>> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>> +               return -EINVAL;
>> +       }
>>
>>          reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
>>          ret = regmap_write(map, reg, 0);
>> @@ -379,22 +417,12 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
>>          int ret, id, ch, dir = substream->stream;
>>          unsigned int dai_id = cpu_dai->driver->id;
>>
>> -
>>          ch = pcm_data->dma_ch;
>> -       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
>> -               if (dai_id == LPASS_DP_RX) {
>> -                       dmactl = drvdata->hdmi_rd_dmactl;
>> -                       map = drvdata->hdmiif_map;
>> -               } else {
>> -                       dmactl = drvdata->rd_dmactl;
>> -                       map = drvdata->lpaif_map;
>> -               }
>>
>> -               id = pcm_data->dma_ch;
>> -       } else {
>> -               dmactl = drvdata->wr_dmactl;
>> -               id = pcm_data->dma_ch - v->wrdma_channel_start;
>> -               map = drvdata->lpaif_map;
>> +       __lpass_get_lpaif_handle(substream, component, &dmactl, &id, &map);
>> +       if (!dmactl) {
>> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>> +               return -EINVAL;
>>          }
>>
>>          ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
>> @@ -444,25 +472,15 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>>          struct lpaif_dmactl *dmactl;
>>          struct regmap *map;
>>          int ret, ch, id;
>> -       int dir = substream->stream;
>>          unsigned int reg_irqclr = 0, val_irqclr = 0;
>>          unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
>>          unsigned int dai_id = cpu_dai->driver->id;
>>
>>          ch = pcm_data->dma_ch;
>> -       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
>> -               id = pcm_data->dma_ch;
>> -               if (dai_id == LPASS_DP_RX) {
>> -                       dmactl = drvdata->hdmi_rd_dmactl;
>> -                       map = drvdata->hdmiif_map;
>> -               } else {
>> -                       dmactl = drvdata->rd_dmactl;
>> -                       map = drvdata->lpaif_map;
>> -               }
>> -       } else {
>> -               dmactl = drvdata->wr_dmactl;
>> -               id = pcm_data->dma_ch - v->wrdma_channel_start;
>> -               map = drvdata->lpaif_map;
>> +       __lpass_get_lpaif_handle(substream, component, &dmactl, &id, &map);
>> +       if (!dmactl) {
>> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>> +               return -EINVAL;
>>          }
>>
>>          switch (cmd) {
>> @@ -597,10 +615,11 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
>>          struct regmap *map;
>>          unsigned int dai_id = cpu_dai->driver->id;
>>
>> -       if (dai_id == LPASS_DP_RX)
>> -               map = drvdata->hdmiif_map;
>> -       else
>> -               map = drvdata->lpaif_map;
>> +       __lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
>> +       if (!map) {
>> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>> +               return -EINVAL;
>> +       }
>>
>>          ch = pcm_data->dma_ch;
>>
>> --
>> 2.7.4
>>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 05/10] ASoC: qcom: Add register definition for codec rddma and wrdma
  2022-02-15  1:12   ` Stephen Boyd
@ 2022-02-16  5:14     ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-16  5:14 UTC (permalink / raw)
  To: Stephen Boyd, agross, alsa-devel, bgoswami, bjorn.andersson,
	broonie, devicetree, judyhsiao, lgirdwood, linux-arm-msm,
	linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu


On 2/15/2022 6:42 AM, Stephen Boyd wrote:
Thanks for your time Stephen!!!
> Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:23)
>> This patch adds register definitions for codec read dma and write dma
>   git grep "This patch" -- Documentation/process/
Okay. Will remove and reword the commit message.
>
>> lpass interface.
>>
>> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
>> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
>> index 7cc3763..e059c4a 100644
>> --- a/sound/soc/qcom/lpass.h
>> +++ b/sound/soc/qcom/lpass.h
>> @@ -39,6 +39,29 @@
>>                          return -EINVAL;         \
>>          } while (0)
>>
>> +static inline bool is_cdc_dma_port(int dai_id)
>> +{
>> +       switch (dai_id) {
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               return true;
>> +       default:
> Drop case
Okay. will remove it.
>
>> +               return false;
>> +       }
> return false;
>
> would be shorter.
Okay. will change it.
>
>> +}
>> +
>> +static inline bool is_rxtx_cdc_dma_port(int dai_id)
>> +{
>> +       switch (dai_id) {
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               return true;
>> +       default:
>> +               return false;
>> +       }
> Same.
Okay.
>
>> +}
>> +
>>   struct lpaif_i2sctl {
>>          struct regmap_field *loopback;
>>          struct regmap_field *spken;

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 07/10] ASoC: qcom: Add support for codec dma driver
  2022-02-14 14:58 ` [RESEND v13 07/10] ASoC: qcom: Add " Srinivasa Rao Mandadapu
  2022-02-15  1:27   ` Stephen Boyd
@ 2022-02-16  6:42   ` kernel test robot
  2022-02-17 13:14   ` Dan Carpenter
  2 siblings, 0 replies; 28+ messages in thread
From: kernel test robot @ 2022-02-16  6:42 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, bjorn.andersson, lgirdwood,
	broonie, robh+dt, quic_plai, bgoswami, perex, tiwai,
	srinivas.kandagatla, rohitkr, linux-arm-msm, alsa-devel,
	devicetree, linux-kernel, swboyd, judyhsiao
  Cc: kbuild-all, Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Hi Srinivasa,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on v5.17-rc4 next-20220215]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Srinivasa-Rao-Mandadapu/Add-support-for-audio-on-SC7280-based-targets/20220214-230256
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: csky-randconfig-s032-20220216 (https://download.01.org/0day-ci/archive/20220216/202202161407.5MOObZwm-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 11.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # apt-get install sparse
        # sparse version: v0.6.4-dirty
        # https://github.com/0day-ci/linux/commit/e81c7e5d842d2b8039700a71557683e88ce0162d
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Srinivasa-Rao-Mandadapu/Add-support-for-audio-on-SC7280-based-targets/20220214-230256
        git checkout e81c7e5d842d2b8039700a71557683e88ce0162d
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=csky SHELL=/bin/bash sound/soc/qcom/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
>> sound/soc/qcom/lpass-platform.c:1218:52: sparse: sparse: incorrect type in initializer (different address spaces) @@     expected void [noderef] __iomem *dma_buf @@     got unsigned char * @@
   sound/soc/qcom/lpass-platform.c:1218:52: sparse:     expected void [noderef] __iomem *dma_buf
   sound/soc/qcom/lpass-platform.c:1218:52: sparse:     got unsigned char *

vim +1218 sound/soc/qcom/lpass-platform.c

  1209	
  1210	static int lpass_platform_copy(struct snd_soc_component *component,
  1211				       struct snd_pcm_substream *substream, int channel,
  1212				       unsigned long pos, void __user *buf, unsigned long bytes)
  1213	{
  1214		struct snd_pcm_runtime *rt = substream->runtime;
  1215		unsigned int dai_id = component->id;
  1216		int ret = 0;
  1217	
> 1218		void __iomem *dma_buf = rt->dma_area + pos +
  1219					channel * (rt->dma_bytes / rt->channels);
  1220	
  1221		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  1222			if (is_cdc_dma_port(dai_id))
  1223				ret = copy_from_user_toio(dma_buf, buf, bytes);
  1224			else
  1225				ret = copy_from_user((void __force *)dma_buf, buf, bytes);
  1226		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  1227			if (is_cdc_dma_port(dai_id))
  1228				ret = copy_to_user_fromio(buf, dma_buf, bytes);
  1229			else
  1230				ret = copy_to_user(buf, (void __force *)dma_buf, bytes);
  1231		}
  1232	
  1233		return ret;
  1234	}
  1235	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 07/10] ASoC: qcom: Add support for codec dma driver
  2022-02-15  1:27   ` Stephen Boyd
@ 2022-02-16  6:53     ` Srinivasa Rao Mandadapu
  2022-02-17 19:50       ` Stephen Boyd
  0 siblings, 1 reply; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-16  6:53 UTC (permalink / raw)
  To: Stephen Boyd, agross, alsa-devel, bgoswami, bjorn.andersson,
	broonie, devicetree, judyhsiao, lgirdwood, linux-arm-msm,
	linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu


On 2/15/2022 6:57 AM, Stephen Boyd wrote:
Thanks for your time and valuable review comments Stephen!!!
> Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:25)
>> Upadate lpass cpu and platform driver to support audio over codec dma
>> in ADSP bypass use case.
>>
>> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
>> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>> Reported-by: kernel test robot <lkp@intel.com>
>> ---
>>   sound/soc/qcom/lpass-cpu.c      |  59 ++++-
>>   sound/soc/qcom/lpass-platform.c | 499 ++++++++++++++++++++++++++++++++++++++--
>>   2 files changed, 537 insertions(+), 21 deletions(-)
>>
>> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
>> index 4fb9669..a5a46bc 100644
>> --- a/sound/soc/qcom/lpass-cpu.c
>> +++ b/sound/soc/qcom/lpass-cpu.c
>> @@ -1042,7 +1042,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
>>                  }
>>                  if (id == LPASS_DP_RX) {
>>                          data->hdmi_port_enable = 1;
>> -               } else {
>> +               } else if (is_cdc_dma_port(id))
> Please add braces if any of the other arms of the if statement have
> braces
Okay.
>
> 	} else if (is_cdc_dma_port(id)) {
>
>> +                       data->codec_dma_enable = 1;
>> +               else {
>
> 	} else {
>
>>                          data->mi2s_playback_sd_mode[id] =
>>                                  of_lpass_cpu_parse_sd_lines(dev, node,
>>                                                              "qcom,playback-sd-lines");
>> @@ -1057,6 +1059,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>>   {
>>          struct lpass_data *drvdata;
>>          struct device_node *dsp_of_node;
>> +       struct resource *res;
>>          struct lpass_variant *variant;
>>          struct device *dev = &pdev->dev;
>>          const struct of_device_id *match;
>> @@ -1082,6 +1085,58 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>>
>>          of_lpass_cpu_parse_dai_data(dev, drvdata);
>>
>> +       drvdata->num_clks =  variant->num_clks;
>> +       if (drvdata->codec_dma_enable) {
>> +               drvdata->rxtx_lpaif =
>> +                               devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
>> +               if (IS_ERR(drvdata->rxtx_lpaif))
>> +                       return PTR_ERR(drvdata->rxtx_lpaif);
>> +
>> +               drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
>> +               if (IS_ERR(drvdata->va_lpaif))
>> +                       return PTR_ERR(drvdata->va_lpaif);
>> +
>> +               lpass_rxtx_regmap_config.max_register = LPAIF_CDC_RXTX_WRDMAPER_REG(variant,
>> +                                       variant->rxtx_wrdma_channels +
>> +                                       variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
>> +
>> +               drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
>> +                                       &lpass_rxtx_regmap_config);
>> +               if (IS_ERR(drvdata->rxtx_lpaif_map)) {
>> +                       dev_err(dev, "error initializing rxtx regmap: %ld\n",
>> +                               PTR_ERR(drvdata->rxtx_lpaif_map));
> The regmap core already prints when things go wrong. Let's just use that
> instead of adding another error message.
Okay. Will remove print here.
>
>> +                       return PTR_ERR(drvdata->rxtx_lpaif_map);
>> +               }
>> +               lpass_va_regmap_config.max_register = LPAIF_CDC_VA_WRDMAPER_REG(variant,
>> +                                       variant->va_wrdma_channels +
>> +                                       variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
>> +
>> +               drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
>> +                                       &lpass_va_regmap_config);
>> +               if (IS_ERR(drvdata->va_lpaif_map)) {
>> +                       dev_err(dev, "error initializing va regmap: %ld\n",
>> +                               PTR_ERR(drvdata->va_lpaif_map));
>> +                       return PTR_ERR(drvdata->va_lpaif_map);
>> +               }
>> +               drvdata->cdc_clks = devm_kcalloc(dev, variant->cdc_dma_num_clks,
>> +                                       sizeof(*drvdata->cdc_clks), GFP_KERNEL);
>> +               drvdata->cdc_num_clks = variant->cdc_dma_num_clks;
>> +
>> +               for (i = 0; i < drvdata->cdc_num_clks; i++)
>> +                       drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
>> +
>> +               ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, drvdata->cdc_clks);
> Do you care about particular clks? If not please use
> devm_clk_bulk_get_all() and stop storing clk names and counts.
Yes, individual clocks are required in cdc dma driver.  Will change 
individual clock voting with naming.
>
>> +               if (ret) {
>> +                       dev_err(dev, "Failed to get clocks %d\n", ret);
>> +                       return ret;
>> +               }
>> +
>> +               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
>> +               drvdata->rxtx_cdc_dma_lpm_buf = res->start;
>> +
>> +               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
>> +               drvdata->va_cdc_dma_lpm_buf = res->start;
>> +       }
>>          drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
>>          if (IS_ERR(drvdata->lpaif))
>>                  return PTR_ERR(drvdata->lpaif);
>> @@ -1124,7 +1179,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>>
>>          for (i = 0; i < variant->num_dai; i++) {
>>                  dai_id = variant->dai_driver[i].id;
>> -               if (dai_id == LPASS_DP_RX)
>> +               if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
>>                          continue;
>>
>>                  drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
>> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
>> index 5d77240..12b8d40 100644
>> --- a/sound/soc/qcom/lpass-platform.c
>> +++ b/sound/soc/qcom/lpass-platform.c
>> @@ -20,6 +20,9 @@
>>
>>   #define LPASS_PLATFORM_BUFFER_SIZE     (24 *  2 * 1024)
>>   #define LPASS_PLATFORM_PERIODS         2
>> +#define LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE (8 * 1024)
>> +#define LPASS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
>> +#define LPASS_CDC_DMA_REGISTER_FIELDS_MAX 15
>>
>>   static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>>          .info                   =       SNDRV_PCM_INFO_MMAP |
>> @@ -45,6 +48,99 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>>          .fifo_size              =       0,
>>   };
>>
>> +static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
>> +       .info                   =       SNDRV_PCM_INFO_MMAP |
>> +                                       SNDRV_PCM_INFO_MMAP_VALID |
>> +                                       SNDRV_PCM_INFO_INTERLEAVED |
>> +                                       SNDRV_PCM_INFO_PAUSE |
>> +                                       SNDRV_PCM_INFO_RESUME,
>> +       .formats                =       SNDRV_PCM_FMTBIT_S16 |
>> +                                       SNDRV_PCM_FMTBIT_S24 |
>> +                                       SNDRV_PCM_FMTBIT_S32,
>> +       .rates                  =       SNDRV_PCM_RATE_8000_192000,
>> +       .rate_min               =       8000,
>> +       .rate_max               =       192000,
>> +       .channels_min           =       1,
>> +       .channels_max           =       8,
>> +       .buffer_bytes_max       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
>> +       .period_bytes_max       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
>> +                                               LPASS_PLATFORM_PERIODS,
>> +       .period_bytes_min       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
>> +                                               LPASS_PLATFORM_PERIODS,
>> +       .periods_min            =       LPASS_PLATFORM_PERIODS,
>> +       .periods_max            =       LPASS_PLATFORM_PERIODS,
>> +       .fifo_size              =       0,
>> +};
>> +
>> +static const struct snd_pcm_hardware lpass_platform_va_hardware = {
>> +       .info                   =       SNDRV_PCM_INFO_MMAP |
>> +                                       SNDRV_PCM_INFO_MMAP_VALID |
>> +                                       SNDRV_PCM_INFO_INTERLEAVED |
>> +                                       SNDRV_PCM_INFO_PAUSE |
>> +                                       SNDRV_PCM_INFO_RESUME,
>> +       .formats                =       SNDRV_PCM_FMTBIT_S16 |
>> +                                       SNDRV_PCM_FMTBIT_S24 |
>> +                                       SNDRV_PCM_FMTBIT_S32,
>> +       .rates                  =       SNDRV_PCM_RATE_8000_192000,
>> +       .rate_min               =       8000,
>> +       .rate_max               =       192000,
>> +       .channels_min           =       1,
>> +       .channels_max           =       8,
>> +       .buffer_bytes_max       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE,
>> +       .period_bytes_max       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
>> +                                               LPASS_PLATFORM_PERIODS,
>> +       .period_bytes_min       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
>> +                                               LPASS_PLATFORM_PERIODS,
>> +       .periods_min            =       LPASS_PLATFORM_PERIODS,
>> +       .periods_max            =       LPASS_PLATFORM_PERIODS,
>> +       .fifo_size              =       0,
>> +};
>> +
>> +static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
>> +                                        struct regmap *map)
>> +{
>> +       struct lpass_data *drvdata = dev_get_drvdata(dev);
>> +       struct lpass_variant *v = drvdata->variant;
>> +       struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
>> +       int rval;
>> +
>> +       rd_dmactl = devm_kzalloc(dev, sizeof(*rd_dmactl), GFP_KERNEL);
>> +       if (rd_dmactl == NULL)
> 	if (!rd_dmactl)
>
> is kernel idiomatic. Please follow that style.
Okay. will change.
>
>> +               return -ENOMEM;
>> +
>> +       wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
>> +       if (wr_dmactl == NULL)
>> +               return -ENOMEM;
>> +
>> +       drvdata->rxtx_rd_dmactl = rd_dmactl;
>> +       drvdata->rxtx_wr_dmactl = wr_dmactl;
>> +
>> +       rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
>> +                                           &v->rxtx_rdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
>> +       if (rval)
>> +               return rval;
>> +
>> +       return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
>> +                                           &v->rxtx_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
>> +}
>> +
>> +static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
>> +                                        struct regmap *map)
>> +{
>> +       struct lpass_data *drvdata = dev_get_drvdata(dev);
>> +       struct lpass_variant *v = drvdata->variant;
>> +       struct lpaif_dmactl *wr_dmactl;
>> +
>> +       wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
>> +       if (wr_dmactl == NULL)
>> +               return -ENOMEM;
>> +
>> +       drvdata->va_wr_dmactl = wr_dmactl;
>> +       return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
>> +                                           &v->va_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
>> +}
>> +
>> +
>>   static int lpass_platform_alloc_dmactl_fields(struct device *dev,
>>                                           struct regmap *map)
>>   {
>> @@ -123,25 +219,55 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
>>                  return dma_ch;
>>          }
>>
>> -       if (cpu_dai->driver->id == LPASS_DP_RX) {
>> -               map = drvdata->hdmiif_map;
>> -               drvdata->hdmi_substream[dma_ch] = substream;
>> -       } else {
>> +       switch (dai_id) {
>> +       case MI2S_PRIMARY ... MI2S_QUINARY:
>>                  map = drvdata->lpaif_map;
>>                  drvdata->substream[dma_ch] = substream;
>> +               break;
>> +       case LPASS_DP_RX:
>> +               map = drvdata->hdmiif_map;
>> +               drvdata->hdmi_substream[dma_ch] = substream;
>> +               break;
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               map = drvdata->rxtx_lpaif_map;
>> +               drvdata->rxtx_substream[dma_ch] = substream;
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               map = drvdata->va_lpaif_map;
>> +               drvdata->va_substream[dma_ch] = substream;
>> +               break;
>> +       default:
>> +               break;
>>          }
>> +
>>          data->dma_ch = dma_ch;
>> -       ret = regmap_write(map,
>> -                       LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
>> -       if (ret) {
>> -               dev_err(soc_runtime->dev,
>> -                       "error writing to rdmactl reg: %d\n", ret);
>> -               return ret;
>> +       switch (dai_id) {
>> +       case MI2S_PRIMARY ... MI2S_QUINARY:
>> +       case LPASS_DP_RX:
>> +               ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
>> +               if (ret) {
>> +                       kfree(data);
>> +                       dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret);
>> +                       return ret;
>> +               }
>> +               snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
>> +               runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
>> +               break;
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
>> +               runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
>> +               snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
>> +               runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
>> +               snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
>> +               break;
>> +       default:
>> +               break;
>>          }
>> -       snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
>> -
>> -       runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
>> -
>>          ret = snd_pcm_hw_constraint_integer(runtime,
>>                          SNDRV_PCM_HW_PARAM_PERIODS);
>>          if (ret < 0) {
>> @@ -166,10 +292,25 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>>          unsigned int dai_id = cpu_dai->driver->id;
>>
>>          data = runtime->private_data;
>> -       if (dai_id == LPASS_DP_RX)
>> -               drvdata->hdmi_substream[data->dma_ch] = NULL;
>> -       else
>> +
>> +       switch (dai_id) {
>> +       case MI2S_PRIMARY ... MI2S_QUINARY:
>>                  drvdata->substream[data->dma_ch] = NULL;
>> +               break;
>> +       case LPASS_DP_RX:
>> +               drvdata->hdmi_substream[data->dma_ch] = NULL;
>> +               break;
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               drvdata->rxtx_substream[data->dma_ch] = NULL;
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               drvdata->va_substream[data->dma_ch] = NULL;
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +
>>          if (v->free_dma_channel)
>>                  v->free_dma_channel(drvdata, data->dma_ch, dai_id);
>>
>> @@ -209,9 +350,25 @@ static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,
>>                  l_dmactl = drvdata->hdmi_rd_dmactl;
>>                  l_map = drvdata->hdmiif_map;
>>                  break;
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +               l_id = pcm_data->dma_ch;
>> +               l_dmactl = drvdata->rxtx_rd_dmactl;
>> +               l_map = drvdata->rxtx_lpaif_map;
>> +               break;
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
>> +               l_dmactl = drvdata->rxtx_wr_dmactl;
>> +               l_map = drvdata->rxtx_lpaif_map;
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
>> +               l_dmactl = drvdata->va_wr_dmactl;
>> +               l_map = drvdata->va_lpaif_map;
>> +               break;
>>          default:
>>                  break;
>>          }
>> +
>>          if (dmactl)
>>                  *dmactl = l_dmactl;
>>          if (id)
>> @@ -299,6 +456,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>>                  }
>>
>>                  break;
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
>> +               break;
>>          default:
>>                  dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
>>                  break;
>> @@ -387,6 +548,9 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
>>          struct regmap *map;
>>          unsigned int dai_id = cpu_dai->driver->id;
>>
>> +       if (is_cdc_dma_port(dai_id))
>> +               return 0;
>> +
>>          __lpass_get_lpaif_handle(substream, component, NULL, NULL, &map);
>>          if (!map) {
>>                  dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>> @@ -449,6 +613,14 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
>>                  return ret;
>>          }
>>
>> +       if (is_cdc_dma_port(dai_id)) {
>> +               ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
>> +               if (ret) {
>> +                       dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",
>> +                               ret, id);
>> +                       return ret;
>> +               }
>> +       }
>>          ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
>>          if (ret) {
>>                  dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
>> @@ -532,6 +704,35 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>>                          val_mask = LPAIF_IRQ_ALL(ch);
>>                          val_irqen = LPAIF_IRQ_ALL(ch);
>>                          break;
>> +               case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +               case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
>> +                       if (ret) {
>> +                               dev_err(soc_runtime->dev,
>> +                                       "error writing to rdmactl reg field: %d\n", ret);
>> +                               return ret;
>> +                       }
>> +                       reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
>> +
>> +                       reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_mask = LPAIF_IRQ_ALL(ch);
>> +                       val_irqen = LPAIF_IRQ_ALL(ch);
>> +                       break;
>> +               case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
>> +                       if (ret) {
>> +                               dev_err(soc_runtime->dev,
>> +                                       "error writing to rdmactl reg field: %d\n", ret);
>> +                               return ret;
>> +                       }
>> +                       reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
>> +
>> +                       reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_mask = LPAIF_IRQ_ALL(ch);
>> +                       val_irqen = LPAIF_IRQ_ALL(ch);
>> +                       break;
>>                  default:
>>                          dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
>>                          return -EINVAL;
>> @@ -583,6 +784,37 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>>                          val_mask = LPAIF_IRQ_ALL(ch);
>>                          val_irqen = 0;
>>                          break;
>> +               case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +               case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
>> +                       if (ret) {
>> +                               dev_err(soc_runtime->dev,
>> +                                       "error writing to rdmactl reg field: %d\n", ret);
>> +                               return ret;
>> +                       }
>> +
>> +                       reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
>> +
>> +                       reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_mask = LPAIF_IRQ_ALL(ch);
>> +                       val_irqen = LPAIF_IRQ_ALL(ch);
>> +                       break;
>> +               case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +                       ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
>> +                       if (ret) {
>> +                               dev_err(soc_runtime->dev,
>> +                                       "error writing to rdmactl reg field: %d\n", ret);
>> +                               return ret;
>> +                       }
>> +
>> +                       reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_irqclr = LPAIF_IRQ_ALL(ch);
>> +
>> +                       reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
>> +                       val_mask = LPAIF_IRQ_ALL(ch);
>> +                       val_irqen = LPAIF_IRQ_ALL(ch);
>> +                       break;
>>                  default:
>>                          dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
>>                          return -EINVAL;
>> @@ -642,6 +874,39 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
>>          return bytes_to_frames(substream->runtime, curr_addr - base_addr);
>>   }
>>
>> +static int lpass_platform_cdc_dma_mmap(struct snd_soc_component *component,
> 'component' is not used.
Okay. will remove it.
>
>> +                                      struct snd_pcm_substream *substream,
>> +                                      struct vm_area_struct *vma)
>> +{
>> +       struct snd_pcm_runtime *runtime = substream->runtime;
>> +       unsigned long size, offset;
>> +
>> +       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
>> +       size = vma->vm_end - vma->vm_start;
>> +       offset = vma->vm_pgoff << PAGE_SHIFT;
>> +       return io_remap_pfn_range(vma, vma->vm_start,
>> +                       (runtime->dma_addr + offset) >> PAGE_SHIFT,
>> +                       size, vma->vm_page_prot);
>> +
>> +}
>> +
>> +static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
>> +                                     struct snd_pcm_substream *substream,
>> +                                     struct vm_area_struct *vma)
>> +{
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
>> +       unsigned int dai_id = cpu_dai->driver->id;
>> +       int err;
>> +
>> +       if (is_cdc_dma_port(dai_id))
>> +               err = lpass_platform_cdc_dma_mmap(component, substream, vma);
> return lpass_platform_cdc_dma_mmap(...)
Okay. Will change it.
>
>> +       else
> Drop else
Okay.
>
>> +               err = snd_pcm_lib_default_mmap(substream, vma);
> return snd_pcm_lib_default_mmap(...)
Okay.
>
>> +
>> +       return err;
> err is no longer required.
Okay. will remove it.
>
>> +}
>> +
>>   static irqreturn_t lpass_dma_interrupt_handler(
>>                          struct snd_pcm_substream *substream,
>>                          struct lpass_data *drvdata,
>> @@ -674,6 +939,17 @@ static irqreturn_t lpass_dma_interrupt_handler(
>>                  reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>>                  val = 0;
>>          break;
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               map = drvdata->rxtx_lpaif_map;
>> +               reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>> +               val = 0;
>> +       break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               map = drvdata->va_lpaif_map;
>> +               reg = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
>> +               val = 0;
>> +       break;
>>          default:
>>          dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
>>          return -EINVAL;
>> @@ -781,18 +1057,122 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
>>                                  return rv;
>>                  }
>>          }
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
>> +{
>> +       struct lpass_data *drvdata = data;
>> +       struct lpass_variant *v = drvdata->variant;
>> +       unsigned int irqs;
>> +       int rv, chan;
> Why is 'rv' int vs. irqreturn_t? Is something that isn't an irqreturn_t
> type being returned from lpass_dma_interrupt_handler()? That's bad. If
> the regmap read fails in the irq handler we are in pretty bad shape. I'd
> say that we don't care to handle that case, or at the least, don't care
> about the return value and can simply get out of this irq handler as
> fast as possible.
Okay.  will change accordingly.
>
>> +
>> +       rv = regmap_read(drvdata->rxtx_lpaif_map,
>> +                       LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
>> +       if (rv)
>> +               return IRQ_NONE;
>> +       /* Handle per channel interrupts */
>> +       for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
>> +               if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {
>> +                       rv = lpass_dma_interrupt_handler(
>> +                                               drvdata->rxtx_substream[chan],
>> +                                               drvdata, chan, irqs);
>> +                       if (rv != IRQ_HANDLED)
>> +                               return rv;
>> +               }
>> +       }
>>
>>          return IRQ_HANDLED;
>>   }
>>
>> +static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
>> +{
>> +       struct lpass_data *drvdata = data;
>> +       struct lpass_variant *v = drvdata->variant;
>> +       unsigned int irqs;
>> +       int rv, chan;
>> +
>> +       rv = regmap_read(drvdata->va_lpaif_map,
>> +                       LPAIF_VA_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
>> +       if (rv)
>> +               return IRQ_NONE;
>> +       /* Handle per channel interrupts */
>> +       for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
>> +               if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {
>> +                       rv = lpass_dma_interrupt_handler(
>> +                                               drvdata->va_substream[chan],
>> +                                               drvdata, chan, irqs);
>> +                       if (rv != IRQ_HANDLED)
>> +                               return rv;
>> +               }
>> +       }
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,
>> +                                                 struct snd_pcm *pcm, int dai_id)
>> +{
>> +       struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
>> +       struct snd_pcm_substream *substream;
>> +       struct snd_dma_buffer *buf;
>> +       int ret;
>> +
>> +       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
>> +               substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
>> +       else
>> +               substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
>> +
>> +       ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(64));
> Why isn't the dma mask setup for this device?
Okay. It seems redundant here.  Will remove it.
>
>> +       if (ret)
>> +               return ret;
>> +
>> +       buf = &substream->dma_buffer;
>> +       buf->dev.dev = pcm->card->dev;
>> +       buf->private_data = NULL;
>> +
>> +       /* Assign Codec DMA buffer pointers */
>> +       buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
>> +
>> +       switch (dai_id) {
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +               buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
>> +               buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
>> +               break;
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
>> +               buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
>> +               buf->addr = drvdata->va_cdc_dma_lpm_buf;
>> +               break;
>> +       default:
>> +               break;
>> +       }
>> +
>> +       buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
> Why aren't we using the DMA mapping framework?
Here, Need to use hardware memory, that is LPASS LPM region for codec DMA.
>
>> +
>> +       return 0;
>> +}
>> +
>>   static int lpass_platform_pcm_new(struct snd_soc_component *component,
>>                                    struct snd_soc_pcm_runtime *soc_runtime)
>>   {
>>          struct snd_pcm *pcm = soc_runtime->pcm;
>> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
>> +       unsigned int dai_id = cpu_dai->driver->id;
>> +
>>          size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
>>
>> -       return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
>> -                                           component->dev, size);
>> +       /*
>> +        * Lpass codec dma can access only lpass lpm hardware memory.
>> +        * ioremap is for HLOS to access hardware memory.
>> +        */
>> +       if (is_cdc_dma_port(dai_id))
>> +               return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
>> +       else
>> +               return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
>> +                                               component->dev, size);
> else return is an anti-pattern. Please remove the else and deindent the
> return.
Okay. Will change it.
>
>>   }
>>
>>   static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
>> @@ -827,6 +1207,31 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
>>          return regcache_sync(map);
>>   }
>>
>> +static int lpass_platform_copy(struct snd_soc_component *component,
>> +                              struct snd_pcm_substream *substream, int channel,
>> +                              unsigned long pos, void __user *buf, unsigned long bytes)
>> +{
>> +       struct snd_pcm_runtime *rt = substream->runtime;
>> +       unsigned int dai_id = component->id;
>> +       int ret = 0;
>> +
>> +       void __iomem *dma_buf = rt->dma_area + pos +
>> +                               channel * (rt->dma_bytes / rt->channels);
>> +
>> +       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> +               if (is_cdc_dma_port(dai_id))
>> +                       ret = copy_from_user_toio(dma_buf, buf, bytes);
>> +               else
>> +                       ret = copy_from_user((void __force *)dma_buf, buf, bytes);
>> +       } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
>> +               if (is_cdc_dma_port(dai_id))
>> +                       ret = copy_to_user_fromio(buf, dma_buf, bytes);
>> +               else
>> +                       ret = copy_to_user(buf, (void __force *)dma_buf, bytes);
> Having __force in here highlights the lack of DMA API usage. I guess
> there's a sound dma wrapper library in sound/core/memalloc.c? Why can't
> that be used?
Didn't see any memcopy wrapper functions in memalloc.c. Could You please 
elaborate or share some example.
>
>> +       }
>> +
>> +       return ret;
>> +}
>>
>>   static const struct snd_soc_component_driver lpass_component_driver = {
>>          .name           = DRV_NAME,
>> @@ -837,9 +1242,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
>>          .prepare        = lpass_platform_pcmops_prepare,
>>          .trigger        = lpass_platform_pcmops_trigger,
>>          .pointer        = lpass_platform_pcmops_pointer,
>> +       .mmap           = lpass_platform_pcmops_mmap,
>>          .pcm_construct  = lpass_platform_pcm_new,
>>          .suspend                = lpass_platform_pcmops_suspend,
>>          .resume                 = lpass_platform_pcmops_resume,
>> +       .copy_user              = lpass_platform_copy,
>>
>>   };
>>
>> @@ -877,6 +1284,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
>>                  return ret;
>>          }
>>
>> +       if (drvdata->codec_dma_enable) {
>> +               ret = regmap_write(drvdata->rxtx_lpaif_map,
>> +                       LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
>> +                       return ret;
>> +               }
>> +               ret = regmap_write(drvdata->va_lpaif_map,
>> +                       LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
>> +                       return ret;
>> +               }
>> +               drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
>> +               if (drvdata->rxtxif_irq < 0)
>> +                       return -ENODEV;
>> +
>> +               ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
>> +                               lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,
> Drop flags and get it from firmware please.
Same is followed in existing for other i2s and HDMI interrupts. Could 
You please give some example if it's really matters?
>
>> +                               "lpass-irq-rxtxif", drvdata);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
>> +                       return ret;
>> +               }
>> +
>> +               ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
>> +                                                drvdata->rxtx_lpaif_map);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev,
>> +                               "error initializing rxtx dmactl fields: %d\n", ret);
>> +                       return ret;
>> +               }
>> +
>> +               drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");
>> +               if (drvdata->vaif_irq < 0)
>> +                       return -ENODEV;
>> +
>> +               ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
>> +                               lpass_platform_vaif_irq, IRQF_TRIGGER_RISING,
> Drop flags and get it from firmware please.
Some Example Please!!!
>
>> +                               "lpass-irq-vaif", drvdata);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
>> +                       return ret;
>> +               }
>> +
>> +               ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
>> +                                                drvdata->va_lpaif_map);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev,
>> +                               "error initializing va dmactl fields: %d\n", ret);
>> +                       return ret;
>> +               }
>> +       }
>> +
>>          if (drvdata->hdmi_port_enable) {
>>                  drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
>>                  if (drvdata->hdmiif_irq < 0)
>> --
>> 2.7.4
>>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control
  2022-02-15  1:33   ` Stephen Boyd
@ 2022-02-16  9:42     ` Srinivasa Rao Mandadapu
  2022-02-17 19:53       ` Stephen Boyd
  0 siblings, 1 reply; 28+ messages in thread
From: Srinivasa Rao Mandadapu @ 2022-02-16  9:42 UTC (permalink / raw)
  To: Stephen Boyd, agross, alsa-devel, bgoswami, bjorn.andersson,
	broonie, devicetree, judyhsiao, lgirdwood, linux-arm-msm,
	linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu


On 2/15/2022 7:03 AM, Stephen Boyd wrote:
Thanks for your time Stephen!!!
> Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:26)
>> diff --git a/sound/soc/qcom/lpass-cdc-dma.c b/sound/soc/qcom/lpass-cdc-dma.c
>> new file mode 100644
>> index 0000000..4a50baa
>> --- /dev/null
>> +++ b/sound/soc/qcom/lpass-cdc-dma.c
>> @@ -0,0 +1,304 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2021 The Linux Foundation. All rights reserved.
>> + *
>> + * lpass-cdc-dma.c -- ALSA SoC CDC DMA CPU DAI driver for QTi LPASS
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/module.h>
> export.h for EXPORT_SYMBOL usage.
>
>> +#include <sound/soc.h>
>> +#include <sound/soc-dai.h>
>> +
>> +#include "lpass-lpaif-reg.h"
>> +#include "lpass.h"
>> +
>> +#define CODEC_MEM_FREQ_NORMAL 153600000
> Is this in Hz? CODEC_MEM_HZ_NORMAL?
Okay. Will change accordingly.
>
>> +
>> +enum codec_dma_interfaces {
>> +       LPASS_CDC_DMA_INTERFACE1 = 1,
>> +       LPASS_CDC_DMA_INTERFACE2,
>> +       LPASS_CDC_DMA_INTERFACE3,
>> +       LPASS_CDC_DMA_INTERFACE4,
>> +       LPASS_CDC_DMA_INTERFACE5,
>> +       LPASS_CDC_DMA_INTERFACE6,
>> +       LPASS_CDC_DMA_INTERFACE7,
>> +       LPASS_CDC_DMA_INTERFACE8,
>> +       LPASS_CDC_DMA_INTERFACE9,
>> +       LPASS_CDC_DMA_INTERFACE10,
>> +};
>> +
>> +static void __lpass_get_dmactl_handle(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
>> +                                     struct lpaif_dmactl **dmactl, int *id)
>> +{
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
>> +       struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> +       struct snd_pcm_runtime *rt = substream->runtime;
>> +       struct lpass_pcm_data *pcm_data = rt->private_data;
>> +       struct lpass_variant *v = drvdata->variant;
>> +       unsigned int dai_id = cpu_dai->driver->id;
>> +
>> +       switch (dai_id) {
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +               *dmactl = drvdata->rxtx_rd_dmactl;
>> +               *id = pcm_data->dma_ch;
>> +               break;
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               *dmactl = drvdata->rxtx_wr_dmactl;
>> +               *id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
>> +               *dmactl = drvdata->va_wr_dmactl;
>> +               *id = pcm_data->dma_ch - v->va_wrdma_channel_start;
>> +               break;
>> +       default:
>> +               dev_err(soc_runtime->dev, "invalid dai id for dma ctl: %d\n", dai_id);
>> +               break;
>> +       }
>> +}
>> +
>> +static int __lpass_get_codec_dma_intf_type(int dai_id)
>> +{
>> +       int ret;
>> +
>> +       switch (dai_id) {
>> +       case LPASS_CDC_DMA_RX0:
>> +       case LPASS_CDC_DMA_TX0:
>> +       case LPASS_CDC_DMA_VA_TX0:
>> +               ret = LPASS_CDC_DMA_INTERFACE1;
>> +               break;
>> +       case LPASS_CDC_DMA_RX1:
>> +       case LPASS_CDC_DMA_TX1:
>> +       case LPASS_CDC_DMA_VA_TX1:
>> +               ret = LPASS_CDC_DMA_INTERFACE2;
>> +               break;
>> +       case LPASS_CDC_DMA_RX2:
>> +       case LPASS_CDC_DMA_TX2:
>> +       case LPASS_CDC_DMA_VA_TX2:
>> +               ret = LPASS_CDC_DMA_INTERFACE3;
>> +               break;
>> +       case LPASS_CDC_DMA_RX3:
>> +       case LPASS_CDC_DMA_TX3:
>> +       case LPASS_CDC_DMA_VA_TX3:
>> +               ret = LPASS_CDC_DMA_INTERFACE4;
>> +               break;
>> +       case LPASS_CDC_DMA_RX4:
>> +       case LPASS_CDC_DMA_TX4:
>> +       case LPASS_CDC_DMA_VA_TX4:
>> +               ret = LPASS_CDC_DMA_INTERFACE5;
>> +               break;
>> +       case LPASS_CDC_DMA_RX5:
>> +       case LPASS_CDC_DMA_TX5:
>> +       case LPASS_CDC_DMA_VA_TX5:
>> +               ret = LPASS_CDC_DMA_INTERFACE6;
>> +               break;
>> +       case LPASS_CDC_DMA_RX6:
>> +       case LPASS_CDC_DMA_TX6:
>> +       case LPASS_CDC_DMA_VA_TX6:
>> +               ret = LPASS_CDC_DMA_INTERFACE7;
>> +               break;
>> +       case LPASS_CDC_DMA_RX7:
>> +       case LPASS_CDC_DMA_TX7:
>> +       case LPASS_CDC_DMA_VA_TX7:
>> +               ret = LPASS_CDC_DMA_INTERFACE8;
>> +               break;
>> +       case LPASS_CDC_DMA_RX8:
>> +       case LPASS_CDC_DMA_TX8:
>> +       case LPASS_CDC_DMA_VA_TX8:
>> +               ret = LPASS_CDC_DMA_INTERFACE9;
>> +               break;
>> +       case LPASS_CDC_DMA_RX9:
>> +               ret  = LPASS_CDC_DMA_INTERFACE10;
>> +               break;
>> +       default:
>> +               ret = -EINVAL;
>> +               break;
>> +       }
>> +       return ret;
>> +}
>> +
>> +static int __lpass_platform_codec_intf_init(struct snd_soc_dai *dai,
>> +                                           struct snd_pcm_substream *substream)
>> +{
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
>> +       struct lpaif_dmactl *dmactl = NULL;
>> +       struct device *dev = soc_runtime->dev;
>> +       int ret, id, codec_intf;
>> +       unsigned int dai_id = cpu_dai->driver->id;
>> +
>> +       codec_intf = __lpass_get_codec_dma_intf_type(dai_id);
>> +       if (codec_intf < 0) {
>> +               dev_err(dev, "failed to get codec_intf: %d\n", codec_intf);
>> +               return codec_intf;
>> +       }
>> +
>> +       __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
>> +       if (!dmactl) {
>> +               dev_err(dev, "failed to get dmactl handle for dai_id: %d\n", dai_id);
>> +               return -EINVAL;
>> +       }
>> +
>> +       ret = regmap_fields_write(dmactl->codec_intf, id, codec_intf);
>> +       if (ret) {
>> +               dev_err(dev, "error writing to dmactl codec_intf reg field: %d\n", ret);
>> +               return ret;
>> +       }
>> +       ret = regmap_fields_write(dmactl->codec_fs_sel, id, 0x0);
>> +       if (ret) {
>> +               dev_err(dev, "error writing to dmactl codec_fs_sel reg field: %d\n", ret);
>> +               return ret;
>> +       }
>> +       ret = regmap_fields_write(dmactl->codec_fs_delay, id, 0x0);
>> +       if (ret) {
>> +               dev_err(dev, "error writing to dmactl codec_fs_delay reg field: %d\n", ret);
>> +               return ret;
>> +       }
>> +       ret = regmap_fields_write(dmactl->codec_pack, id, 0x1);
>> +       if (ret) {
>> +               dev_err(dev, "error writing to dmactl codec_pack reg field: %d\n", ret);
>> +               return ret;
>> +       }
>> +       ret = regmap_fields_write(dmactl->codec_enable, id, LPAIF_DMACTL_ENABLE_ON);
>> +       if (ret) {
>> +               dev_err(dev, "error writing to dmactl codec_enable reg field: %d\n", ret);
>> +               return ret;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int lpass_cdc_dma_daiops_startup(struct snd_pcm_substream *substream,
>> +                                   struct snd_soc_dai *dai)
>> +{
>> +       struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +
>> +       switch (dai->id) {
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               clk_set_rate(drvdata->cdc_clks[2].clk, CODEC_MEM_FREQ_NORMAL);
>> +               clk_prepare_enable(drvdata->cdc_clks[2].clk);
> Where do '2' and '5' come from? Why are they part of the bulk clk array?
> Why not get them separately and give them real named pointer values?
Okay. will change to real named pointers.
>
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
>> +               clk_set_rate(drvdata->cdc_clks[5].clk, CODEC_MEM_FREQ_NORMAL);
>> +               clk_prepare_enable(drvdata->cdc_clks[5].clk);
>> +               break;
>> +       default:
>> +               dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai->id);
>> +               break;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static void lpass_cdc_dma_daiops_shutdown(struct snd_pcm_substream *substream,
>> +                                     struct snd_soc_dai *dai)
>> +{
>> +       struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +
>> +       switch (dai->id) {
>> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
>> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
>> +               clk_disable_unprepare(drvdata->cdc_clks[2].clk);
>> +               break;
>> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
>> +               clk_disable_unprepare(drvdata->cdc_clks[5].clk);
>> +               break;
>> +       default:
>> +               dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai->id);
>> +               break;
>> +       }
>> +}
>> +
>> +static int lpass_cdc_dma_daiops_hw_params(struct snd_pcm_substream *substream,
>> +                                     struct snd_pcm_hw_params *params,
>> +                                     struct snd_soc_dai *dai)
>> +{
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +       struct lpaif_dmactl *dmactl = NULL;
>> +       unsigned int ret, regval;
>> +       unsigned int channels = params_channels(params);
>> +       int id;
>> +
>> +       switch (channels) {
>> +       case 1:
>> +               regval = LPASS_CDC_DMA_INTF_ONE_CHANNEL;
>> +               break;
>> +       case 2:
>> +               regval = LPASS_CDC_DMA_INTF_TWO_CHANNEL;
>> +               break;
>> +       case 4:
>> +               regval = LPASS_CDC_DMA_INTF_FOUR_CHANNEL;
>> +               break;
>> +       case 6:
>> +               regval = LPASS_CDC_DMA_INTF_SIX_CHANNEL;
>> +               break;
>> +       case 8:
>> +               regval = LPASS_CDC_DMA_INTF_EIGHT_CHANNEL;
>> +               break;
>> +       default:
>> +               dev_err(soc_runtime->dev, "invalid PCM config\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
>> +       if (!dmactl) {
>> +               dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>> +               return -EINVAL;
>> +       }
>> +       ret = regmap_fields_write(dmactl->codec_channel, id, regval);
>> +       if (ret) {
>> +               dev_err(soc_runtime->dev,
>> +                       "error writing to dmactl codec_channel reg field: %d\n", ret);
>> +               return ret;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int lpass_cdc_dma_daiops_trigger(struct snd_pcm_substream *substream,
>> +                                   int cmd, struct snd_soc_dai *dai)
>> +{
>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>> +       struct lpaif_dmactl *dmactl;
>> +       int ret = 0, id;
>> +
>> +       switch (cmd) {
>> +       case SNDRV_PCM_TRIGGER_START:
>> +       case SNDRV_PCM_TRIGGER_RESUME:
>> +       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> +               __lpass_platform_codec_intf_init(dai, substream);
>> +               break;
>> +       case SNDRV_PCM_TRIGGER_STOP:
>> +       case SNDRV_PCM_TRIGGER_SUSPEND:
>> +       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>> +               __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
>> +               if (!dmactl) {
>> +                       dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> This same message is in many places. I really hope it never gets printed
> because finding out which line it got printed at is going to be
> impossible.
Okay. Will add function name in each print.
>
>> +                       return -EINVAL;
>> +               }
>> +               ret = regmap_fields_write(dmactl->codec_enable, id, LPAIF_DMACTL_ENABLE_OFF);
>> +               if (ret) {
>> +                       dev_err(soc_runtime->dev,
>> +                               "error writing to dmactl codec_enable reg: %d\n", ret);
>> +                       return ret;
>> +               }
>> +               break;
>> +       default:
>> +               ret = -EINVAL;
>> +               dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, cmd);
>> +               break;
>> +       }
>> +       return ret;
>> +}
>> +
>> +const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops = {
>> +       .startup        = lpass_cdc_dma_daiops_startup,
>> +       .shutdown       = lpass_cdc_dma_daiops_shutdown,
>> +       .hw_params      = lpass_cdc_dma_daiops_hw_params,
>> +       .trigger        = lpass_cdc_dma_daiops_trigger,
>> +};
>> +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cdc_dma_dai_ops);
>> +
>> +MODULE_DESCRIPTION("QTi LPASS CDC DMA Driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
>> index e059c4a..d279a72 100644
>> --- a/sound/soc/qcom/lpass.h
>> +++ b/sound/soc/qcom/lpass.h
>> @@ -410,5 +410,6 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
>>   extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
>>   int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
>>                                  struct snd_soc_dai *dai);
>> +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops;
>>
>>   #endif /* __LPASS_H__ */
>> --
>> 2.7.4
>>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 07/10] ASoC: qcom: Add support for codec dma driver
  2022-02-14 14:58 ` [RESEND v13 07/10] ASoC: qcom: Add " Srinivasa Rao Mandadapu
  2022-02-15  1:27   ` Stephen Boyd
  2022-02-16  6:42   ` kernel test robot
@ 2022-02-17 13:14   ` Dan Carpenter
  2 siblings, 0 replies; 28+ messages in thread
From: Dan Carpenter @ 2022-02-17 13:14 UTC (permalink / raw)
  To: kbuild, Srinivasa Rao Mandadapu, agross, bjorn.andersson,
	lgirdwood, broonie, robh+dt, quic_plai, bgoswami, perex, tiwai,
	srinivas.kandagatla, rohitkr, linux-arm-msm, alsa-devel,
	devicetree, linux-kernel, swboyd, judyhsiao
  Cc: lkp, kbuild-all, Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Hi Srinivasa,

url:    https://github.com/0day-ci/linux/commits/Srinivasa-Rao-Mandadapu/Add-support-for-audio-on-SC7280-based-targets/20220214-230256
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: m68k-randconfig-m031-20220214 (https://download.01.org/0day-ci/archive/20220215/202202151059.hEuYfkLa-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 11.2.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

smatch warnings:
sound/soc/qcom/lpass-platform.c:1233 lpass_platform_copy() warn: maybe return -EFAULT instead of the bytes remaining?

vim +1233 sound/soc/qcom/lpass-platform.c

e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1210  static int lpass_platform_copy(struct snd_soc_component *component,
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1211  			       struct snd_pcm_substream *substream, int channel,
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1212  			       unsigned long pos, void __user *buf, unsigned long bytes)
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1213  {
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1214  	struct snd_pcm_runtime *rt = substream->runtime;
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1215  	unsigned int dai_id = component->id;
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1216  	int ret = 0;
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1217  
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1218  	void __iomem *dma_buf = rt->dma_area + pos +
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1219  				channel * (rt->dma_bytes / rt->channels);
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1220  
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1221  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1222  		if (is_cdc_dma_port(dai_id))
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1223  			ret = copy_from_user_toio(dma_buf, buf, bytes);
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1224  		else
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1225  			ret = copy_from_user((void __force *)dma_buf, buf, bytes);
                                                                                      ^^^^^^^^^^^^^^
Positives are treated as success in _soc_component_ret()

e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1226  	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1227  		if (is_cdc_dma_port(dai_id))
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1228  			ret = copy_to_user_fromio(buf, dma_buf, bytes);
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1229  		else
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1230  			ret = copy_to_user(buf, (void __force *)dma_buf, bytes);

Same

e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1231  	}
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1232  
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14 @1233  	return ret;
e81c7e5d842d2b Srinivasa Rao Mandadapu 2022-02-14  1234  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
  2022-02-16  5:11     ` Srinivasa Rao Mandadapu
@ 2022-02-17 19:41       ` Stephen Boyd
  2022-02-19 18:45         ` Srinivasa Rao Mandadapu (Temp)
  0 siblings, 1 reply; 28+ messages in thread
From: Stephen Boyd @ 2022-02-17 19:41 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-15 21:11:29)
>
> On 2/15/2022 6:40 AM, Stephen Boyd wrote:
> Thanks for your time Stephen!!!
> > Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:22)
> >> Add support function to get dma control and lpaif handle to avoid
> >> repeated code in platform driver
> >>
> >> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
> >> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> >> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
> >> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> >> ---
> >>   sound/soc/qcom/lpass-platform.c | 113 +++++++++++++++++++++++-----------------
> >>   1 file changed, 66 insertions(+), 47 deletions(-)
> >>
> >> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> >> index a44162c..5d77240 100644
> >> --- a/sound/soc/qcom/lpass-platform.c
> >> +++ b/sound/soc/qcom/lpass-platform.c
> >> @@ -177,6 +177,49 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
> >>          return 0;
> >>   }
> >>
> >> +static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,
> > const?
> Okay. will add const to substream pointer.
> >
> >> +                                    struct snd_soc_component *component,
> > const?
> Here const is giving compilation errors in below code.

Ok

> >
> >> +                       l_id = pcm_data->dma_ch;
> >> +                       l_dmactl = drvdata->rd_dmactl;
> >> +               } else {
> >> +                       l_dmactl = drvdata->wr_dmactl;
> >> +                       l_id = pcm_data->dma_ch - v->wrdma_channel_start;
> >> +               }
> >> +               l_map = drvdata->lpaif_map;
> >> +               break;
> >> +       case LPASS_DP_RX:
> >> +               l_id = pcm_data->dma_ch;
> >> +               l_dmactl = drvdata->hdmi_rd_dmactl;
> >> +               l_map = drvdata->hdmiif_map;
> >> +               break;
> >> +       default:
> >> +               break;
> >> +       }
> >> +       if (dmactl)
> >> +               *dmactl = l_dmactl;
> >> +       if (id)
> >> +               *id = l_id;
> >> +       if (map)
> >> +               *map = l_map;
> > Why not 'return 0' here and return -EINVAL in the default case above? Then
> > we can skip the checks for !map or !dmactl below and simply bail out if
> > it failed with an error value.
>
> Here the check is for input params. some users call for only damctl or
> only map.

Yes the check is to make sure there's a pointer to store the value into.
I get that. The users are all internal to this driver though because
the function is static. If the function returned an error because it
couldn't find something then we wouldn't have to test the resulting
pointers for success, instead we could check for a return value.
Similarly, it may be clearer to have a single get for each item and then
return a pointer from the function vs. passing it in to extract
something. It may duplicate some code but otherwise the code would be
clearer because we're getting one thing and can pass an error value
through the pointer with PTR_ERR().

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 07/10] ASoC: qcom: Add support for codec dma driver
  2022-02-16  6:53     ` Srinivasa Rao Mandadapu
@ 2022-02-17 19:50       ` Stephen Boyd
  0 siblings, 0 replies; 28+ messages in thread
From: Stephen Boyd @ 2022-02-17 19:50 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-15 22:53:11)
>
> On 2/15/2022 6:57 AM, Stephen Boyd wrote:
> Thanks for your time and valuable review comments Stephen!!!
> > Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:25)
> >> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> >> index 5d77240..12b8d40 100644
> >> --- a/sound/soc/qcom/lpass-platform.c
> >> +++ b/sound/soc/qcom/lpass-platform.c
[...]
> >
> >> +       if (ret)
> >> +               return ret;
> >> +
> >> +       buf = &substream->dma_buffer;
> >> +       buf->dev.dev = pcm->card->dev;
> >> +       buf->private_data = NULL;
> >> +
> >> +       /* Assign Codec DMA buffer pointers */
> >> +       buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
> >> +
> >> +       switch (dai_id) {
> >> +       case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
> >> +               buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> >> +               buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
> >> +               break;
> >> +       case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
> >> +               buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> >> +               buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
> >> +               break;
> >> +       case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
> >> +               buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
> >> +               buf->addr = drvdata->va_cdc_dma_lpm_buf;
> >> +               break;
> >> +       default:
> >> +               break;
> >> +       }
> >> +
> >> +       buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
> > Why aren't we using the DMA mapping framework?
> Here, Need to use hardware memory, that is LPASS LPM region for codec DMA.

It does not look like iomem, so the usage of ioremap() is wrong. I
understand that it is some place inside the audio subsystem used to DMA.
ioremap() memory should be accessed through the io accessors,
readl/writel, ioread/iowrite.

> >> @@ -827,6 +1207,31 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
> >>          return regcache_sync(map);
> >>   }
> >>
> >> +static int lpass_platform_copy(struct snd_soc_component *component,
> >> +                              struct snd_pcm_substream *substream, int channel,
> >> +                              unsigned long pos, void __user *buf, unsigned long bytes)
> >> +{
> >> +       struct snd_pcm_runtime *rt = substream->runtime;
> >> +       unsigned int dai_id = component->id;
> >> +       int ret = 0;
> >> +
> >> +       void __iomem *dma_buf = rt->dma_area + pos +
> >> +                               channel * (rt->dma_bytes / rt->channels);
> >> +
> >> +       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> >> +               if (is_cdc_dma_port(dai_id))
> >> +                       ret = copy_from_user_toio(dma_buf, buf, bytes);
> >> +               else
> >> +                       ret = copy_from_user((void __force *)dma_buf, buf, bytes);
> >> +       } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> >> +               if (is_cdc_dma_port(dai_id))
> >> +                       ret = copy_to_user_fromio(buf, dma_buf, bytes);
> >> +               else
> >> +                       ret = copy_to_user(buf, (void __force *)dma_buf, bytes);
> > Having __force in here highlights the lack of DMA API usage. I guess
> > there's a sound dma wrapper library in sound/core/memalloc.c? Why can't
> > that be used?
> Didn't see any memcopy wrapper functions in memalloc.c. Could You please
> elaborate or share some example.

Can you add some memcpy wrappers to memalloc.c? Or implement the copy
wrapper you need?

> >
> >> +       }
> >> +
> >> +       return ret;
> >> +}
> >>
> >>   static const struct snd_soc_component_driver lpass_component_driver = {
> >>          .name           = DRV_NAME,
> >> @@ -837,9 +1242,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
> >>          .prepare        = lpass_platform_pcmops_prepare,
> >>          .trigger        = lpass_platform_pcmops_trigger,
> >>          .pointer        = lpass_platform_pcmops_pointer,
> >> +       .mmap           = lpass_platform_pcmops_mmap,
> >>          .pcm_construct  = lpass_platform_pcm_new,
> >>          .suspend                = lpass_platform_pcmops_suspend,
> >>          .resume                 = lpass_platform_pcmops_resume,
> >> +       .copy_user              = lpass_platform_copy,
> >>
> >>   };
> >>
> >> @@ -877,6 +1284,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
> >>                  return ret;
> >>          }
> >>
> >> +       if (drvdata->codec_dma_enable) {
> >> +               ret = regmap_write(drvdata->rxtx_lpaif_map,
> >> +                       LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
> >> +               if (ret) {
> >> +                       dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
> >> +                       return ret;
> >> +               }
> >> +               ret = regmap_write(drvdata->va_lpaif_map,
> >> +                       LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
> >> +               if (ret) {
> >> +                       dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
> >> +                       return ret;
> >> +               }
> >> +               drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
> >> +               if (drvdata->rxtxif_irq < 0)
> >> +                       return -ENODEV;
> >> +
> >> +               ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
> >> +                               lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,
> > Drop flags and get it from firmware please.
> Same is followed in existing for other i2s and HDMI interrupts. Could
> You please give some example if it's really matters?

It matters in the case that the hardware team decides to change the pin
to falling. DT already has the flags encoded, so having a zero here
avoids conflicting with what DT has set and also alleviates us from
having to set different flags on different devices. Everyone wins. Look
around for drivers that pass 0 in place of IRQF_TRIGGER_RISING, there
are many examples.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control
  2022-02-16  9:42     ` Srinivasa Rao Mandadapu
@ 2022-02-17 19:53       ` Stephen Boyd
  2022-02-19 18:56         ` Srinivasa Rao Mandadapu (Temp)
  0 siblings, 1 reply; 28+ messages in thread
From: Stephen Boyd @ 2022-02-17 19:53 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, alsa-devel, bgoswami,
	bjorn.andersson, broonie, devicetree, judyhsiao, lgirdwood,
	linux-arm-msm, linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu

Quoting Srinivasa Rao Mandadapu (2022-02-16 01:42:42)
>
> On 2/15/2022 7:03 AM, Stephen Boyd wrote:
> Thanks for your time Stephen!!!
> > Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:26)
> >> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> >> +       struct lpaif_dmactl *dmactl;
> >> +       int ret = 0, id;
> >> +
> >> +       switch (cmd) {
> >> +       case SNDRV_PCM_TRIGGER_START:
> >> +       case SNDRV_PCM_TRIGGER_RESUME:
> >> +       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> >> +               __lpass_platform_codec_intf_init(dai, substream);
> >> +               break;
> >> +       case SNDRV_PCM_TRIGGER_STOP:
> >> +       case SNDRV_PCM_TRIGGER_SUSPEND:
> >> +       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> >> +               __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
> >> +               if (!dmactl) {
> >> +                       dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
> > This same message is in many places. I really hope it never gets printed
> > because finding out which line it got printed at is going to be
> > impossible.
> Okay. Will add function name in each print.

Are they useful prints at all? They seem like development prints that
won't trigger after the driver is developed. Why can't we just remove
them?

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
  2022-02-17 19:41       ` Stephen Boyd
@ 2022-02-19 18:45         ` Srinivasa Rao Mandadapu (Temp)
  0 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu (Temp) @ 2022-02-19 18:45 UTC (permalink / raw)
  To: Stephen Boyd, agross, alsa-devel, bgoswami, bjorn.andersson,
	broonie, devicetree, judyhsiao, lgirdwood, linux-arm-msm,
	linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu


On 2/18/2022 1:11 AM, Stephen Boyd wrote:
Thanks for Your time Stephen!!!
> Quoting Srinivasa Rao Mandadapu (2022-02-15 21:11:29)
>> On 2/15/2022 6:40 AM, Stephen Boyd wrote:
>> Thanks for your time Stephen!!!
>>> Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:22)
>>>> Add support function to get dma control and lpaif handle to avoid
>>>> repeated code in platform driver
>>>>
>>>> Signed-off-by: Srinivasa Rao Mandadapu <quic_srivasam@quicinc.com>
>>>> Co-developed-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>>>> Signed-off-by: Venkata Prasad Potturu <quic_potturu@quicinc.com>
>>>> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>>> ---
>>>>    sound/soc/qcom/lpass-platform.c | 113 +++++++++++++++++++++++-----------------
>>>>    1 file changed, 66 insertions(+), 47 deletions(-)
>>>>
>>>> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
>>>> index a44162c..5d77240 100644
>>>> --- a/sound/soc/qcom/lpass-platform.c
>>>> +++ b/sound/soc/qcom/lpass-platform.c
>>>> @@ -177,6 +177,49 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>>>>           return 0;
>>>>    }
>>>>
>>>> +static void __lpass_get_lpaif_handle(struct snd_pcm_substream *substream,
>>> const?
>> Okay. will add const to substream pointer.
>>>> +                                    struct snd_soc_component *component,
>>> const?
>> Here const is giving compilation errors in below code.
> Ok
>
>>>> +                       l_id = pcm_data->dma_ch;
>>>> +                       l_dmactl = drvdata->rd_dmactl;
>>>> +               } else {
>>>> +                       l_dmactl = drvdata->wr_dmactl;
>>>> +                       l_id = pcm_data->dma_ch - v->wrdma_channel_start;
>>>> +               }
>>>> +               l_map = drvdata->lpaif_map;
>>>> +               break;
>>>> +       case LPASS_DP_RX:
>>>> +               l_id = pcm_data->dma_ch;
>>>> +               l_dmactl = drvdata->hdmi_rd_dmactl;
>>>> +               l_map = drvdata->hdmiif_map;
>>>> +               break;
>>>> +       default:
>>>> +               break;
>>>> +       }
>>>> +       if (dmactl)
>>>> +               *dmactl = l_dmactl;
>>>> +       if (id)
>>>> +               *id = l_id;
>>>> +       if (map)
>>>> +               *map = l_map;
>>> Why not 'return 0' here and return -EINVAL in the default case above? Then
>>> we can skip the checks for !map or !dmactl below and simply bail out if
>>> it failed with an error value.
>> Here the check is for input params. some users call for only damctl or
>> only map.
> Yes the check is to make sure there's a pointer to store the value into.
> I get that. The users are all internal to this driver though because
> the function is static. If the function returned an error because it
> couldn't find something then we wouldn't have to test the resulting
> pointers for success, instead we could check for a return value.
> Similarly, it may be clearer to have a single get for each item and then
> return a pointer from the function vs. passing it in to extract
> something. It may duplicate some code but otherwise the code would be
> clearer because we're getting one thing and can pass an error value
> through the pointer with PTR_ERR().

Okay. Agreed. But in initial review comments, asked to make common 
function for code readability,

and to avoid duplicate code.

Anyway will change accordingly and re post it.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control
  2022-02-17 19:53       ` Stephen Boyd
@ 2022-02-19 18:56         ` Srinivasa Rao Mandadapu (Temp)
  0 siblings, 0 replies; 28+ messages in thread
From: Srinivasa Rao Mandadapu (Temp) @ 2022-02-19 18:56 UTC (permalink / raw)
  To: Stephen Boyd, agross, alsa-devel, bgoswami, bjorn.andersson,
	broonie, devicetree, judyhsiao, lgirdwood, linux-arm-msm,
	linux-kernel, perex, quic_plai, robh+dt, rohitkr,
	srinivas.kandagatla, tiwai
  Cc: Venkata Prasad Potturu


On 2/18/2022 1:23 AM, Stephen Boyd wrote:
Thanks for Your time Stephen!!!
> Quoting Srinivasa Rao Mandadapu (2022-02-16 01:42:42)
>> On 2/15/2022 7:03 AM, Stephen Boyd wrote:
>> Thanks for your time Stephen!!!
>>> Quoting Srinivasa Rao Mandadapu (2022-02-14 06:58:26)
>>>> +       struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
>>>> +       struct lpaif_dmactl *dmactl;
>>>> +       int ret = 0, id;
>>>> +
>>>> +       switch (cmd) {
>>>> +       case SNDRV_PCM_TRIGGER_START:
>>>> +       case SNDRV_PCM_TRIGGER_RESUME:
>>>> +       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>>>> +               __lpass_platform_codec_intf_init(dai, substream);
>>>> +               break;
>>>> +       case SNDRV_PCM_TRIGGER_STOP:
>>>> +       case SNDRV_PCM_TRIGGER_SUSPEND:
>>>> +       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>>>> +               __lpass_get_dmactl_handle(substream, dai, &dmactl, &id);
>>>> +               if (!dmactl) {
>>>> +                       dev_err(soc_runtime->dev, "failed to get dmactl handle\n");
>>> This same message is in many places. I really hope it never gets printed
>>> because finding out which line it got printed at is going to be
>>> impossible.
>> Okay. Will add function name in each print.
> Are they useful prints at all? They seem like development prints that
> won't trigger after the driver is developed. Why can't we just remove
> them?
Okay. Will remove prints.

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2022-02-19 18:57 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-14 14:58 [RESEND v13 00/10] Add support for audio on SC7280 based targets Srinivasa Rao Mandadapu
2022-02-14 14:58 ` [RESEND v13 01/10] ASoC: qcom: SC7280: Update config for building codec dma drivers Srinivasa Rao Mandadapu
2022-02-14 14:58 ` [RESEND v13 02/10] ASoC: qcom: Move lpass_pcm_data structure to lpass header Srinivasa Rao Mandadapu
2022-02-14 14:58 ` [RESEND v13 03/10] ASoC: qcom: lpass: Add dma fields for codec dma lpass interface Srinivasa Rao Mandadapu
2022-02-15  1:05   ` Stephen Boyd
2022-02-16  4:58     ` Srinivasa Rao Mandadapu
2022-02-14 14:58 ` [RESEND v13 04/10] ASoC: qcom: Add helper function to get dma control and lpaif handle Srinivasa Rao Mandadapu
2022-02-15  1:10   ` Stephen Boyd
2022-02-16  5:11     ` Srinivasa Rao Mandadapu
2022-02-17 19:41       ` Stephen Boyd
2022-02-19 18:45         ` Srinivasa Rao Mandadapu (Temp)
2022-02-14 14:58 ` [RESEND v13 05/10] ASoC: qcom: Add register definition for codec rddma and wrdma Srinivasa Rao Mandadapu
2022-02-15  1:12   ` Stephen Boyd
2022-02-16  5:14     ` Srinivasa Rao Mandadapu
2022-02-14 14:58 ` [RESEND v13 06/10] ASoC: qcom: Add regmap config support for codec dma driver Srinivasa Rao Mandadapu
2022-02-14 14:58 ` [RESEND v13 07/10] ASoC: qcom: Add " Srinivasa Rao Mandadapu
2022-02-15  1:27   ` Stephen Boyd
2022-02-16  6:53     ` Srinivasa Rao Mandadapu
2022-02-17 19:50       ` Stephen Boyd
2022-02-16  6:42   ` kernel test robot
2022-02-17 13:14   ` Dan Carpenter
2022-02-14 14:58 ` [RESEND v13 08/10] ASoC: qcom: Add lpass CPU driver for codec dma control Srinivasa Rao Mandadapu
2022-02-15  1:33   ` Stephen Boyd
2022-02-16  9:42     ` Srinivasa Rao Mandadapu
2022-02-17 19:53       ` Stephen Boyd
2022-02-19 18:56         ` Srinivasa Rao Mandadapu (Temp)
2022-02-14 14:58 ` [RESEND v13 09/10] ASoC: dt-bindings: Add SC7280 lpass cpu bindings Srinivasa Rao Mandadapu
2022-02-14 14:58 ` [RESEND v13 10/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio Srinivasa Rao Mandadapu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).