From: Quanyang Wang <quanyang.w...@windriver.com>

According to the description in the section "Audio Management" of
Chapter 33 in "Zynq UltraScale+ Device Technical Reference Manual",
A set/clr operation to TX_AUDIO_CONTROL register is needed when we
start/stop audio play. It means that when we stop playing audio,
TX_AUDIO_CONTROL register should be cleared. Now the dp codec driver
xilinx-dp-codec.c can't access DP Tx registers and it has no control
of DP Tx Audio registers. This results that even if we close the audio
device after playing audio, Tx Audio is still working and it triggers
numerous underflow interrupts (bit 17 in DP_INT_STATUS).

zcu102-zynqmp:~$ cat /proc/interrupts | grep display
 52:    1063792    0    0    0   GICv2 151 Level   fd4a0000.display

zcu102-zynqmp:~$ top
Mem: 158168K used, 3864792K free, 9992K shrd, 0K buff, 36500K cached
CPU:  0.0% usr  1.0% sys  0.0% nic 98.9% idle  0.0% io  0.0% irq  0.0% sirq
Load average: 0.03 0.03 0.01 1/122 391
  PID  PPID USER    STAT   VSZ %VSZ CPU %CPU COMMAND
  223     2 root    SW       0  0.0   0  0.9 [irq/52-fd4a0000]
  352     1 root    S    94148  2.3   0  0.0 /usr/sbin/tcf-agent -d -L- -l0

So we register a HDMI codec device and use callbacks in hdmi_codec_ops
to set/clr TX_AUDIO_CONTROL.

Signed-off-by: Quanyang Wang <quanyang.w...@windriver.com>
---
Hi Bruce,
Would you please help merge this patch to the branches:
        v5.15/standard/preempt-rt/sdkv5.15/xlnx-soc
        v5.15/standard/sdkv5.15/xlnx-soc
Thanks,
Quanyang
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c  | 55 +++++++++++++++++++++++++++++++
 sound/soc/xilinx/Kconfig          |  1 +
 sound/soc/xilinx/xilinx-dp-card.c | 14 ++------
 3 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 308404f122957..c9badbfe5b566 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -26,6 +26,7 @@
 #include <linux/phy/phy.h>
 #include <linux/reset.h>
 #include <linux/uaccess.h>
+#include <sound/hdmi-codec.h>
 
 #include "zynqmp_disp.h"
 #include "zynqmp_dp.h"
@@ -329,6 +330,7 @@ struct zynqmp_dp {
        void __iomem *iomem;
        struct reset_control *reset;
        int irq;
+       struct platform_device *audio_pdev;
 
        struct zynqmp_dp_config config;
        struct drm_dp_aux aux;
@@ -375,6 +377,53 @@ static void zynqmp_dp_set(void __iomem *base, int offset, 
u32 set)
        zynqmp_dp_write(base, offset, zynqmp_dp_read(base, offset) | set);
 }
 
+static int zynqmp_dp_audio_hw_params(struct device *dev,  void *data,
+                                  struct hdmi_codec_daifmt *daifmt,
+                                  struct hdmi_codec_params *params)
+{
+       return 0;
+}
+
+static int zynqmp_dp_audio_startup(struct device *dev, void *data)
+{
+       struct zynqmp_dp *dp = data;
+
+       if (zynqmp_disp_aud_enabled(dp->dpsub->disp))
+               zynqmp_dp_write(dp->iomem, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
+
+       return 0;
+}
+
+static void zynqmp_dp_audio_shutdown(struct device *dev, void *data)
+{
+       struct zynqmp_dp *dp = data;
+
+       if (zynqmp_disp_aud_enabled(dp->dpsub->disp))
+               zynqmp_dp_write(dp->iomem, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+       .hw_params = zynqmp_dp_audio_hw_params,
+       .audio_shutdown = zynqmp_dp_audio_shutdown,
+       .audio_startup = zynqmp_dp_audio_startup,
+};
+
+static int zynqmp_dp_audio_init(struct zynqmp_dp *dp,
+                                  struct device *dev)
+{
+       struct hdmi_codec_pdata codec_data = {
+               .ops = &audio_codec_ops,
+               .spdif = 1,
+               .data = dp,
+       };
+
+       dp->audio_pdev = platform_device_register_data(
+                        dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_NONE,
+                        &codec_data, sizeof(codec_data));
+
+       return PTR_ERR_OR_ZERO(dp->audio_pdev);
+}
+
 /* 
-----------------------------------------------------------------------------
  * PHY Handling
  */
@@ -1950,6 +1999,12 @@ int zynqmp_dp_probe(struct platform_device *pdev)
                goto error;
        }
 
+       ret = zynqmp_dp_audio_init(dp, dp->dev);
+       if (ret < 0) {
+               dev_err(dp->dev, "failed to initialize DP audio codec\n");
+               goto error;
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                ret = irq;
diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig
index ade55b32a8cc6..787b92a406a23 100644
--- a/sound/soc/xilinx/Kconfig
+++ b/sound/soc/xilinx/Kconfig
@@ -3,6 +3,7 @@ config SND_SOC_XILINX_DP
        tristate "Audio support for the the Xilinx DisplayPort"
        select SND_DMAENGINE_PCM
        select SND_SOC_GENERIC_DMAENGINE_PCM
+       select SND_SOC_HDMI_CODEC
        help
          Audio support the for Xilinx DisplayPort.
 
diff --git a/sound/soc/xilinx/xilinx-dp-card.c 
b/sound/soc/xilinx/xilinx-dp-card.c
index 396a87d56394f..ec0682f2a7a6c 100644
--- a/sound/soc/xilinx/xilinx-dp-card.c
+++ b/sound/soc/xilinx/xilinx-dp-card.c
@@ -36,12 +36,12 @@ static const struct snd_soc_ops xilinx_dp_ops = {
 
 SND_SOC_DAILINK_DEFS(xilinx_dp0,
                DAILINK_COMP_ARRAY(COMP_CPU("xilinx-dp-snd-codec-dai")),
-               DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "xilinx-dp-snd-codec-dai")),
+               DAILINK_COMP_ARRAY(COMP_CODEC("hdmi-audio-codec", 
"spdif-hifi")),
                DAILINK_COMP_ARRAY(COMP_PLATFORM(NULL)));
 
 SND_SOC_DAILINK_DEFS(xilinx_dp1,
                DAILINK_COMP_ARRAY(COMP_CPU("xilinx-dp-snd-codec-dai")),
-               DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "xilinx-dp-snd-codec-dai")),
+               DAILINK_COMP_ARRAY(COMP_CODEC("hdmi-audio-codec", 
"spdif-hifi")),
                DAILINK_COMP_ARRAY(COMP_PLATFORM(NULL)));
 
 static struct snd_soc_dai_link xilinx_dp_dai_links[] = {
@@ -71,28 +71,20 @@ static int xilinx_dp_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &xilinx_dp_card;
        struct device_node *node = pdev->dev.of_node;
-       struct device_node *codec, *pcm;
+       struct device_node *pcm;
        int ret;
 
        card->dev = &pdev->dev;
 
-       codec = of_parse_phandle(node, "xlnx,dp-snd-codec", 0);
-       if (!codec)
-               return -ENODEV;
-
        pcm = of_parse_phandle(node, "xlnx,dp-snd-pcm", 0);
        if (!pcm)
                return -ENODEV;
        xilinx_dp_dai_links[0].platforms->of_node = pcm;
-       xilinx_dp_dai_links[0].cpus->of_node = codec;
-       xilinx_dp_dai_links[0].codecs->of_node = codec;
 
        pcm = of_parse_phandle(node, "xlnx,dp-snd-pcm", 1);
        if (!pcm)
                return -ENODEV;
        xilinx_dp_dai_links[1].platforms->of_node = pcm;
-       xilinx_dp_dai_links[1].cpus->of_node = codec;
-       xilinx_dp_dai_links[1].codecs->of_node = codec;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret)
-- 
2.36.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#13680): 
https://lists.yoctoproject.org/g/linux-yocto/message/13680
Mute This Topic: https://lists.yoctoproject.org/mt/104902291/21656
Group Owner: linux-yocto+ow...@lists.yoctoproject.org
Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to