All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix
@ 2022-04-06  8:48 ` Sandor.yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

From: Sandor Yu <Sandor.yu@nxp.com>

It is new features and bug fix patch set for DW_HDMI DRM bridge driver
that has verified by NXP iMX865.
Three new feature added:
1. Add GP Audio interface for DW_HDMI.
2. Add CEC PM functions to restore CEC status when device suspend/resume
3. New API for reset PHY Gen1.
Two bugs fixed:
1. Enable overflow workaround for v2.13a.
2. Clear GPC_Auto bit for 24bit bpp to pass CTS.

Sandor Yu (5):
  drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
  drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
  drm: bridge: dw_hdmi: Enable GCP only for Deep Color
  drm: bridge: dw_hdmi: add reset function for PHY GEN1
  drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver

 drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
 drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c |  35 +++
 .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199 ++++++++++++++++++
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 157 +++++++++++++-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c        |   2 +-
 include/drm/bridge/dw_hdmi.h                  |   9 +-
 8 files changed, 416 insertions(+), 11 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c

-- 
2.25.1


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

* [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix
@ 2022-04-06  8:48 ` Sandor.yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

From: Sandor Yu <Sandor.yu@nxp.com>

It is new features and bug fix patch set for DW_HDMI DRM bridge driver
that has verified by NXP iMX865.
Three new feature added:
1. Add GP Audio interface for DW_HDMI.
2. Add CEC PM functions to restore CEC status when device suspend/resume
3. New API for reset PHY Gen1.
Two bugs fixed:
1. Enable overflow workaround for v2.13a.
2. Clear GPC_Auto bit for 24bit bpp to pass CTS.

Sandor Yu (5):
  drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
  drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
  drm: bridge: dw_hdmi: Enable GCP only for Deep Color
  drm: bridge: dw_hdmi: add reset function for PHY GEN1
  drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver

 drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
 drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c |  35 +++
 .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199 ++++++++++++++++++
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 157 +++++++++++++-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c        |   2 +-
 include/drm/bridge/dw_hdmi.h                  |   9 +-
 8 files changed, 416 insertions(+), 11 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c

-- 
2.25.1


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

* [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
  2022-04-06  8:48 ` Sandor.yu
@ 2022-04-06  8:48   ` Sandor.yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

From: Sandor Yu <Sandor.yu@nxp.com>

CEC interrupt status/mask and logical address registers
will be reset when device enter suspend.
It will cause cec fail to work after device resume.
Add CEC suspend/resume functions, save these registers status
when suspend and restore them when resume.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
index c8f44bcb298a..ceb619b32fde 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
@@ -18,6 +18,8 @@
 
 #include "dw-hdmi-cec.h"
 
+static u8 cec_saved_regs[5];
+
 enum {
 	HDMI_IH_CEC_STAT0	= 0x0106,
 	HDMI_IH_MUTE_CEC_STAT0	= 0x0186,
@@ -306,11 +308,44 @@ static int dw_hdmi_cec_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int __maybe_unused dw_hdmi_cec_resume(struct device *dev)
+{
+	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
+
+	/* Restore logical address and interrupt status/mask register */
+	dw_hdmi_write(cec, cec_saved_regs[0], HDMI_CEC_ADDR_L);
+	dw_hdmi_write(cec, cec_saved_regs[1], HDMI_CEC_ADDR_H);
+	dw_hdmi_write(cec, cec_saved_regs[2], HDMI_CEC_POLARITY);
+	dw_hdmi_write(cec, cec_saved_regs[3], HDMI_CEC_MASK);
+	dw_hdmi_write(cec, cec_saved_regs[4], HDMI_IH_MUTE_CEC_STAT0);
+
+	return 0;
+}
+
+static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev)
+{
+	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
+
+	/* store logical address and interrupt status/mask register */
+	cec_saved_regs[0] = dw_hdmi_read(cec, HDMI_CEC_ADDR_L);
+	cec_saved_regs[1] = dw_hdmi_read(cec, HDMI_CEC_ADDR_H);
+	cec_saved_regs[2] = dw_hdmi_read(cec, HDMI_CEC_POLARITY);
+	cec_saved_regs[3] = dw_hdmi_read(cec, HDMI_CEC_MASK);
+	cec_saved_regs[4] = dw_hdmi_read(cec, HDMI_IH_MUTE_CEC_STAT0);
+
+	return 0;
+}
+
+static const struct dev_pm_ops dw_hdmi_cec_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend, dw_hdmi_cec_resume)
+};
+
 static struct platform_driver dw_hdmi_cec_driver = {
 	.probe	= dw_hdmi_cec_probe,
 	.remove	= dw_hdmi_cec_remove,
 	.driver = {
 		.name = "dw-hdmi-cec",
+		.pm = &dw_hdmi_cec_pm,
 	},
 };
 module_platform_driver(dw_hdmi_cec_driver);
-- 
2.25.1


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

* [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
@ 2022-04-06  8:48   ` Sandor.yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

From: Sandor Yu <Sandor.yu@nxp.com>

CEC interrupt status/mask and logical address registers
will be reset when device enter suspend.
It will cause cec fail to work after device resume.
Add CEC suspend/resume functions, save these registers status
when suspend and restore them when resume.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
index c8f44bcb298a..ceb619b32fde 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
@@ -18,6 +18,8 @@
 
 #include "dw-hdmi-cec.h"
 
+static u8 cec_saved_regs[5];
+
 enum {
 	HDMI_IH_CEC_STAT0	= 0x0106,
 	HDMI_IH_MUTE_CEC_STAT0	= 0x0186,
@@ -306,11 +308,44 @@ static int dw_hdmi_cec_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int __maybe_unused dw_hdmi_cec_resume(struct device *dev)
+{
+	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
+
+	/* Restore logical address and interrupt status/mask register */
+	dw_hdmi_write(cec, cec_saved_regs[0], HDMI_CEC_ADDR_L);
+	dw_hdmi_write(cec, cec_saved_regs[1], HDMI_CEC_ADDR_H);
+	dw_hdmi_write(cec, cec_saved_regs[2], HDMI_CEC_POLARITY);
+	dw_hdmi_write(cec, cec_saved_regs[3], HDMI_CEC_MASK);
+	dw_hdmi_write(cec, cec_saved_regs[4], HDMI_IH_MUTE_CEC_STAT0);
+
+	return 0;
+}
+
+static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev)
+{
+	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
+
+	/* store logical address and interrupt status/mask register */
+	cec_saved_regs[0] = dw_hdmi_read(cec, HDMI_CEC_ADDR_L);
+	cec_saved_regs[1] = dw_hdmi_read(cec, HDMI_CEC_ADDR_H);
+	cec_saved_regs[2] = dw_hdmi_read(cec, HDMI_CEC_POLARITY);
+	cec_saved_regs[3] = dw_hdmi_read(cec, HDMI_CEC_MASK);
+	cec_saved_regs[4] = dw_hdmi_read(cec, HDMI_IH_MUTE_CEC_STAT0);
+
+	return 0;
+}
+
+static const struct dev_pm_ops dw_hdmi_cec_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend, dw_hdmi_cec_resume)
+};
+
 static struct platform_driver dw_hdmi_cec_driver = {
 	.probe	= dw_hdmi_cec_probe,
 	.remove	= dw_hdmi_cec_remove,
 	.driver = {
 		.name = "dw-hdmi-cec",
+		.pm = &dw_hdmi_cec_pm,
 	},
 };
 module_platform_driver(dw_hdmi_cec_driver);
-- 
2.25.1


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

* [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
  2022-04-06  8:48 ` Sandor.yu
@ 2022-04-06  8:48   ` Sandor.yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

From: Sandor Yu <Sandor.yu@nxp.com>

iMX865 HDMI (v2.13a) have been identified as needing the workaround.
Tests show that one iteration is enough.

Without the workaround, iMX865 HDMI audio may not work
after cable plugout/in, because HDMI mode is not really set in
register HDMI_FC_INVIDCONF.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 4befc104d220..b11577de4836 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2087,9 +2087,9 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
 	 *
 	 * The number of iterations matters and depends on the HDMI TX revision
 	 * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
-	 * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
-	 * as needing the workaround, with 4 iterations for v1.30a and 1
-	 * iteration for others.
+	 * (v1.31a), iMX865(v2.13a) and multiple Allwinner SoCs (v1.32a)
+	 * have been identified as needing the workaround,
+	 * with 4 iterations for v1.30a and 1 iteration for others.
 	 * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing
 	 * the workaround with a single iteration.
 	 * The Rockchip RK3288 SoC (v2.00a) and RK3328/RK3399 SoCs (v2.11a) have
@@ -2106,6 +2106,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
 	case 0x201a:
 	case 0x211a:
 	case 0x212a:
+	case 0x213a:
 		count = 1;
 		break;
 	default:
-- 
2.25.1


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

* [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
@ 2022-04-06  8:48   ` Sandor.yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

From: Sandor Yu <Sandor.yu@nxp.com>

iMX865 HDMI (v2.13a) have been identified as needing the workaround.
Tests show that one iteration is enough.

Without the workaround, iMX865 HDMI audio may not work
after cable plugout/in, because HDMI mode is not really set in
register HDMI_FC_INVIDCONF.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 4befc104d220..b11577de4836 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2087,9 +2087,9 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
 	 *
 	 * The number of iterations matters and depends on the HDMI TX revision
 	 * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
-	 * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
-	 * as needing the workaround, with 4 iterations for v1.30a and 1
-	 * iteration for others.
+	 * (v1.31a), iMX865(v2.13a) and multiple Allwinner SoCs (v1.32a)
+	 * have been identified as needing the workaround,
+	 * with 4 iterations for v1.30a and 1 iteration for others.
 	 * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing
 	 * the workaround with a single iteration.
 	 * The Rockchip RK3288 SoC (v2.00a) and RK3328/RK3399 SoCs (v2.11a) have
@@ -2106,6 +2106,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
 	case 0x201a:
 	case 0x211a:
 	case 0x212a:
+	case 0x213a:
 		count = 1;
 		break;
 	default:
-- 
2.25.1


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

* [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for Deep Color
  2022-04-06  8:48 ` Sandor.yu
@ 2022-04-06  8:48   ` Sandor.yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

From: Sandor Yu <Sandor.yu@nxp.com>

HDMI1.4b specification section 6.5.3:
Source shall only send GCPs with non-zero CD to sinks
that indicate support for Deep Color.

DW HDMI GPC default enabled, clear gpc_auto bit for bpp 24.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index b11577de4836..c7b11582529e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1160,6 +1160,14 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
 	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
 
+	val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3);
+	if (color_depth == 4)
+		/* disable Auto GCP when bpp 24 */
+		val &= ~0x4;
+	else
+		val |= 0x4;
+	hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
+
 	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
 		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
 
-- 
2.25.1


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

* [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for Deep Color
@ 2022-04-06  8:48   ` Sandor.yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

From: Sandor Yu <Sandor.yu@nxp.com>

HDMI1.4b specification section 6.5.3:
Source shall only send GCPs with non-zero CD to sinks
that indicate support for Deep Color.

DW HDMI GPC default enabled, clear gpc_auto bit for bpp 24.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index b11577de4836..c7b11582529e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1160,6 +1160,14 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
 	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
 
+	val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3);
+	if (color_depth == 4)
+		/* disable Auto GCP when bpp 24 */
+		val &= ~0x4;
+	else
+		val |= 0x4;
+	hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
+
 	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
 		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
 
-- 
2.25.1


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

* [PATCH v1 4/5] drm: bridge: dw_hdmi: add reset function for PHY GEN1
  2022-04-06  8:48 ` Sandor.yu
@ 2022-04-06  8:48   ` Sandor.yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

From: Sandor Yu <Sandor.yu@nxp.com>

PHY reset register(MC_PHYRSTZ) active high reset control for PHY GEN2,
and active low reset control for PHY GEN1.

Rename function dw_hdmi_phy_reset to dw_hdmi_phy_gen2_reset.
Add dw_hdmi_phy_gen1_reset function for PHY GEN1.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 14 +++++++++++---
 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c    |  2 +-
 include/drm/bridge/dw_hdmi.h              |  4 +++-
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index c7b11582529e..c6e701acd416 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1365,13 +1365,21 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
 			 HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
-void dw_hdmi_phy_reset(struct dw_hdmi *hdmi)
+void dw_hdmi_phy_gen1_reset(struct dw_hdmi *hdmi)
+{
+	/* PHY reset. The reset signal is active low on Gen1 PHYs. */
+	hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen1_reset);
+
+void dw_hdmi_phy_gen2_reset(struct dw_hdmi *hdmi)
 {
 	/* PHY reset. The reset signal is active high on Gen2 PHYs. */
 	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
 	hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
 }
-EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_reset);
 
 void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address)
 {
@@ -1525,7 +1533,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi,
 	if (phy->has_svsret)
 		dw_hdmi_phy_enable_svsret(hdmi, 1);
 
-	dw_hdmi_phy_reset(hdmi);
+	dw_hdmi_phy_gen2_reset(hdmi);
 
 	hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 5e2b0175df36..2860e6bff8b7 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -135,7 +135,7 @@ static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
 	dw_hdmi_phy_gen2_txpwron(hdmi, 0);
 	dw_hdmi_phy_gen2_pddq(hdmi, 1);
 
-	dw_hdmi_phy_reset(hdmi);
+	dw_hdmi_phy_gen2_reset(hdmi);
 
 	dw_hdmi_phy_gen2_pddq(hdmi, 0);
 
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 2a1f85f9a8a3..70082f80a8c8 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -187,9 +187,11 @@ void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
 void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
 			   unsigned char addr);
 
+void dw_hdmi_phy_gen1_reset(struct dw_hdmi *hdmi);
+
 void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable);
 void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable);
-void dw_hdmi_phy_reset(struct dw_hdmi *hdmi);
+void dw_hdmi_phy_gen2_reset(struct dw_hdmi *hdmi);
 
 enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
 					       void *data);
-- 
2.25.1


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

* [PATCH v1 4/5] drm: bridge: dw_hdmi: add reset function for PHY GEN1
@ 2022-04-06  8:48   ` Sandor.yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

From: Sandor Yu <Sandor.yu@nxp.com>

PHY reset register(MC_PHYRSTZ) active high reset control for PHY GEN2,
and active low reset control for PHY GEN1.

Rename function dw_hdmi_phy_reset to dw_hdmi_phy_gen2_reset.
Add dw_hdmi_phy_gen1_reset function for PHY GEN1.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 14 +++++++++++---
 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c    |  2 +-
 include/drm/bridge/dw_hdmi.h              |  4 +++-
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index c7b11582529e..c6e701acd416 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1365,13 +1365,21 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
 			 HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
-void dw_hdmi_phy_reset(struct dw_hdmi *hdmi)
+void dw_hdmi_phy_gen1_reset(struct dw_hdmi *hdmi)
+{
+	/* PHY reset. The reset signal is active low on Gen1 PHYs. */
+	hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen1_reset);
+
+void dw_hdmi_phy_gen2_reset(struct dw_hdmi *hdmi)
 {
 	/* PHY reset. The reset signal is active high on Gen2 PHYs. */
 	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
 	hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
 }
-EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_reset);
 
 void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address)
 {
@@ -1525,7 +1533,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi,
 	if (phy->has_svsret)
 		dw_hdmi_phy_enable_svsret(hdmi, 1);
 
-	dw_hdmi_phy_reset(hdmi);
+	dw_hdmi_phy_gen2_reset(hdmi);
 
 	hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 5e2b0175df36..2860e6bff8b7 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -135,7 +135,7 @@ static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
 	dw_hdmi_phy_gen2_txpwron(hdmi, 0);
 	dw_hdmi_phy_gen2_pddq(hdmi, 1);
 
-	dw_hdmi_phy_reset(hdmi);
+	dw_hdmi_phy_gen2_reset(hdmi);
 
 	dw_hdmi_phy_gen2_pddq(hdmi, 0);
 
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 2a1f85f9a8a3..70082f80a8c8 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -187,9 +187,11 @@ void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
 void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
 			   unsigned char addr);
 
+void dw_hdmi_phy_gen1_reset(struct dw_hdmi *hdmi);
+
 void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable);
 void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable);
-void dw_hdmi_phy_reset(struct dw_hdmi *hdmi);
+void dw_hdmi_phy_gen2_reset(struct dw_hdmi *hdmi);
 
 enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
 					       void *data);
-- 
2.25.1


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

* [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver
  2022-04-06  8:48 ` Sandor.yu
@ 2022-04-06  8:48   ` Sandor.yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

From: Sandor Yu <Sandor.yu@nxp.com>

General Parallel Audio (GPA) interface is one of the supported
audio interface for synopsys HDMI module, which has verified for
i.MX8MP platform.
This is initial version for GPA.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
 drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
 .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199 ++++++++++++++++++
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 128 ++++++++++-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
 include/drm/bridge/dw_hdmi.h                  |   5 +
 6 files changed, 354 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c

diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/bridge/synopsys/Kconfig
index 21a1be3ced0f..e398b58c996d 100644
--- a/drivers/gpu/drm/bridge/synopsys/Kconfig
+++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
@@ -25,6 +25,17 @@ config DRM_DW_HDMI_I2S_AUDIO
 	  Support the I2S Audio interface which is part of the Synopsys
 	  Designware HDMI block.
 
+config DRM_DW_HDMI_GP_AUDIO
+	tristate "Synopsys Designware GP Audio interface"
+	depends on DRM_DW_HDMI && SND
+	select SND_PCM
+	select SND_PCM_ELD
+	select SND_PCM_IEC958
+	help
+	  Support the GP Audio interface which is part of the Synopsys
+	  Designware HDMI block.  This is used in conjunction with
+	  the i.MX865 HDMI driver.
+
 config DRM_DW_HDMI_CEC
 	tristate "Synopsis Designware CEC interface"
 	depends on DRM_DW_HDMI
diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile
index 91d746ad5de1..ce715562e9e5 100644
--- a/drivers/gpu/drm/bridge/synopsys/Makefile
+++ b/drivers/gpu/drm/bridge/synopsys/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
 obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
+obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o
 obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
 obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
 
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
new file mode 100644
index 000000000000..10a957c85a83
--- /dev/null
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * dw-hdmi-gp-audio.c
+ *
+ * Copyright 2020-2022 NXP
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <drm/bridge/dw_hdmi.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_connector.h>
+
+#include <sound/hdmi-codec.h>
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_drm_eld.h>
+#include <sound/pcm_iec958.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-gp-audio"
+#define DRV_NAME    "hdmi-gp-audio"
+
+struct snd_dw_hdmi {
+	struct dw_hdmi_audio_data data;
+	struct platform_device  *audio_pdev;
+	unsigned int pos;
+};
+
+struct dw_hdmi_channel_conf {
+	u8 conf1;
+	u8 ca;
+};
+
+/*
+ * The default mapping of ALSA channels to HDMI channels and speaker
+ * allocation bits.  Note that we can't do channel remapping here -
+ * channels must be in the same order.
+ *
+ * Mappings for alsa-lib pcm/surround*.conf files:
+ *
+ *		Front	Sur4.0	Sur4.1	Sur5.0	Sur5.1	Sur7.1
+ * Channels	2	4	6	6	6	8
+ *
+ * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel:
+ *
+ *				Number of ALSA channels
+ * ALSA Channel	2	3	4	5	6	7	8
+ * 0		FL:0	=	=	=	=	=	=
+ * 1		FR:1	=	=	=	=	=	=
+ * 2			FC:3	RL:4	LFE:2	=	=	=
+ * 3				RR:5	RL:4	FC:3	=	=
+ * 4					RR:5	RL:4	=	=
+ * 5						RR:5	=	=
+ * 6							RC:6	=
+ * 7							RLC/FRC	RLC/FRC
+ */
+static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
+	{ 0x03, 0x00 },	/* FL,FR */
+	{ 0x0b, 0x02 },	/* FL,FR,FC */
+	{ 0x33, 0x08 },	/* FL,FR,RL,RR */
+	{ 0x37, 0x09 },	/* FL,FR,LFE,RL,RR */
+	{ 0x3f, 0x0b },	/* FL,FR,LFE,FC,RL,RR */
+	{ 0x7f, 0x0f },	/* FL,FR,LFE,FC,RL,RR,RC */
+	{ 0xff, 0x13 },	/* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */
+};
+
+static int audio_hw_params(struct device *dev,  void *data,
+			   struct hdmi_codec_daifmt *daifmt,
+			   struct hdmi_codec_params *params)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+	int ret = 0;
+	u8 ca;
+
+	dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
+
+	ca = default_hdmi_channel_config[params->channels - 2].ca;
+
+	dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
+	dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
+
+	dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
+				   params->iec.status[0] & IEC958_AES0_NONAUDIO);
+	dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
+
+	return ret;
+}
+
+static void audio_shutdown(struct device *dev, void *data)
+{
+}
+
+static int audio_mute_stream(struct device *dev, void *data,
+			      bool enable, int direction)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (!enable)
+		dw_hdmi_audio_enable(dw->data.hdmi);
+	else
+		dw_hdmi_audio_disable(dw->data.hdmi);
+
+	return ret;
+}
+
+static int audio_get_eld(struct device *dev, void *data,
+			 u8 *buf, size_t len)
+{
+	struct dw_hdmi_audio_data *audio = data;
+	u8 *eld;
+
+	eld = audio->get_eld(audio->hdmi);
+	if (eld)
+		memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
+	else
+		/* Pass en empty ELD if connector not available */
+		memset(buf, 0, len);
+
+	return 0;
+}
+
+static int audio_hook_plugged_cb(struct device *dev, void *data,
+				 hdmi_codec_plugged_cb fn,
+				 struct device *codec_dev)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+	return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev);
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+	.hw_params = audio_hw_params,
+	.audio_shutdown = audio_shutdown,
+	.mute_stream = audio_mute_stream,
+	.get_eld = audio_get_eld,
+	.hook_plugged_cb = audio_hook_plugged_cb,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
+	struct snd_dw_hdmi *dw;
+
+	const struct hdmi_codec_pdata codec_data = {
+		.i2s = 1,
+		.spdif = 0,
+		.ops = &audio_codec_ops,
+		.max_i2s_channels = 8,
+		.data = data,
+	};
+
+	dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
+	if (!dw)
+		return -ENOMEM;
+
+	dw->data = *data;
+
+	platform_set_drvdata(pdev, dw);
+
+	dw->audio_pdev = platform_device_register_data(&pdev->dev,
+						       HDMI_CODEC_DRV_NAME, 1,
+						       &codec_data,
+						       sizeof(codec_data));
+
+	return PTR_ERR_OR_ZERO(dw->audio_pdev);
+}
+
+static int snd_dw_hdmi_remove(struct platform_device *pdev)
+{
+	struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
+
+	platform_device_unregister(dw->audio_pdev);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.remove	= snd_dw_hdmi_remove,
+	.driver	= {
+		.name = DRIVER_NAME,
+	},
+};
+
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI GPA ALSA interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index c6e701acd416..1385d8f7870e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -191,7 +191,10 @@ struct dw_hdmi {
 
 	spinlock_t audio_lock;
 	struct mutex audio_mutex;
+	unsigned int sample_non_pcm;
+	unsigned int sample_width;
 	unsigned int sample_rate;
+	unsigned int channels;
 	unsigned int audio_cts;
 	unsigned int audio_n;
 	bool audio_enable;
@@ -589,6 +592,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
 			n = 4096;
 		else if (pixel_clk == 74176000 || pixel_clk == 148352000)
 			n = 11648;
+		else if (pixel_clk == 297000000)
+			n = 3072;
 		else
 			n = 4096;
 		n *= mult;
@@ -601,6 +606,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
 			n = 17836;
 		else if (pixel_clk == 148352000)
 			n = 8918;
+		else if (pixel_clk == 297000000)
+			n = 4704;
 		else
 			n = 6272;
 		n *= mult;
@@ -615,6 +622,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
 			n = 11648;
 		else if (pixel_clk == 148352000)
 			n = 5824;
+		else if (pixel_clk == 297000000)
+			n = 5120;
 		else
 			n = 6144;
 		n *= mult;
@@ -660,7 +669,7 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
 	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
 
 	/* Only compute CTS when using internal AHB audio */
-	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
+	if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 & HDMI_CONFIG3_GPAUD)) {
 		/*
 		 * Compute the CTS value from the N value.  Note that CTS and N
 		 * can be up to 20 bits in total, so we need 64-bit math.  Also
@@ -702,6 +711,22 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
 	mutex_unlock(&hdmi->audio_mutex);
 }
 
+void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_width = width;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
+
+void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_non_pcm = non_pcm;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
+
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
 {
 	mutex_lock(&hdmi->audio_mutex);
@@ -717,6 +742,7 @@ void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt)
 	u8 layout;
 
 	mutex_lock(&hdmi->audio_mutex);
+	hdmi->channels = cnt;
 
 	/*
 	 * For >2 channel PCM audio, we need to select layout 1
@@ -765,6 +791,87 @@ static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi)
 	return hdmi->curr_conn->eld;
 }
 
+static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
+{
+	int sample_freq = 0x2, org_sample_freq = 0xD;
+	int ch_mask = BIT(hdmi->channels) - 1;
+
+	switch (hdmi->sample_rate) {
+	case 32000:
+		sample_freq = 0x03;
+		org_sample_freq = 0x0C;
+		break;
+	case 44100:
+		sample_freq = 0x00;
+		org_sample_freq = 0x0F;
+		break;
+	case 48000:
+		sample_freq = 0x02;
+		org_sample_freq = 0x0D;
+		break;
+	case 88200:
+		sample_freq = 0x08;
+		org_sample_freq = 0x07;
+		break;
+	case 96000:
+		sample_freq = 0x0A;
+		org_sample_freq = 0x05;
+		break;
+	case 176400:
+		sample_freq = 0x0C;
+		org_sample_freq = 0x03;
+		break;
+	case 192000:
+		sample_freq = 0x0E;
+		org_sample_freq = 0x01;
+		break;
+	default:
+		break;
+	}
+
+	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
+	hdmi_enable_audio_clk(hdmi, true);
+
+	hdmi_writeb(hdmi, 0x1, HDMI_FC_AUDSCHNLS0);
+	hdmi_writeb(hdmi, hdmi->channels, HDMI_FC_AUDSCHNLS2);
+	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS3);
+	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS4);
+	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS5);
+	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS6);
+	hdmi_writeb(hdmi, (0x3 << 4) | sample_freq, HDMI_FC_AUDSCHNLS7);
+	hdmi_writeb(hdmi, (org_sample_freq << 4) | 0xb, HDMI_FC_AUDSCHNLS8);
+
+	hdmi_writeb(hdmi, ch_mask, HDMI_GP_CONF1);
+	hdmi_writeb(hdmi, 0x02, HDMI_GP_CONF2);
+	hdmi_writeb(hdmi, 0x01, HDMI_GP_CONF0);
+
+	hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
+
+	/* hbr */
+	if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
+	    hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
+		hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
+	}
+
+	if (hdmi->phy.ops->enable_audio)
+		hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
+					    hdmi->channels,
+					    hdmi->sample_width,
+					    hdmi->sample_rate,
+					    hdmi->sample_non_pcm);
+}
+
+static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)
+{
+	hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
+
+	hdmi_modb(hdmi,  0, 0x3, HDMI_FC_DATAUTO3);
+	if (hdmi->phy.ops->disable_audio)
+		hdmi->phy.ops->disable_audio(hdmi, hdmi->phy.data);
+
+	hdmi_enable_audio_clk(hdmi, false);
+}
+
 static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
 {
 	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
@@ -3259,6 +3366,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
 	hdmi->plat_data = plat_data;
 	hdmi->dev = dev;
 	hdmi->sample_rate = 48000;
+	hdmi->channels = 2;
 	hdmi->disabled = true;
 	hdmi->rxsense = true;
 	hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
@@ -3482,6 +3590,24 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
 		pdevinfo.size_data = sizeof(audio);
 		pdevinfo.dma_mask = DMA_BIT_MASK(32);
 		hdmi->audio = platform_device_register_full(&pdevinfo);
+	} else if (iores && config3 & HDMI_CONFIG3_GPAUD) {
+		struct dw_hdmi_audio_data audio;
+
+		audio.phys = iores->start;
+		audio.base = hdmi->regs;
+		audio.irq = irq;
+		audio.hdmi = hdmi;
+		audio.get_eld = hdmi_audio_get_eld;
+
+		hdmi->enable_audio = dw_hdmi_gp_audio_enable;
+		hdmi->disable_audio = dw_hdmi_gp_audio_disable;
+
+		pdevinfo.name = "dw-hdmi-gp-audio";
+		pdevinfo.id = PLATFORM_DEVID_NONE;
+		pdevinfo.data = &audio;
+		pdevinfo.size_data = sizeof(audio);
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
 	if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) {
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
index 1999db05bc3b..99aa1c03343b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
@@ -158,8 +158,17 @@
 #define HDMI_FC_SPDDEVICEINF                    0x1062
 #define HDMI_FC_AUDSCONF                        0x1063
 #define HDMI_FC_AUDSSTAT                        0x1064
-#define HDMI_FC_AUDSCHNLS7                      0x106e
-#define HDMI_FC_AUDSCHNLS8                      0x106f
+#define HDMI_FC_AUDSV                           0x1065
+#define HDMI_FC_AUDSU                           0x1066
+#define HDMI_FC_AUDSCHNLS0                       0x1067
+#define HDMI_FC_AUDSCHNLS1                       0x1068
+#define HDMI_FC_AUDSCHNLS2                       0x1069
+#define HDMI_FC_AUDSCHNLS3                       0x106A
+#define HDMI_FC_AUDSCHNLS4                       0x106B
+#define HDMI_FC_AUDSCHNLS5                       0x106C
+#define HDMI_FC_AUDSCHNLS6                       0x106D
+#define HDMI_FC_AUDSCHNLS7                       0x106E
+#define HDMI_FC_AUDSCHNLS8                       0x106F
 #define HDMI_FC_DATACH0FILL                     0x1070
 #define HDMI_FC_DATACH1FILL                     0x1071
 #define HDMI_FC_DATACH2FILL                     0x1072
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 70082f80a8c8..7f73c3398a54 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -121,6 +121,9 @@ struct dw_hdmi_phy_ops {
 	void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
 			   bool force, bool disabled, bool rxsense);
 	void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
+	void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel,
+			     int width, int rate, int non_pcm);
+	void (*disable_audio)(struct dw_hdmi *hdmi, void *data);
 };
 
 struct dw_hdmi_plat_data {
@@ -173,6 +176,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
 
 int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
 			   struct device *codec_dev);
+void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm);
+void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width);
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt);
 void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status);
-- 
2.25.1


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

* [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver
@ 2022-04-06  8:48   ` Sandor.yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor.yu @ 2022-04-06  8:48 UTC (permalink / raw)
  To: dri-devel, linux-kernel, andrzej.hajda, narmstrong, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: Sandor.yu, shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

From: Sandor Yu <Sandor.yu@nxp.com>

General Parallel Audio (GPA) interface is one of the supported
audio interface for synopsys HDMI module, which has verified for
i.MX8MP platform.
This is initial version for GPA.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
 drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
 .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199 ++++++++++++++++++
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 128 ++++++++++-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
 include/drm/bridge/dw_hdmi.h                  |   5 +
 6 files changed, 354 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c

diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/bridge/synopsys/Kconfig
index 21a1be3ced0f..e398b58c996d 100644
--- a/drivers/gpu/drm/bridge/synopsys/Kconfig
+++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
@@ -25,6 +25,17 @@ config DRM_DW_HDMI_I2S_AUDIO
 	  Support the I2S Audio interface which is part of the Synopsys
 	  Designware HDMI block.
 
+config DRM_DW_HDMI_GP_AUDIO
+	tristate "Synopsys Designware GP Audio interface"
+	depends on DRM_DW_HDMI && SND
+	select SND_PCM
+	select SND_PCM_ELD
+	select SND_PCM_IEC958
+	help
+	  Support the GP Audio interface which is part of the Synopsys
+	  Designware HDMI block.  This is used in conjunction with
+	  the i.MX865 HDMI driver.
+
 config DRM_DW_HDMI_CEC
 	tristate "Synopsis Designware CEC interface"
 	depends on DRM_DW_HDMI
diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile
index 91d746ad5de1..ce715562e9e5 100644
--- a/drivers/gpu/drm/bridge/synopsys/Makefile
+++ b/drivers/gpu/drm/bridge/synopsys/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
 obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
+obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o
 obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
 obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
 
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
new file mode 100644
index 000000000000..10a957c85a83
--- /dev/null
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * dw-hdmi-gp-audio.c
+ *
+ * Copyright 2020-2022 NXP
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <drm/bridge/dw_hdmi.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_connector.h>
+
+#include <sound/hdmi-codec.h>
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_drm_eld.h>
+#include <sound/pcm_iec958.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-gp-audio"
+#define DRV_NAME    "hdmi-gp-audio"
+
+struct snd_dw_hdmi {
+	struct dw_hdmi_audio_data data;
+	struct platform_device  *audio_pdev;
+	unsigned int pos;
+};
+
+struct dw_hdmi_channel_conf {
+	u8 conf1;
+	u8 ca;
+};
+
+/*
+ * The default mapping of ALSA channels to HDMI channels and speaker
+ * allocation bits.  Note that we can't do channel remapping here -
+ * channels must be in the same order.
+ *
+ * Mappings for alsa-lib pcm/surround*.conf files:
+ *
+ *		Front	Sur4.0	Sur4.1	Sur5.0	Sur5.1	Sur7.1
+ * Channels	2	4	6	6	6	8
+ *
+ * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel:
+ *
+ *				Number of ALSA channels
+ * ALSA Channel	2	3	4	5	6	7	8
+ * 0		FL:0	=	=	=	=	=	=
+ * 1		FR:1	=	=	=	=	=	=
+ * 2			FC:3	RL:4	LFE:2	=	=	=
+ * 3				RR:5	RL:4	FC:3	=	=
+ * 4					RR:5	RL:4	=	=
+ * 5						RR:5	=	=
+ * 6							RC:6	=
+ * 7							RLC/FRC	RLC/FRC
+ */
+static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
+	{ 0x03, 0x00 },	/* FL,FR */
+	{ 0x0b, 0x02 },	/* FL,FR,FC */
+	{ 0x33, 0x08 },	/* FL,FR,RL,RR */
+	{ 0x37, 0x09 },	/* FL,FR,LFE,RL,RR */
+	{ 0x3f, 0x0b },	/* FL,FR,LFE,FC,RL,RR */
+	{ 0x7f, 0x0f },	/* FL,FR,LFE,FC,RL,RR,RC */
+	{ 0xff, 0x13 },	/* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */
+};
+
+static int audio_hw_params(struct device *dev,  void *data,
+			   struct hdmi_codec_daifmt *daifmt,
+			   struct hdmi_codec_params *params)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+	int ret = 0;
+	u8 ca;
+
+	dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
+
+	ca = default_hdmi_channel_config[params->channels - 2].ca;
+
+	dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
+	dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
+
+	dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
+				   params->iec.status[0] & IEC958_AES0_NONAUDIO);
+	dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
+
+	return ret;
+}
+
+static void audio_shutdown(struct device *dev, void *data)
+{
+}
+
+static int audio_mute_stream(struct device *dev, void *data,
+			      bool enable, int direction)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (!enable)
+		dw_hdmi_audio_enable(dw->data.hdmi);
+	else
+		dw_hdmi_audio_disable(dw->data.hdmi);
+
+	return ret;
+}
+
+static int audio_get_eld(struct device *dev, void *data,
+			 u8 *buf, size_t len)
+{
+	struct dw_hdmi_audio_data *audio = data;
+	u8 *eld;
+
+	eld = audio->get_eld(audio->hdmi);
+	if (eld)
+		memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
+	else
+		/* Pass en empty ELD if connector not available */
+		memset(buf, 0, len);
+
+	return 0;
+}
+
+static int audio_hook_plugged_cb(struct device *dev, void *data,
+				 hdmi_codec_plugged_cb fn,
+				 struct device *codec_dev)
+{
+	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
+
+	return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev);
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+	.hw_params = audio_hw_params,
+	.audio_shutdown = audio_shutdown,
+	.mute_stream = audio_mute_stream,
+	.get_eld = audio_get_eld,
+	.hook_plugged_cb = audio_hook_plugged_cb,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
+	struct snd_dw_hdmi *dw;
+
+	const struct hdmi_codec_pdata codec_data = {
+		.i2s = 1,
+		.spdif = 0,
+		.ops = &audio_codec_ops,
+		.max_i2s_channels = 8,
+		.data = data,
+	};
+
+	dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
+	if (!dw)
+		return -ENOMEM;
+
+	dw->data = *data;
+
+	platform_set_drvdata(pdev, dw);
+
+	dw->audio_pdev = platform_device_register_data(&pdev->dev,
+						       HDMI_CODEC_DRV_NAME, 1,
+						       &codec_data,
+						       sizeof(codec_data));
+
+	return PTR_ERR_OR_ZERO(dw->audio_pdev);
+}
+
+static int snd_dw_hdmi_remove(struct platform_device *pdev)
+{
+	struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
+
+	platform_device_unregister(dw->audio_pdev);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.remove	= snd_dw_hdmi_remove,
+	.driver	= {
+		.name = DRIVER_NAME,
+	},
+};
+
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI GPA ALSA interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index c6e701acd416..1385d8f7870e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -191,7 +191,10 @@ struct dw_hdmi {
 
 	spinlock_t audio_lock;
 	struct mutex audio_mutex;
+	unsigned int sample_non_pcm;
+	unsigned int sample_width;
 	unsigned int sample_rate;
+	unsigned int channels;
 	unsigned int audio_cts;
 	unsigned int audio_n;
 	bool audio_enable;
@@ -589,6 +592,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
 			n = 4096;
 		else if (pixel_clk == 74176000 || pixel_clk == 148352000)
 			n = 11648;
+		else if (pixel_clk == 297000000)
+			n = 3072;
 		else
 			n = 4096;
 		n *= mult;
@@ -601,6 +606,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
 			n = 17836;
 		else if (pixel_clk == 148352000)
 			n = 8918;
+		else if (pixel_clk == 297000000)
+			n = 4704;
 		else
 			n = 6272;
 		n *= mult;
@@ -615,6 +622,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
 			n = 11648;
 		else if (pixel_clk == 148352000)
 			n = 5824;
+		else if (pixel_clk == 297000000)
+			n = 5120;
 		else
 			n = 6144;
 		n *= mult;
@@ -660,7 +669,7 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
 	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
 
 	/* Only compute CTS when using internal AHB audio */
-	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
+	if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 & HDMI_CONFIG3_GPAUD)) {
 		/*
 		 * Compute the CTS value from the N value.  Note that CTS and N
 		 * can be up to 20 bits in total, so we need 64-bit math.  Also
@@ -702,6 +711,22 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
 	mutex_unlock(&hdmi->audio_mutex);
 }
 
+void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_width = width;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
+
+void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_non_pcm = non_pcm;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
+
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
 {
 	mutex_lock(&hdmi->audio_mutex);
@@ -717,6 +742,7 @@ void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt)
 	u8 layout;
 
 	mutex_lock(&hdmi->audio_mutex);
+	hdmi->channels = cnt;
 
 	/*
 	 * For >2 channel PCM audio, we need to select layout 1
@@ -765,6 +791,87 @@ static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi)
 	return hdmi->curr_conn->eld;
 }
 
+static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
+{
+	int sample_freq = 0x2, org_sample_freq = 0xD;
+	int ch_mask = BIT(hdmi->channels) - 1;
+
+	switch (hdmi->sample_rate) {
+	case 32000:
+		sample_freq = 0x03;
+		org_sample_freq = 0x0C;
+		break;
+	case 44100:
+		sample_freq = 0x00;
+		org_sample_freq = 0x0F;
+		break;
+	case 48000:
+		sample_freq = 0x02;
+		org_sample_freq = 0x0D;
+		break;
+	case 88200:
+		sample_freq = 0x08;
+		org_sample_freq = 0x07;
+		break;
+	case 96000:
+		sample_freq = 0x0A;
+		org_sample_freq = 0x05;
+		break;
+	case 176400:
+		sample_freq = 0x0C;
+		org_sample_freq = 0x03;
+		break;
+	case 192000:
+		sample_freq = 0x0E;
+		org_sample_freq = 0x01;
+		break;
+	default:
+		break;
+	}
+
+	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
+	hdmi_enable_audio_clk(hdmi, true);
+
+	hdmi_writeb(hdmi, 0x1, HDMI_FC_AUDSCHNLS0);
+	hdmi_writeb(hdmi, hdmi->channels, HDMI_FC_AUDSCHNLS2);
+	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS3);
+	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS4);
+	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS5);
+	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS6);
+	hdmi_writeb(hdmi, (0x3 << 4) | sample_freq, HDMI_FC_AUDSCHNLS7);
+	hdmi_writeb(hdmi, (org_sample_freq << 4) | 0xb, HDMI_FC_AUDSCHNLS8);
+
+	hdmi_writeb(hdmi, ch_mask, HDMI_GP_CONF1);
+	hdmi_writeb(hdmi, 0x02, HDMI_GP_CONF2);
+	hdmi_writeb(hdmi, 0x01, HDMI_GP_CONF0);
+
+	hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
+
+	/* hbr */
+	if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
+	    hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
+		hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
+	}
+
+	if (hdmi->phy.ops->enable_audio)
+		hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
+					    hdmi->channels,
+					    hdmi->sample_width,
+					    hdmi->sample_rate,
+					    hdmi->sample_non_pcm);
+}
+
+static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)
+{
+	hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
+
+	hdmi_modb(hdmi,  0, 0x3, HDMI_FC_DATAUTO3);
+	if (hdmi->phy.ops->disable_audio)
+		hdmi->phy.ops->disable_audio(hdmi, hdmi->phy.data);
+
+	hdmi_enable_audio_clk(hdmi, false);
+}
+
 static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
 {
 	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
@@ -3259,6 +3366,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
 	hdmi->plat_data = plat_data;
 	hdmi->dev = dev;
 	hdmi->sample_rate = 48000;
+	hdmi->channels = 2;
 	hdmi->disabled = true;
 	hdmi->rxsense = true;
 	hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
@@ -3482,6 +3590,24 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
 		pdevinfo.size_data = sizeof(audio);
 		pdevinfo.dma_mask = DMA_BIT_MASK(32);
 		hdmi->audio = platform_device_register_full(&pdevinfo);
+	} else if (iores && config3 & HDMI_CONFIG3_GPAUD) {
+		struct dw_hdmi_audio_data audio;
+
+		audio.phys = iores->start;
+		audio.base = hdmi->regs;
+		audio.irq = irq;
+		audio.hdmi = hdmi;
+		audio.get_eld = hdmi_audio_get_eld;
+
+		hdmi->enable_audio = dw_hdmi_gp_audio_enable;
+		hdmi->disable_audio = dw_hdmi_gp_audio_disable;
+
+		pdevinfo.name = "dw-hdmi-gp-audio";
+		pdevinfo.id = PLATFORM_DEVID_NONE;
+		pdevinfo.data = &audio;
+		pdevinfo.size_data = sizeof(audio);
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
 	if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) {
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
index 1999db05bc3b..99aa1c03343b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
@@ -158,8 +158,17 @@
 #define HDMI_FC_SPDDEVICEINF                    0x1062
 #define HDMI_FC_AUDSCONF                        0x1063
 #define HDMI_FC_AUDSSTAT                        0x1064
-#define HDMI_FC_AUDSCHNLS7                      0x106e
-#define HDMI_FC_AUDSCHNLS8                      0x106f
+#define HDMI_FC_AUDSV                           0x1065
+#define HDMI_FC_AUDSU                           0x1066
+#define HDMI_FC_AUDSCHNLS0                       0x1067
+#define HDMI_FC_AUDSCHNLS1                       0x1068
+#define HDMI_FC_AUDSCHNLS2                       0x1069
+#define HDMI_FC_AUDSCHNLS3                       0x106A
+#define HDMI_FC_AUDSCHNLS4                       0x106B
+#define HDMI_FC_AUDSCHNLS5                       0x106C
+#define HDMI_FC_AUDSCHNLS6                       0x106D
+#define HDMI_FC_AUDSCHNLS7                       0x106E
+#define HDMI_FC_AUDSCHNLS8                       0x106F
 #define HDMI_FC_DATACH0FILL                     0x1070
 #define HDMI_FC_DATACH1FILL                     0x1071
 #define HDMI_FC_DATACH2FILL                     0x1072
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 70082f80a8c8..7f73c3398a54 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -121,6 +121,9 @@ struct dw_hdmi_phy_ops {
 	void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
 			   bool force, bool disabled, bool rxsense);
 	void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
+	void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel,
+			     int width, int rate, int non_pcm);
+	void (*disable_audio)(struct dw_hdmi *hdmi, void *data);
 };
 
 struct dw_hdmi_plat_data {
@@ -173,6 +176,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
 
 int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
 			   struct device *codec_dev);
+void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm);
+void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width);
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt);
 void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status);
-- 
2.25.1


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

* Re: [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
  2022-04-06  8:48   ` Sandor.yu
@ 2022-04-06  9:17     ` Neil Armstrong
  -1 siblings, 0 replies; 32+ messages in thread
From: Neil Armstrong @ 2022-04-06  9:17 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

Hi,

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> iMX865 HDMI (v2.13a) have been identified as needing the workaround.
> Tests show that one iteration is enough.
> 
> Without the workaround, iMX865 HDMI audio may not work
> after cable plugout/in, because HDMI mode is not really set in
> register HDMI_FC_INVIDCONF.
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 ++++---
>   1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 4befc104d220..b11577de4836 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2087,9 +2087,9 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
>   	 *
>   	 * The number of iterations matters and depends on the HDMI TX revision
>   	 * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
> -	 * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
> -	 * as needing the workaround, with 4 iterations for v1.30a and 1
> -	 * iteration for others.
> +	 * (v1.31a), iMX865(v2.13a) and multiple Allwinner SoCs (v1.32a)
> +	 * have been identified as needing the workaround,
> +	 * with 4 iterations for v1.30a and 1 iteration for others.
>   	 * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing
>   	 * the workaround with a single iteration.
>   	 * The Rockchip RK3288 SoC (v2.00a) and RK3328/RK3399 SoCs (v2.11a) have
> @@ -2106,6 +2106,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
>   	case 0x201a:
>   	case 0x211a:
>   	case 0x212a:
> +	case 0x213a:
>   		count = 1;
>   		break;

At some point we must consider only v1.30a needs 4, and other needs 1.

It would be simpler to put the "count = 1" in a default case.

The comment change is still welcome so we can track.

Thanks,
Neil

>   	default:


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

* Re: [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
@ 2022-04-06  9:17     ` Neil Armstrong
  0 siblings, 0 replies; 32+ messages in thread
From: Neil Armstrong @ 2022-04-06  9:17 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

Hi,

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> iMX865 HDMI (v2.13a) have been identified as needing the workaround.
> Tests show that one iteration is enough.
> 
> Without the workaround, iMX865 HDMI audio may not work
> after cable plugout/in, because HDMI mode is not really set in
> register HDMI_FC_INVIDCONF.
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 ++++---
>   1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 4befc104d220..b11577de4836 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2087,9 +2087,9 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
>   	 *
>   	 * The number of iterations matters and depends on the HDMI TX revision
>   	 * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
> -	 * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
> -	 * as needing the workaround, with 4 iterations for v1.30a and 1
> -	 * iteration for others.
> +	 * (v1.31a), iMX865(v2.13a) and multiple Allwinner SoCs (v1.32a)
> +	 * have been identified as needing the workaround,
> +	 * with 4 iterations for v1.30a and 1 iteration for others.
>   	 * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing
>   	 * the workaround with a single iteration.
>   	 * The Rockchip RK3288 SoC (v2.00a) and RK3328/RK3399 SoCs (v2.11a) have
> @@ -2106,6 +2106,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
>   	case 0x201a:
>   	case 0x211a:
>   	case 0x212a:
> +	case 0x213a:
>   		count = 1;
>   		break;

At some point we must consider only v1.30a needs 4, and other needs 1.

It would be simpler to put the "count = 1" in a default case.

The comment change is still welcome so we can track.

Thanks,
Neil

>   	default:


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

* Re: [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for Deep Color
  2022-04-06  8:48   ` Sandor.yu
@ 2022-04-06  9:20     ` Neil Armstrong
  -1 siblings, 0 replies; 32+ messages in thread
From: Neil Armstrong @ 2022-04-06  9:20 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> HDMI1.4b specification section 6.5.3:
> Source shall only send GCPs with non-zero CD to sinks
> that indicate support for Deep Color.
> 
> DW HDMI GPC default enabled, clear gpc_auto bit for bpp 24.
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index b11577de4836..c7b11582529e 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -1160,6 +1160,14 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
>   		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
>   	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
>   
> +	val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3);
> +	if (color_depth == 4)
> +		/* disable Auto GCP when bpp 24 */
> +		val &= ~0x4;
> +	else
> +		val |= 0x4;
> +	hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
> +
>   	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
>   		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
>   

Do you handle the case when color_depth == 0 when output is YUV422 ?

Neil

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

* Re: [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for Deep Color
@ 2022-04-06  9:20     ` Neil Armstrong
  0 siblings, 0 replies; 32+ messages in thread
From: Neil Armstrong @ 2022-04-06  9:20 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> HDMI1.4b specification section 6.5.3:
> Source shall only send GCPs with non-zero CD to sinks
> that indicate support for Deep Color.
> 
> DW HDMI GPC default enabled, clear gpc_auto bit for bpp 24.
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index b11577de4836..c7b11582529e 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -1160,6 +1160,14 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
>   		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
>   	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
>   
> +	val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3);
> +	if (color_depth == 4)
> +		/* disable Auto GCP when bpp 24 */
> +		val &= ~0x4;
> +	else
> +		val |= 0x4;
> +	hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
> +
>   	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
>   		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
>   

Do you handle the case when color_depth == 0 when output is YUV422 ?

Neil

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

* Re: [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver
  2022-04-06  8:48   ` Sandor.yu
@ 2022-04-06  9:27     ` Neil Armstrong
  -1 siblings, 0 replies; 32+ messages in thread
From: Neil Armstrong @ 2022-04-06  9:27 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

Hi,

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> General Parallel Audio (GPA) interface is one of the supported
> audio interface for synopsys HDMI module, which has verified for
> i.MX8MP platform.
> This is initial version for GPA.
> 
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>   drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
>   drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
>   .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199 ++++++++++++++++++
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 128 ++++++++++-
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
>   include/drm/bridge/dw_hdmi.h                  |   5 +
>   6 files changed, 354 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/bridge/synopsys/Kconfig
> index 21a1be3ced0f..e398b58c996d 100644
> --- a/drivers/gpu/drm/bridge/synopsys/Kconfig
> +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
> @@ -25,6 +25,17 @@ config DRM_DW_HDMI_I2S_AUDIO
>   	  Support the I2S Audio interface which is part of the Synopsys
>   	  Designware HDMI block.
>   
> +config DRM_DW_HDMI_GP_AUDIO
> +	tristate "Synopsys Designware GP Audio interface"
> +	depends on DRM_DW_HDMI && SND
> +	select SND_PCM
> +	select SND_PCM_ELD
> +	select SND_PCM_IEC958
> +	help
> +	  Support the GP Audio interface which is part of the Synopsys
> +	  Designware HDMI block.  This is used in conjunction with
> +	  the i.MX865 HDMI driver.

What does that mean ? it can only be used with i.MX865 HDMI driver ?
If not, remove reference to i.MX865 HDMI driver.

> +
>   config DRM_DW_HDMI_CEC
>   	tristate "Synopsis Designware CEC interface"
>   	depends on DRM_DW_HDMI
> diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile
> index 91d746ad5de1..ce715562e9e5 100644
> --- a/drivers/gpu/drm/bridge/synopsys/Makefile
> +++ b/drivers/gpu/drm/bridge/synopsys/Makefile
> @@ -1,6 +1,7 @@
>   # SPDX-License-Identifier: GPL-2.0-only
>   obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
>   obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> +obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o
>   obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
>   obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
>   
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> new file mode 100644
> index 000000000000..10a957c85a83
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> @@ -0,0 +1,199 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * dw-hdmi-gp-audio.c
> + *
> + * Copyright 2020-2022 NXP
> + */
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +#include <drm/bridge/dw_hdmi.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drm_connector.h>
> +
> +#include <sound/hdmi-codec.h>
> +#include <sound/asoundef.h>
> +#include <sound/core.h>
> +#include <sound/initval.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_drm_eld.h>
> +#include <sound/pcm_iec958.h>
> +#include <sound/dmaengine_pcm.h>
> +
> +#include "dw-hdmi-audio.h"
> +
> +#define DRIVER_NAME "dw-hdmi-gp-audio"
> +#define DRV_NAME    "hdmi-gp-audio"
> +
> +struct snd_dw_hdmi {
> +	struct dw_hdmi_audio_data data;
> +	struct platform_device  *audio_pdev;
> +	unsigned int pos;
> +};
> +
> +struct dw_hdmi_channel_conf {
> +	u8 conf1;
> +	u8 ca;
> +};
> +
> +/*
> + * The default mapping of ALSA channels to HDMI channels and speaker
> + * allocation bits.  Note that we can't do channel remapping here -
> + * channels must be in the same order.
> + *
> + * Mappings for alsa-lib pcm/surround*.conf files:
> + *
> + *		Front	Sur4.0	Sur4.1	Sur5.0	Sur5.1	Sur7.1
> + * Channels	2	4	6	6	6	8
> + *
> + * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel:
> + *
> + *				Number of ALSA channels
> + * ALSA Channel	2	3	4	5	6	7	8
> + * 0		FL:0	=	=	=	=	=	=
> + * 1		FR:1	=	=	=	=	=	=
> + * 2			FC:3	RL:4	LFE:2	=	=	=
> + * 3				RR:5	RL:4	FC:3	=	=
> + * 4					RR:5	RL:4	=	=
> + * 5						RR:5	=	=
> + * 6							RC:6	=
> + * 7							RLC/FRC	RLC/FRC
> + */
> +static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
> +	{ 0x03, 0x00 },	/* FL,FR */
> +	{ 0x0b, 0x02 },	/* FL,FR,FC */
> +	{ 0x33, 0x08 },	/* FL,FR,RL,RR */
> +	{ 0x37, 0x09 },	/* FL,FR,LFE,RL,RR */
> +	{ 0x3f, 0x0b },	/* FL,FR,LFE,FC,RL,RR */
> +	{ 0x7f, 0x0f },	/* FL,FR,LFE,FC,RL,RR,RC */
> +	{ 0xff, 0x13 },	/* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */
> +};
> +
> +static int audio_hw_params(struct device *dev,  void *data,
> +			   struct hdmi_codec_daifmt *daifmt,
> +			   struct hdmi_codec_params *params)
> +{
> +	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +	int ret = 0;
> +	u8 ca;
> +
> +	dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
> +
> +	ca = default_hdmi_channel_config[params->channels - 2].ca;
> +
> +	dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
> +	dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
> +
> +	dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
> +				   params->iec.status[0] & IEC958_AES0_NONAUDIO);
> +	dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
> +
> +	return ret;
> +}
> +
> +static void audio_shutdown(struct device *dev, void *data)
> +{
> +}
> +
> +static int audio_mute_stream(struct device *dev, void *data,
> +			      bool enable, int direction)
> +{
> +	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	if (!enable)
> +		dw_hdmi_audio_enable(dw->data.hdmi);
> +	else
> +		dw_hdmi_audio_disable(dw->data.hdmi);
> +
> +	return ret;
> +}
> +
> +static int audio_get_eld(struct device *dev, void *data,
> +			 u8 *buf, size_t len)
> +{
> +	struct dw_hdmi_audio_data *audio = data;
> +	u8 *eld;
> +
> +	eld = audio->get_eld(audio->hdmi);
> +	if (eld)
> +		memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
> +	else
> +		/* Pass en empty ELD if connector not available */
> +		memset(buf, 0, len);
> +
> +	return 0;
> +}
> +
> +static int audio_hook_plugged_cb(struct device *dev, void *data,
> +				 hdmi_codec_plugged_cb fn,
> +				 struct device *codec_dev)
> +{
> +	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +
> +	return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev);
> +}
> +
> +static const struct hdmi_codec_ops audio_codec_ops = {
> +	.hw_params = audio_hw_params,
> +	.audio_shutdown = audio_shutdown,
> +	.mute_stream = audio_mute_stream,
> +	.get_eld = audio_get_eld,
> +	.hook_plugged_cb = audio_hook_plugged_cb,
> +};
> +
> +static int snd_dw_hdmi_probe(struct platform_device *pdev)
> +{
> +	struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
> +	struct snd_dw_hdmi *dw;
> +
> +	const struct hdmi_codec_pdata codec_data = {
> +		.i2s = 1,
> +		.spdif = 0,
> +		.ops = &audio_codec_ops,
> +		.max_i2s_channels = 8,
> +		.data = data,
> +	};
> +
> +	dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	dw->data = *data;
> +
> +	platform_set_drvdata(pdev, dw);
> +
> +	dw->audio_pdev = platform_device_register_data(&pdev->dev,
> +						       HDMI_CODEC_DRV_NAME, 1,
> +						       &codec_data,
> +						       sizeof(codec_data));
> +
> +	return PTR_ERR_OR_ZERO(dw->audio_pdev);
> +}
> +
> +static int snd_dw_hdmi_remove(struct platform_device *pdev)
> +{
> +	struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
> +
> +	platform_device_unregister(dw->audio_pdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver snd_dw_hdmi_driver = {
> +	.probe	= snd_dw_hdmi_probe,
> +	.remove	= snd_dw_hdmi_remove,
> +	.driver	= {
> +		.name = DRIVER_NAME,
> +	},
> +};
> +
> +module_platform_driver(snd_dw_hdmi_driver);
> +
> +MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
> +MODULE_DESCRIPTION("Synopsis Designware HDMI GPA ALSA interface");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index c6e701acd416..1385d8f7870e 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -191,7 +191,10 @@ struct dw_hdmi {
>   
>   	spinlock_t audio_lock;
>   	struct mutex audio_mutex;
> +	unsigned int sample_non_pcm;
> +	unsigned int sample_width;
>   	unsigned int sample_rate;
> +	unsigned int channels;
>   	unsigned int audio_cts;
>   	unsigned int audio_n;
>   	bool audio_enable;
> @@ -589,6 +592,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
>   			n = 4096;
>   		else if (pixel_clk == 74176000 || pixel_clk == 148352000)
>   			n = 11648;
> +		else if (pixel_clk == 297000000)
> +			n = 3072;
>   		else
>   			n = 4096;
>   		n *= mult;
> @@ -601,6 +606,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
>   			n = 17836;
>   		else if (pixel_clk == 148352000)
>   			n = 8918;
> +		else if (pixel_clk == 297000000)
> +			n = 4704;
>   		else
>   			n = 6272;
>   		n *= mult;
> @@ -615,6 +622,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
>   			n = 11648;
>   		else if (pixel_clk == 148352000)
>   			n = 5824;
> +		else if (pixel_clk == 297000000)
> +			n = 5120;
>   		else
>   			n = 6144;
>   		n *= mult;
> @@ -660,7 +669,7 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
>   	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
>   
>   	/* Only compute CTS when using internal AHB audio */
> -	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
> +	if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 & HDMI_CONFIG3_GPAUD)) {

Update the comment to include GPAUD.

>   		/*
>   		 * Compute the CTS value from the N value.  Note that CTS and N
>   		 * can be up to 20 bits in total, so we need 64-bit math.  Also
> @@ -702,6 +711,22 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
>   	mutex_unlock(&hdmi->audio_mutex);
>   }
>   
> +void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width)
> +{
> +	mutex_lock(&hdmi->audio_mutex);
> +	hdmi->sample_width = width;
> +	mutex_unlock(&hdmi->audio_mutex);
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
> +
> +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm)
> +{
> +	mutex_lock(&hdmi->audio_mutex);
> +	hdmi->sample_non_pcm = non_pcm;
> +	mutex_unlock(&hdmi->audio_mutex);
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
> +
>   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
>   {
>   	mutex_lock(&hdmi->audio_mutex);
> @@ -717,6 +742,7 @@ void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt)
>   	u8 layout;
>   
>   	mutex_lock(&hdmi->audio_mutex);
> +	hdmi->channels = cnt;
>   
>   	/*
>   	 * For >2 channel PCM audio, we need to select layout 1
> @@ -765,6 +791,87 @@ static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi)
>   	return hdmi->curr_conn->eld;
>   }
>   
> +static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
> +{
> +	int sample_freq = 0x2, org_sample_freq = 0xD;
> +	int ch_mask = BIT(hdmi->channels) - 1;
> +
> +	switch (hdmi->sample_rate) {
> +	case 32000:
> +		sample_freq = 0x03;
> +		org_sample_freq = 0x0C;
> +		break;
> +	case 44100:
> +		sample_freq = 0x00;
> +		org_sample_freq = 0x0F;
> +		break;
> +	case 48000:
> +		sample_freq = 0x02;
> +		org_sample_freq = 0x0D;
> +		break;
> +	case 88200:
> +		sample_freq = 0x08;
> +		org_sample_freq = 0x07;
> +		break;
> +	case 96000:
> +		sample_freq = 0x0A;
> +		org_sample_freq = 0x05;
> +		break;
> +	case 176400:
> +		sample_freq = 0x0C;
> +		org_sample_freq = 0x03;
> +		break;
> +	case 192000:
> +		sample_freq = 0x0E;
> +		org_sample_freq = 0x01;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> +	hdmi_enable_audio_clk(hdmi, true);
> +
> +	hdmi_writeb(hdmi, 0x1, HDMI_FC_AUDSCHNLS0);
> +	hdmi_writeb(hdmi, hdmi->channels, HDMI_FC_AUDSCHNLS2);
> +	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS3);
> +	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS4);
> +	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS5);
> +	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS6);
> +	hdmi_writeb(hdmi, (0x3 << 4) | sample_freq, HDMI_FC_AUDSCHNLS7);
> +	hdmi_writeb(hdmi, (org_sample_freq << 4) | 0xb, HDMI_FC_AUDSCHNLS8);
> +
> +	hdmi_writeb(hdmi, ch_mask, HDMI_GP_CONF1);
> +	hdmi_writeb(hdmi, 0x02, HDMI_GP_CONF2);
> +	hdmi_writeb(hdmi, 0x01, HDMI_GP_CONF0);
> +
> +	hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
> +
> +	/* hbr */
> +	if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
> +	    hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
> +		hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
> +	}
> +
> +	if (hdmi->phy.ops->enable_audio)
> +		hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
> +					    hdmi->channels,
> +					    hdmi->sample_width,
> +					    hdmi->sample_rate,
> +					    hdmi->sample_non_pcm);
> +}
> +
> +static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)
> +{
> +	hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
> +
> +	hdmi_modb(hdmi,  0, 0x3, HDMI_FC_DATAUTO3);
> +	if (hdmi->phy.ops->disable_audio)
> +		hdmi->phy.ops->disable_audio(hdmi, hdmi->phy.data);
> +
> +	hdmi_enable_audio_clk(hdmi, false);
> +}
> +
>   static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
>   {
>   	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> @@ -3259,6 +3366,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
>   	hdmi->plat_data = plat_data;
>   	hdmi->dev = dev;
>   	hdmi->sample_rate = 48000;
> +	hdmi->channels = 2;
>   	hdmi->disabled = true;
>   	hdmi->rxsense = true;
>   	hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
> @@ -3482,6 +3590,24 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
>   		pdevinfo.size_data = sizeof(audio);
>   		pdevinfo.dma_mask = DMA_BIT_MASK(32);
>   		hdmi->audio = platform_device_register_full(&pdevinfo);
> +	} else if (iores && config3 & HDMI_CONFIG3_GPAUD) {
> +		struct dw_hdmi_audio_data audio;
> +
> +		audio.phys = iores->start;
> +		audio.base = hdmi->regs;
> +		audio.irq = irq;
> +		audio.hdmi = hdmi;
> +		audio.get_eld = hdmi_audio_get_eld;
> +
> +		hdmi->enable_audio = dw_hdmi_gp_audio_enable;
> +		hdmi->disable_audio = dw_hdmi_gp_audio_disable;
> +
> +		pdevinfo.name = "dw-hdmi-gp-audio";
> +		pdevinfo.id = PLATFORM_DEVID_NONE;
> +		pdevinfo.data = &audio;
> +		pdevinfo.size_data = sizeof(audio);
> +		pdevinfo.dma_mask = DMA_BIT_MASK(32);
> +		hdmi->audio = platform_device_register_full(&pdevinfo);
>   	}
>   
>   	if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) {
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> index 1999db05bc3b..99aa1c03343b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> @@ -158,8 +158,17 @@
>   #define HDMI_FC_SPDDEVICEINF                    0x1062
>   #define HDMI_FC_AUDSCONF                        0x1063
>   #define HDMI_FC_AUDSSTAT                        0x1064
> -#define HDMI_FC_AUDSCHNLS7                      0x106e
> -#define HDMI_FC_AUDSCHNLS8                      0x106f
> +#define HDMI_FC_AUDSV                           0x1065
> +#define HDMI_FC_AUDSU                           0x1066
> +#define HDMI_FC_AUDSCHNLS0                       0x1067
> +#define HDMI_FC_AUDSCHNLS1                       0x1068
> +#define HDMI_FC_AUDSCHNLS2                       0x1069
> +#define HDMI_FC_AUDSCHNLS3                       0x106A
> +#define HDMI_FC_AUDSCHNLS4                       0x106B
> +#define HDMI_FC_AUDSCHNLS5                       0x106C
> +#define HDMI_FC_AUDSCHNLS6                       0x106D
> +#define HDMI_FC_AUDSCHNLS7                       0x106E
> +#define HDMI_FC_AUDSCHNLS8                       0x106F
>   #define HDMI_FC_DATACH0FILL                     0x1070
>   #define HDMI_FC_DATACH1FILL                     0x1071
>   #define HDMI_FC_DATACH2FILL                     0x1072
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index 70082f80a8c8..7f73c3398a54 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -121,6 +121,9 @@ struct dw_hdmi_phy_ops {
>   	void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
>   			   bool force, bool disabled, bool rxsense);
>   	void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
> +	void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel,
> +			     int width, int rate, int non_pcm);
> +	void (*disable_audio)(struct dw_hdmi *hdmi, void *data);
>   };
>   
>   struct dw_hdmi_plat_data {
> @@ -173,6 +176,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
>   
>   int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
>   			   struct device *codec_dev);
> +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm);
> +void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width);
>   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
>   void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt);
>   void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status);

Thanks,
Neil

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

* Re: [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver
@ 2022-04-06  9:27     ` Neil Armstrong
  0 siblings, 0 replies; 32+ messages in thread
From: Neil Armstrong @ 2022-04-06  9:27 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, robert.foss,
	Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, cai.huoqing, maxime, harry.wentland,
	hverkuil-cisco, amuel

Hi,

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> General Parallel Audio (GPA) interface is one of the supported
> audio interface for synopsys HDMI module, which has verified for
> i.MX8MP platform.
> This is initial version for GPA.
> 
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>   drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
>   drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
>   .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199 ++++++++++++++++++
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 128 ++++++++++-
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
>   include/drm/bridge/dw_hdmi.h                  |   5 +
>   6 files changed, 354 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/bridge/synopsys/Kconfig
> index 21a1be3ced0f..e398b58c996d 100644
> --- a/drivers/gpu/drm/bridge/synopsys/Kconfig
> +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
> @@ -25,6 +25,17 @@ config DRM_DW_HDMI_I2S_AUDIO
>   	  Support the I2S Audio interface which is part of the Synopsys
>   	  Designware HDMI block.
>   
> +config DRM_DW_HDMI_GP_AUDIO
> +	tristate "Synopsys Designware GP Audio interface"
> +	depends on DRM_DW_HDMI && SND
> +	select SND_PCM
> +	select SND_PCM_ELD
> +	select SND_PCM_IEC958
> +	help
> +	  Support the GP Audio interface which is part of the Synopsys
> +	  Designware HDMI block.  This is used in conjunction with
> +	  the i.MX865 HDMI driver.

What does that mean ? it can only be used with i.MX865 HDMI driver ?
If not, remove reference to i.MX865 HDMI driver.

> +
>   config DRM_DW_HDMI_CEC
>   	tristate "Synopsis Designware CEC interface"
>   	depends on DRM_DW_HDMI
> diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile
> index 91d746ad5de1..ce715562e9e5 100644
> --- a/drivers/gpu/drm/bridge/synopsys/Makefile
> +++ b/drivers/gpu/drm/bridge/synopsys/Makefile
> @@ -1,6 +1,7 @@
>   # SPDX-License-Identifier: GPL-2.0-only
>   obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
>   obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> +obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o
>   obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
>   obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
>   
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> new file mode 100644
> index 000000000000..10a957c85a83
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> @@ -0,0 +1,199 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * dw-hdmi-gp-audio.c
> + *
> + * Copyright 2020-2022 NXP
> + */
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +#include <drm/bridge/dw_hdmi.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drm_connector.h>
> +
> +#include <sound/hdmi-codec.h>
> +#include <sound/asoundef.h>
> +#include <sound/core.h>
> +#include <sound/initval.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_drm_eld.h>
> +#include <sound/pcm_iec958.h>
> +#include <sound/dmaengine_pcm.h>
> +
> +#include "dw-hdmi-audio.h"
> +
> +#define DRIVER_NAME "dw-hdmi-gp-audio"
> +#define DRV_NAME    "hdmi-gp-audio"
> +
> +struct snd_dw_hdmi {
> +	struct dw_hdmi_audio_data data;
> +	struct platform_device  *audio_pdev;
> +	unsigned int pos;
> +};
> +
> +struct dw_hdmi_channel_conf {
> +	u8 conf1;
> +	u8 ca;
> +};
> +
> +/*
> + * The default mapping of ALSA channels to HDMI channels and speaker
> + * allocation bits.  Note that we can't do channel remapping here -
> + * channels must be in the same order.
> + *
> + * Mappings for alsa-lib pcm/surround*.conf files:
> + *
> + *		Front	Sur4.0	Sur4.1	Sur5.0	Sur5.1	Sur7.1
> + * Channels	2	4	6	6	6	8
> + *
> + * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel:
> + *
> + *				Number of ALSA channels
> + * ALSA Channel	2	3	4	5	6	7	8
> + * 0		FL:0	=	=	=	=	=	=
> + * 1		FR:1	=	=	=	=	=	=
> + * 2			FC:3	RL:4	LFE:2	=	=	=
> + * 3				RR:5	RL:4	FC:3	=	=
> + * 4					RR:5	RL:4	=	=
> + * 5						RR:5	=	=
> + * 6							RC:6	=
> + * 7							RLC/FRC	RLC/FRC
> + */
> +static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
> +	{ 0x03, 0x00 },	/* FL,FR */
> +	{ 0x0b, 0x02 },	/* FL,FR,FC */
> +	{ 0x33, 0x08 },	/* FL,FR,RL,RR */
> +	{ 0x37, 0x09 },	/* FL,FR,LFE,RL,RR */
> +	{ 0x3f, 0x0b },	/* FL,FR,LFE,FC,RL,RR */
> +	{ 0x7f, 0x0f },	/* FL,FR,LFE,FC,RL,RR,RC */
> +	{ 0xff, 0x13 },	/* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */
> +};
> +
> +static int audio_hw_params(struct device *dev,  void *data,
> +			   struct hdmi_codec_daifmt *daifmt,
> +			   struct hdmi_codec_params *params)
> +{
> +	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +	int ret = 0;
> +	u8 ca;
> +
> +	dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
> +
> +	ca = default_hdmi_channel_config[params->channels - 2].ca;
> +
> +	dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
> +	dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
> +
> +	dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
> +				   params->iec.status[0] & IEC958_AES0_NONAUDIO);
> +	dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
> +
> +	return ret;
> +}
> +
> +static void audio_shutdown(struct device *dev, void *data)
> +{
> +}
> +
> +static int audio_mute_stream(struct device *dev, void *data,
> +			      bool enable, int direction)
> +{
> +	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	if (!enable)
> +		dw_hdmi_audio_enable(dw->data.hdmi);
> +	else
> +		dw_hdmi_audio_disable(dw->data.hdmi);
> +
> +	return ret;
> +}
> +
> +static int audio_get_eld(struct device *dev, void *data,
> +			 u8 *buf, size_t len)
> +{
> +	struct dw_hdmi_audio_data *audio = data;
> +	u8 *eld;
> +
> +	eld = audio->get_eld(audio->hdmi);
> +	if (eld)
> +		memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
> +	else
> +		/* Pass en empty ELD if connector not available */
> +		memset(buf, 0, len);
> +
> +	return 0;
> +}
> +
> +static int audio_hook_plugged_cb(struct device *dev, void *data,
> +				 hdmi_codec_plugged_cb fn,
> +				 struct device *codec_dev)
> +{
> +	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> +
> +	return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev);
> +}
> +
> +static const struct hdmi_codec_ops audio_codec_ops = {
> +	.hw_params = audio_hw_params,
> +	.audio_shutdown = audio_shutdown,
> +	.mute_stream = audio_mute_stream,
> +	.get_eld = audio_get_eld,
> +	.hook_plugged_cb = audio_hook_plugged_cb,
> +};
> +
> +static int snd_dw_hdmi_probe(struct platform_device *pdev)
> +{
> +	struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
> +	struct snd_dw_hdmi *dw;
> +
> +	const struct hdmi_codec_pdata codec_data = {
> +		.i2s = 1,
> +		.spdif = 0,
> +		.ops = &audio_codec_ops,
> +		.max_i2s_channels = 8,
> +		.data = data,
> +	};
> +
> +	dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	dw->data = *data;
> +
> +	platform_set_drvdata(pdev, dw);
> +
> +	dw->audio_pdev = platform_device_register_data(&pdev->dev,
> +						       HDMI_CODEC_DRV_NAME, 1,
> +						       &codec_data,
> +						       sizeof(codec_data));
> +
> +	return PTR_ERR_OR_ZERO(dw->audio_pdev);
> +}
> +
> +static int snd_dw_hdmi_remove(struct platform_device *pdev)
> +{
> +	struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
> +
> +	platform_device_unregister(dw->audio_pdev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver snd_dw_hdmi_driver = {
> +	.probe	= snd_dw_hdmi_probe,
> +	.remove	= snd_dw_hdmi_remove,
> +	.driver	= {
> +		.name = DRIVER_NAME,
> +	},
> +};
> +
> +module_platform_driver(snd_dw_hdmi_driver);
> +
> +MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
> +MODULE_DESCRIPTION("Synopsis Designware HDMI GPA ALSA interface");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index c6e701acd416..1385d8f7870e 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -191,7 +191,10 @@ struct dw_hdmi {
>   
>   	spinlock_t audio_lock;
>   	struct mutex audio_mutex;
> +	unsigned int sample_non_pcm;
> +	unsigned int sample_width;
>   	unsigned int sample_rate;
> +	unsigned int channels;
>   	unsigned int audio_cts;
>   	unsigned int audio_n;
>   	bool audio_enable;
> @@ -589,6 +592,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
>   			n = 4096;
>   		else if (pixel_clk == 74176000 || pixel_clk == 148352000)
>   			n = 11648;
> +		else if (pixel_clk == 297000000)
> +			n = 3072;
>   		else
>   			n = 4096;
>   		n *= mult;
> @@ -601,6 +606,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
>   			n = 17836;
>   		else if (pixel_clk == 148352000)
>   			n = 8918;
> +		else if (pixel_clk == 297000000)
> +			n = 4704;
>   		else
>   			n = 6272;
>   		n *= mult;
> @@ -615,6 +622,8 @@ static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
>   			n = 11648;
>   		else if (pixel_clk == 148352000)
>   			n = 5824;
> +		else if (pixel_clk == 297000000)
> +			n = 5120;
>   		else
>   			n = 6144;
>   		n *= mult;
> @@ -660,7 +669,7 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
>   	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
>   
>   	/* Only compute CTS when using internal AHB audio */
> -	if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
> +	if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 & HDMI_CONFIG3_GPAUD)) {

Update the comment to include GPAUD.

>   		/*
>   		 * Compute the CTS value from the N value.  Note that CTS and N
>   		 * can be up to 20 bits in total, so we need 64-bit math.  Also
> @@ -702,6 +711,22 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
>   	mutex_unlock(&hdmi->audio_mutex);
>   }
>   
> +void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width)
> +{
> +	mutex_lock(&hdmi->audio_mutex);
> +	hdmi->sample_width = width;
> +	mutex_unlock(&hdmi->audio_mutex);
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
> +
> +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm)
> +{
> +	mutex_lock(&hdmi->audio_mutex);
> +	hdmi->sample_non_pcm = non_pcm;
> +	mutex_unlock(&hdmi->audio_mutex);
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
> +
>   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
>   {
>   	mutex_lock(&hdmi->audio_mutex);
> @@ -717,6 +742,7 @@ void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt)
>   	u8 layout;
>   
>   	mutex_lock(&hdmi->audio_mutex);
> +	hdmi->channels = cnt;
>   
>   	/*
>   	 * For >2 channel PCM audio, we need to select layout 1
> @@ -765,6 +791,87 @@ static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi)
>   	return hdmi->curr_conn->eld;
>   }
>   
> +static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
> +{
> +	int sample_freq = 0x2, org_sample_freq = 0xD;
> +	int ch_mask = BIT(hdmi->channels) - 1;
> +
> +	switch (hdmi->sample_rate) {
> +	case 32000:
> +		sample_freq = 0x03;
> +		org_sample_freq = 0x0C;
> +		break;
> +	case 44100:
> +		sample_freq = 0x00;
> +		org_sample_freq = 0x0F;
> +		break;
> +	case 48000:
> +		sample_freq = 0x02;
> +		org_sample_freq = 0x0D;
> +		break;
> +	case 88200:
> +		sample_freq = 0x08;
> +		org_sample_freq = 0x07;
> +		break;
> +	case 96000:
> +		sample_freq = 0x0A;
> +		org_sample_freq = 0x05;
> +		break;
> +	case 176400:
> +		sample_freq = 0x0C;
> +		org_sample_freq = 0x03;
> +		break;
> +	case 192000:
> +		sample_freq = 0x0E;
> +		org_sample_freq = 0x01;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> +	hdmi_enable_audio_clk(hdmi, true);
> +
> +	hdmi_writeb(hdmi, 0x1, HDMI_FC_AUDSCHNLS0);
> +	hdmi_writeb(hdmi, hdmi->channels, HDMI_FC_AUDSCHNLS2);
> +	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS3);
> +	hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS4);
> +	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS5);
> +	hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS6);
> +	hdmi_writeb(hdmi, (0x3 << 4) | sample_freq, HDMI_FC_AUDSCHNLS7);
> +	hdmi_writeb(hdmi, (org_sample_freq << 4) | 0xb, HDMI_FC_AUDSCHNLS8);
> +
> +	hdmi_writeb(hdmi, ch_mask, HDMI_GP_CONF1);
> +	hdmi_writeb(hdmi, 0x02, HDMI_GP_CONF2);
> +	hdmi_writeb(hdmi, 0x01, HDMI_GP_CONF0);
> +
> +	hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
> +
> +	/* hbr */
> +	if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
> +	    hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
> +		hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
> +	}
> +
> +	if (hdmi->phy.ops->enable_audio)
> +		hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
> +					    hdmi->channels,
> +					    hdmi->sample_width,
> +					    hdmi->sample_rate,
> +					    hdmi->sample_non_pcm);
> +}
> +
> +static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)
> +{
> +	hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
> +
> +	hdmi_modb(hdmi,  0, 0x3, HDMI_FC_DATAUTO3);
> +	if (hdmi->phy.ops->disable_audio)
> +		hdmi->phy.ops->disable_audio(hdmi, hdmi->phy.data);
> +
> +	hdmi_enable_audio_clk(hdmi, false);
> +}
> +
>   static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
>   {
>   	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> @@ -3259,6 +3366,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
>   	hdmi->plat_data = plat_data;
>   	hdmi->dev = dev;
>   	hdmi->sample_rate = 48000;
> +	hdmi->channels = 2;
>   	hdmi->disabled = true;
>   	hdmi->rxsense = true;
>   	hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
> @@ -3482,6 +3590,24 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
>   		pdevinfo.size_data = sizeof(audio);
>   		pdevinfo.dma_mask = DMA_BIT_MASK(32);
>   		hdmi->audio = platform_device_register_full(&pdevinfo);
> +	} else if (iores && config3 & HDMI_CONFIG3_GPAUD) {
> +		struct dw_hdmi_audio_data audio;
> +
> +		audio.phys = iores->start;
> +		audio.base = hdmi->regs;
> +		audio.irq = irq;
> +		audio.hdmi = hdmi;
> +		audio.get_eld = hdmi_audio_get_eld;
> +
> +		hdmi->enable_audio = dw_hdmi_gp_audio_enable;
> +		hdmi->disable_audio = dw_hdmi_gp_audio_disable;
> +
> +		pdevinfo.name = "dw-hdmi-gp-audio";
> +		pdevinfo.id = PLATFORM_DEVID_NONE;
> +		pdevinfo.data = &audio;
> +		pdevinfo.size_data = sizeof(audio);
> +		pdevinfo.dma_mask = DMA_BIT_MASK(32);
> +		hdmi->audio = platform_device_register_full(&pdevinfo);
>   	}
>   
>   	if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) {
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> index 1999db05bc3b..99aa1c03343b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> @@ -158,8 +158,17 @@
>   #define HDMI_FC_SPDDEVICEINF                    0x1062
>   #define HDMI_FC_AUDSCONF                        0x1063
>   #define HDMI_FC_AUDSSTAT                        0x1064
> -#define HDMI_FC_AUDSCHNLS7                      0x106e
> -#define HDMI_FC_AUDSCHNLS8                      0x106f
> +#define HDMI_FC_AUDSV                           0x1065
> +#define HDMI_FC_AUDSU                           0x1066
> +#define HDMI_FC_AUDSCHNLS0                       0x1067
> +#define HDMI_FC_AUDSCHNLS1                       0x1068
> +#define HDMI_FC_AUDSCHNLS2                       0x1069
> +#define HDMI_FC_AUDSCHNLS3                       0x106A
> +#define HDMI_FC_AUDSCHNLS4                       0x106B
> +#define HDMI_FC_AUDSCHNLS5                       0x106C
> +#define HDMI_FC_AUDSCHNLS6                       0x106D
> +#define HDMI_FC_AUDSCHNLS7                       0x106E
> +#define HDMI_FC_AUDSCHNLS8                       0x106F
>   #define HDMI_FC_DATACH0FILL                     0x1070
>   #define HDMI_FC_DATACH1FILL                     0x1071
>   #define HDMI_FC_DATACH2FILL                     0x1072
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index 70082f80a8c8..7f73c3398a54 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -121,6 +121,9 @@ struct dw_hdmi_phy_ops {
>   	void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
>   			   bool force, bool disabled, bool rxsense);
>   	void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
> +	void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel,
> +			     int width, int rate, int non_pcm);
> +	void (*disable_audio)(struct dw_hdmi *hdmi, void *data);
>   };
>   
>   struct dw_hdmi_plat_data {
> @@ -173,6 +176,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
>   
>   int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
>   			   struct device *codec_dev);
> +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm);
> +void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width);
>   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
>   void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt);
>   void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status);

Thanks,
Neil

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

* Re: [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
  2022-04-06  8:48   ` Sandor.yu
@ 2022-04-06  9:46     ` Hans Verkuil
  -1 siblings, 0 replies; 32+ messages in thread
From: Hans Verkuil @ 2022-04-06  9:46 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, narmstrong,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, cai.huoqing, maxime, amuel

Hi Sandor,

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> CEC interrupt status/mask and logical address registers
> will be reset when device enter suspend.
> It will cause cec fail to work after device resume.
> Add CEC suspend/resume functions, save these registers status
> when suspend and restore them when resume.
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 35 +++++++++++++++++++
>  1 file changed, 35 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> index c8f44bcb298a..ceb619b32fde 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> @@ -18,6 +18,8 @@
>  
>  #include "dw-hdmi-cec.h"
>  
> +static u8 cec_saved_regs[5];

Ewww, not a global. Just save it in struct dw_hdmi_cec.

> +
>  enum {
>  	HDMI_IH_CEC_STAT0	= 0x0106,
>  	HDMI_IH_MUTE_CEC_STAT0	= 0x0186,
> @@ -306,11 +308,44 @@ static int dw_hdmi_cec_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static int __maybe_unused dw_hdmi_cec_resume(struct device *dev)
> +{
> +	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> +
> +	/* Restore logical address and interrupt status/mask register */
> +	dw_hdmi_write(cec, cec_saved_regs[0], HDMI_CEC_ADDR_L);
> +	dw_hdmi_write(cec, cec_saved_regs[1], HDMI_CEC_ADDR_H);

No need to store HDMI_CEC_ADDR_L/R, just use cec->addresses.

> +	dw_hdmi_write(cec, cec_saved_regs[2], HDMI_CEC_POLARITY);
> +	dw_hdmi_write(cec, cec_saved_regs[3], HDMI_CEC_MASK);
> +	dw_hdmi_write(cec, cec_saved_regs[4], HDMI_IH_MUTE_CEC_STAT0);

This doesn't call cec->ops->disable/enable. It might be better to just call
dw_hdmi_cec_enable() and store the enable state in struct dw_hdmi_cec.

Regards,

	Hans

> +
> +	return 0;
> +}
> +
> +static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev)
> +{
> +	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> +
> +	/* store logical address and interrupt status/mask register */
> +	cec_saved_regs[0] = dw_hdmi_read(cec, HDMI_CEC_ADDR_L);
> +	cec_saved_regs[1] = dw_hdmi_read(cec, HDMI_CEC_ADDR_H);
> +	cec_saved_regs[2] = dw_hdmi_read(cec, HDMI_CEC_POLARITY);
> +	cec_saved_regs[3] = dw_hdmi_read(cec, HDMI_CEC_MASK);
> +	cec_saved_regs[4] = dw_hdmi_read(cec, HDMI_IH_MUTE_CEC_STAT0);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops dw_hdmi_cec_pm = {
> +	SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend, dw_hdmi_cec_resume)
> +};
> +
>  static struct platform_driver dw_hdmi_cec_driver = {
>  	.probe	= dw_hdmi_cec_probe,
>  	.remove	= dw_hdmi_cec_remove,
>  	.driver = {
>  		.name = "dw-hdmi-cec",
> +		.pm = &dw_hdmi_cec_pm,
>  	},
>  };
>  module_platform_driver(dw_hdmi_cec_driver);

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

* Re: [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
@ 2022-04-06  9:46     ` Hans Verkuil
  0 siblings, 0 replies; 32+ messages in thread
From: Hans Verkuil @ 2022-04-06  9:46 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, narmstrong,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, cai.huoqing, maxime, harry.wentland, amuel

Hi Sandor,

On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> CEC interrupt status/mask and logical address registers
> will be reset when device enter suspend.
> It will cause cec fail to work after device resume.
> Add CEC suspend/resume functions, save these registers status
> when suspend and restore them when resume.
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 35 +++++++++++++++++++
>  1 file changed, 35 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> index c8f44bcb298a..ceb619b32fde 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> @@ -18,6 +18,8 @@
>  
>  #include "dw-hdmi-cec.h"
>  
> +static u8 cec_saved_regs[5];

Ewww, not a global. Just save it in struct dw_hdmi_cec.

> +
>  enum {
>  	HDMI_IH_CEC_STAT0	= 0x0106,
>  	HDMI_IH_MUTE_CEC_STAT0	= 0x0186,
> @@ -306,11 +308,44 @@ static int dw_hdmi_cec_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static int __maybe_unused dw_hdmi_cec_resume(struct device *dev)
> +{
> +	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> +
> +	/* Restore logical address and interrupt status/mask register */
> +	dw_hdmi_write(cec, cec_saved_regs[0], HDMI_CEC_ADDR_L);
> +	dw_hdmi_write(cec, cec_saved_regs[1], HDMI_CEC_ADDR_H);

No need to store HDMI_CEC_ADDR_L/R, just use cec->addresses.

> +	dw_hdmi_write(cec, cec_saved_regs[2], HDMI_CEC_POLARITY);
> +	dw_hdmi_write(cec, cec_saved_regs[3], HDMI_CEC_MASK);
> +	dw_hdmi_write(cec, cec_saved_regs[4], HDMI_IH_MUTE_CEC_STAT0);

This doesn't call cec->ops->disable/enable. It might be better to just call
dw_hdmi_cec_enable() and store the enable state in struct dw_hdmi_cec.

Regards,

	Hans

> +
> +	return 0;
> +}
> +
> +static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev)
> +{
> +	struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> +
> +	/* store logical address and interrupt status/mask register */
> +	cec_saved_regs[0] = dw_hdmi_read(cec, HDMI_CEC_ADDR_L);
> +	cec_saved_regs[1] = dw_hdmi_read(cec, HDMI_CEC_ADDR_H);
> +	cec_saved_regs[2] = dw_hdmi_read(cec, HDMI_CEC_POLARITY);
> +	cec_saved_regs[3] = dw_hdmi_read(cec, HDMI_CEC_MASK);
> +	cec_saved_regs[4] = dw_hdmi_read(cec, HDMI_IH_MUTE_CEC_STAT0);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops dw_hdmi_cec_pm = {
> +	SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend, dw_hdmi_cec_resume)
> +};
> +
>  static struct platform_driver dw_hdmi_cec_driver = {
>  	.probe	= dw_hdmi_cec_probe,
>  	.remove	= dw_hdmi_cec_remove,
>  	.driver = {
>  		.name = "dw-hdmi-cec",
> +		.pm = &dw_hdmi_cec_pm,
>  	},
>  };
>  module_platform_driver(dw_hdmi_cec_driver);

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

* RE: [EXT] Re: [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
  2022-04-06  9:46     ` Hans Verkuil
@ 2022-04-07  8:30       ` Sandor Yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:30 UTC (permalink / raw)
  To: Hans Verkuil, dri-devel, linux-kernel, andrzej.hajda, narmstrong,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, cai.huoqing, maxime, harry.wentland, amuel

Hi,

> -----Original Message-----
> From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> Sent: 2022年4月6日 17:47
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> narmstrong@baylibre.com; robert.foss@linaro.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec
> suspend/resume function
> 
> Caution: EXT Email
> 
> Hi Sandor,
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > CEC interrupt status/mask and logical address registers will be reset
> > when device enter suspend.
> > It will cause cec fail to work after device resume.
> > Add CEC suspend/resume functions, save these registers status when
> > suspend and restore them when resume.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >  drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 35
> > +++++++++++++++++++
> >  1 file changed, 35 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > index c8f44bcb298a..ceb619b32fde 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > @@ -18,6 +18,8 @@
> >
> >  #include "dw-hdmi-cec.h"
> >
> > +static u8 cec_saved_regs[5];
> 
> Ewww, not a global. Just save it in struct dw_hdmi_cec.

> 
> > +
> >  enum {
> >       HDMI_IH_CEC_STAT0       = 0x0106,
> >       HDMI_IH_MUTE_CEC_STAT0  = 0x0186, @@ -306,11 +308,44
> @@ static
> > int dw_hdmi_cec_remove(struct platform_device *pdev)
> >       return 0;
> >  }
> >
> > +static int __maybe_unused dw_hdmi_cec_resume(struct device *dev) {
> > +     struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> > +
> > +     /* Restore logical address and interrupt status/mask register */
> > +     dw_hdmi_write(cec, cec_saved_regs[0], HDMI_CEC_ADDR_L);
> > +     dw_hdmi_write(cec, cec_saved_regs[1], HDMI_CEC_ADDR_H);
> 
> No need to store HDMI_CEC_ADDR_L/R, just use cec->addresses.
Agree, I will use it later.
> 
> > +     dw_hdmi_write(cec, cec_saved_regs[2], HDMI_CEC_POLARITY);
> > +     dw_hdmi_write(cec, cec_saved_regs[3], HDMI_CEC_MASK);
> > +     dw_hdmi_write(cec, cec_saved_regs[4],
> HDMI_IH_MUTE_CEC_STAT0);
> 
> This doesn't call cec->ops->disable/enable. It might be better to just call
> dw_hdmi_cec_enable() and store the enable state in struct dw_hdmi_cec.
If call cec->ops->disable/enable in suspend/resume, CEC stack will be reset.
CEC user such as EARC/ARC, the CEC link is expect keep in active after device resume.
So I prefer only save those registers for better user experience.
> 
> Regards,
> 
>         Hans
> 
Thanks
Sandor
> > +
> > +     return 0;
> > +}
> > +
> > +static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev) {
> > +     struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> > +
> > +     /* store logical address and interrupt status/mask register */
> > +     cec_saved_regs[0] = dw_hdmi_read(cec, HDMI_CEC_ADDR_L);
> > +     cec_saved_regs[1] = dw_hdmi_read(cec, HDMI_CEC_ADDR_H);
> > +     cec_saved_regs[2] = dw_hdmi_read(cec, HDMI_CEC_POLARITY);
> > +     cec_saved_regs[3] = dw_hdmi_read(cec, HDMI_CEC_MASK);
> > +     cec_saved_regs[4] = dw_hdmi_read(cec,
> HDMI_IH_MUTE_CEC_STAT0);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct dev_pm_ops dw_hdmi_cec_pm = {
> > +     SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend,
> dw_hdmi_cec_resume)
> > +};
> > +
> >  static struct platform_driver dw_hdmi_cec_driver = {
> >       .probe  = dw_hdmi_cec_probe,
> >       .remove = dw_hdmi_cec_remove,
> >       .driver = {
> >               .name = "dw-hdmi-cec",
> > +             .pm = &dw_hdmi_cec_pm,
> >       },
> >  };
> >  module_platform_driver(dw_hdmi_cec_driver);

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

* RE: [EXT] Re: [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec suspend/resume function
@ 2022-04-07  8:30       ` Sandor Yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:30 UTC (permalink / raw)
  To: Hans Verkuil, dri-devel, linux-kernel, andrzej.hajda, narmstrong,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, cai.huoqing, maxime, amuel

Hi,

> -----Original Message-----
> From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> Sent: 2022年4月6日 17:47
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> narmstrong@baylibre.com; robert.foss@linaro.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec
> suspend/resume function
> 
> Caution: EXT Email
> 
> Hi Sandor,
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > CEC interrupt status/mask and logical address registers will be reset
> > when device enter suspend.
> > It will cause cec fail to work after device resume.
> > Add CEC suspend/resume functions, save these registers status when
> > suspend and restore them when resume.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >  drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 35
> > +++++++++++++++++++
> >  1 file changed, 35 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > index c8f44bcb298a..ceb619b32fde 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> > @@ -18,6 +18,8 @@
> >
> >  #include "dw-hdmi-cec.h"
> >
> > +static u8 cec_saved_regs[5];
> 
> Ewww, not a global. Just save it in struct dw_hdmi_cec.

> 
> > +
> >  enum {
> >       HDMI_IH_CEC_STAT0       = 0x0106,
> >       HDMI_IH_MUTE_CEC_STAT0  = 0x0186, @@ -306,11 +308,44
> @@ static
> > int dw_hdmi_cec_remove(struct platform_device *pdev)
> >       return 0;
> >  }
> >
> > +static int __maybe_unused dw_hdmi_cec_resume(struct device *dev) {
> > +     struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> > +
> > +     /* Restore logical address and interrupt status/mask register */
> > +     dw_hdmi_write(cec, cec_saved_regs[0], HDMI_CEC_ADDR_L);
> > +     dw_hdmi_write(cec, cec_saved_regs[1], HDMI_CEC_ADDR_H);
> 
> No need to store HDMI_CEC_ADDR_L/R, just use cec->addresses.
Agree, I will use it later.
> 
> > +     dw_hdmi_write(cec, cec_saved_regs[2], HDMI_CEC_POLARITY);
> > +     dw_hdmi_write(cec, cec_saved_regs[3], HDMI_CEC_MASK);
> > +     dw_hdmi_write(cec, cec_saved_regs[4],
> HDMI_IH_MUTE_CEC_STAT0);
> 
> This doesn't call cec->ops->disable/enable. It might be better to just call
> dw_hdmi_cec_enable() and store the enable state in struct dw_hdmi_cec.
If call cec->ops->disable/enable in suspend/resume, CEC stack will be reset.
CEC user such as EARC/ARC, the CEC link is expect keep in active after device resume.
So I prefer only save those registers for better user experience.
> 
> Regards,
> 
>         Hans
> 
Thanks
Sandor
> > +
> > +     return 0;
> > +}
> > +
> > +static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev) {
> > +     struct dw_hdmi_cec *cec = dev_get_drvdata(dev);
> > +
> > +     /* store logical address and interrupt status/mask register */
> > +     cec_saved_regs[0] = dw_hdmi_read(cec, HDMI_CEC_ADDR_L);
> > +     cec_saved_regs[1] = dw_hdmi_read(cec, HDMI_CEC_ADDR_H);
> > +     cec_saved_regs[2] = dw_hdmi_read(cec, HDMI_CEC_POLARITY);
> > +     cec_saved_regs[3] = dw_hdmi_read(cec, HDMI_CEC_MASK);
> > +     cec_saved_regs[4] = dw_hdmi_read(cec,
> HDMI_IH_MUTE_CEC_STAT0);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct dev_pm_ops dw_hdmi_cec_pm = {
> > +     SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend,
> dw_hdmi_cec_resume)
> > +};
> > +
> >  static struct platform_driver dw_hdmi_cec_driver = {
> >       .probe  = dw_hdmi_cec_probe,
> >       .remove = dw_hdmi_cec_remove,
> >       .driver = {
> >               .name = "dw-hdmi-cec",
> > +             .pm = &dw_hdmi_cec_pm,
> >       },
> >  };
> >  module_platform_driver(dw_hdmi_cec_driver);

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

* RE: [EXT] Re: [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
  2022-04-06  9:17     ` Neil Armstrong
@ 2022-04-07  8:30       ` Sandor Yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:30 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel, linux-kernel, andrzej.hajda,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, amuel, cai.huoqing, maxime, hverkuil-cisco

Hi,

> -----Original Message-----
> From: Neil Armstrong <narmstrong@baylibre.com>
> Sent: 2022年4月6日 17:17
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> robert.foss@linaro.org; Laurent.pinchart@ideasonboard.com;
> jonas@kwiboo.se; jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; hverkuil-cisco@xs4all.nl;
> amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow
> workaround for v2.13a
> 
> Caution: EXT Email
> 
> Hi,
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > iMX865 HDMI (v2.13a) have been identified as needing the workaround.
> > Tests show that one iteration is enough.
> >
> > Without the workaround, iMX865 HDMI audio may not work after cable
> > plugout/in, because HDMI mode is not really set in register
> > HDMI_FC_INVIDCONF.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 ++++---
> >   1 file changed, 4 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > index 4befc104d220..b11577de4836 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -2087,9 +2087,9 @@ static void dw_hdmi_clear_overflow(struct
> dw_hdmi *hdmi)
> >        *
> >        * The number of iterations matters and depends on the HDMI TX
> revision
> >        * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
> > -      * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been
> identified
> > -      * as needing the workaround, with 4 iterations for v1.30a and 1
> > -      * iteration for others.
> > +      * (v1.31a), iMX865(v2.13a) and multiple Allwinner SoCs (v1.32a)
> > +      * have been identified as needing the workaround,
> > +      * with 4 iterations for v1.30a and 1 iteration for others.
> >        * The Amlogic Meson GX SoCs (v2.01a) have been identified as
> needing
> >        * the workaround with a single iteration.
> >        * The Rockchip RK3288 SoC (v2.00a) and RK3328/RK3399 SoCs
> > (v2.11a) have @@ -2106,6 +2106,7 @@ static void
> dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
> >       case 0x201a:
> >       case 0x211a:
> >       case 0x212a:
> > +     case 0x213a:
> >               count = 1;
> >               break;
> 
> At some point we must consider only v1.30a needs 4, and other needs 1.
> 
> It would be simpler to put the "count = 1" in a default case.
> 
Agree, I will put the "count = 1 " to default case.
> The comment change is still welcome so we can track.
> 
> Thanks,
> Neil
> 
> >       default:

Thanks
Sandor


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

* RE: [EXT] Re: [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow workaround for v2.13a
@ 2022-04-07  8:30       ` Sandor Yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:30 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel, linux-kernel, andrzej.hajda,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, cai.huoqing, maxime, harry.wentland, hverkuil-cisco, amuel

Hi,

> -----Original Message-----
> From: Neil Armstrong <narmstrong@baylibre.com>
> Sent: 2022年4月6日 17:17
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> robert.foss@linaro.org; Laurent.pinchart@ideasonboard.com;
> jonas@kwiboo.se; jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; hverkuil-cisco@xs4all.nl;
> amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow
> workaround for v2.13a
> 
> Caution: EXT Email
> 
> Hi,
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > iMX865 HDMI (v2.13a) have been identified as needing the workaround.
> > Tests show that one iteration is enough.
> >
> > Without the workaround, iMX865 HDMI audio may not work after cable
> > plugout/in, because HDMI mode is not really set in register
> > HDMI_FC_INVIDCONF.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 ++++---
> >   1 file changed, 4 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > index 4befc104d220..b11577de4836 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -2087,9 +2087,9 @@ static void dw_hdmi_clear_overflow(struct
> dw_hdmi *hdmi)
> >        *
> >        * The number of iterations matters and depends on the HDMI TX
> revision
> >        * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
> > -      * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been
> identified
> > -      * as needing the workaround, with 4 iterations for v1.30a and 1
> > -      * iteration for others.
> > +      * (v1.31a), iMX865(v2.13a) and multiple Allwinner SoCs (v1.32a)
> > +      * have been identified as needing the workaround,
> > +      * with 4 iterations for v1.30a and 1 iteration for others.
> >        * The Amlogic Meson GX SoCs (v2.01a) have been identified as
> needing
> >        * the workaround with a single iteration.
> >        * The Rockchip RK3288 SoC (v2.00a) and RK3328/RK3399 SoCs
> > (v2.11a) have @@ -2106,6 +2106,7 @@ static void
> dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
> >       case 0x201a:
> >       case 0x211a:
> >       case 0x212a:
> > +     case 0x213a:
> >               count = 1;
> >               break;
> 
> At some point we must consider only v1.30a needs 4, and other needs 1.
> 
> It would be simpler to put the "count = 1" in a default case.
> 
Agree, I will put the "count = 1 " to default case.
> The comment change is still welcome so we can track.
> 
> Thanks,
> Neil
> 
> >       default:

Thanks
Sandor


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

* RE: [EXT] Re: [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for Deep Color
  2022-04-06  9:20     ` Neil Armstrong
@ 2022-04-07  8:31       ` Sandor Yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:31 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel, linux-kernel, andrzej.hajda,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, cai.huoqing, maxime, harry.wentland, hverkuil-cisco, amuel

Hi,

> -----Original Message-----
> From: Neil Armstrong <narmstrong@baylibre.com>
> Sent: 2022年4月6日 17:20
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> robert.foss@linaro.org; Laurent.pinchart@ideasonboard.com;
> jonas@kwiboo.se; jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; hverkuil-cisco@xs4all.nl;
> amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for
> Deep Color
> 
> Caution: EXT Email
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > HDMI1.4b specification section 6.5.3:
> > Source shall only send GCPs with non-zero CD to sinks that indicate
> > support for Deep Color.
> >
> > DW HDMI GPC default enabled, clear gpc_auto bit for bpp 24.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 ++++++++
> >   1 file changed, 8 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > index b11577de4836..c7b11582529e 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -1160,6 +1160,14 @@ static void hdmi_video_packetize(struct
> dw_hdmi *hdmi)
> >               HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
> >       hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
> >
> > +     val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3);
> > +     if (color_depth == 4)
> > +             /* disable Auto GCP when bpp 24 */
> > +             val &= ~0x4;
> > +     else
> > +             val |= 0x4;
> > +     hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
> > +
> >       hdmi_modb(hdmi,
> HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
> >                 HDMI_VP_STUFF_PR_STUFFING_MASK,
> HDMI_VP_STUFF);
> >
> 
> Do you handle the case when color_depth == 0 when output is YUV422 ?
For YUV422 color depth 8, the gcp_auto bit need clear too, I will add it.
> 
> Neil
Thanks,
Sandor

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

* RE: [EXT] Re: [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for Deep Color
@ 2022-04-07  8:31       ` Sandor Yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:31 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel, linux-kernel, andrzej.hajda,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, amuel, cai.huoqing, maxime, hverkuil-cisco

Hi,

> -----Original Message-----
> From: Neil Armstrong <narmstrong@baylibre.com>
> Sent: 2022年4月6日 17:20
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> robert.foss@linaro.org; Laurent.pinchart@ideasonboard.com;
> jonas@kwiboo.se; jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; hverkuil-cisco@xs4all.nl;
> amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for
> Deep Color
> 
> Caution: EXT Email
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > HDMI1.4b specification section 6.5.3:
> > Source shall only send GCPs with non-zero CD to sinks that indicate
> > support for Deep Color.
> >
> > DW HDMI GPC default enabled, clear gpc_auto bit for bpp 24.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 ++++++++
> >   1 file changed, 8 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > index b11577de4836..c7b11582529e 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -1160,6 +1160,14 @@ static void hdmi_video_packetize(struct
> dw_hdmi *hdmi)
> >               HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
> >       hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
> >
> > +     val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3);
> > +     if (color_depth == 4)
> > +             /* disable Auto GCP when bpp 24 */
> > +             val &= ~0x4;
> > +     else
> > +             val |= 0x4;
> > +     hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
> > +
> >       hdmi_modb(hdmi,
> HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
> >                 HDMI_VP_STUFF_PR_STUFFING_MASK,
> HDMI_VP_STUFF);
> >
> 
> Do you handle the case when color_depth == 0 when output is YUV422 ?
For YUV422 color depth 8, the gcp_auto bit need clear too, I will add it.
> 
> Neil
Thanks,
Sandor

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

* RE: [EXT] Re: [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver
  2022-04-06  9:27     ` Neil Armstrong
@ 2022-04-07  8:31       ` Sandor Yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:31 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel, linux-kernel, andrzej.hajda,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, cai.huoqing, maxime, harry.wentland, hverkuil-cisco, amuel

Hi,

> -----Original Message-----
> From: Neil Armstrong <narmstrong@baylibre.com>
> Sent: 2022年4月6日 17:28
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> robert.foss@linaro.org; Laurent.pinchart@ideasonboard.com;
> jonas@kwiboo.se; jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; hverkuil-cisco@xs4all.nl;
> amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General
> Parallel Audio (GPA) driver
> 
> Caution: EXT Email
> 
> Hi,
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > General Parallel Audio (GPA) interface is one of the supported audio
> > interface for synopsys HDMI module, which has verified for i.MX8MP
> > platform.
> > This is initial version for GPA.
> >
> > Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >   drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
> >   drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
> >   .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199
> ++++++++++++++++++
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 128 ++++++++++-
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
> >   include/drm/bridge/dw_hdmi.h                  |   5 +
> >   6 files changed, 354 insertions(+), 3 deletions(-)
> >   create mode 100644
> > drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig
> > b/drivers/gpu/drm/bridge/synopsys/Kconfig
> > index 21a1be3ced0f..e398b58c996d 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/Kconfig
> > +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
> > @@ -25,6 +25,17 @@ config DRM_DW_HDMI_I2S_AUDIO
> >         Support the I2S Audio interface which is part of the Synopsys
> >         Designware HDMI block.
> >
> > +config DRM_DW_HDMI_GP_AUDIO
> > +     tristate "Synopsys Designware GP Audio interface"
> > +     depends on DRM_DW_HDMI && SND
> > +     select SND_PCM
> > +     select SND_PCM_ELD
> > +     select SND_PCM_IEC958
> > +     help
> > +       Support the GP Audio interface which is part of the Synopsys
> > +       Designware HDMI block.  This is used in conjunction with
> > +       the i.MX865 HDMI driver.
> 
> What does that mean ? it can only be used with i.MX865 HDMI driver ?
> If not, remove reference to i.MX865 HDMI driver.
> 
GP audio driver could be used for different SOCs, i.MX865 specific description will be removed.
> > +
> >   config DRM_DW_HDMI_CEC
> >       tristate "Synopsis Designware CEC interface"
> >       depends on DRM_DW_HDMI
> > diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile
> > b/drivers/gpu/drm/bridge/synopsys/Makefile
> > index 91d746ad5de1..ce715562e9e5 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/Makefile
> > +++ b/drivers/gpu/drm/bridge/synopsys/Makefile
> > @@ -1,6 +1,7 @@
> >   # SPDX-License-Identifier: GPL-2.0-only
> >   obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
> >   obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> > +obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o
> >   obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
> >   obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> > new file mode 100644
> > index 000000000000..10a957c85a83
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> > @@ -0,0 +1,199 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * dw-hdmi-gp-audio.c
> > + *
> > + * Copyright 2020-2022 NXP
> > + */
> > +#include <linux/io.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/dma-mapping.h>
> > +#include <drm/bridge/dw_hdmi.h>
> > +#include <drm/drm_edid.h>
> > +#include <drm/drm_connector.h>
> > +
> > +#include <sound/hdmi-codec.h>
> > +#include <sound/asoundef.h>
> > +#include <sound/core.h>
> > +#include <sound/initval.h>
> > +#include <sound/pcm.h>
> > +#include <sound/pcm_drm_eld.h>
> > +#include <sound/pcm_iec958.h>
> > +#include <sound/dmaengine_pcm.h>
> > +
> > +#include "dw-hdmi-audio.h"
> > +
> > +#define DRIVER_NAME "dw-hdmi-gp-audio"
> > +#define DRV_NAME    "hdmi-gp-audio"
> > +
> > +struct snd_dw_hdmi {
> > +     struct dw_hdmi_audio_data data;
> > +     struct platform_device  *audio_pdev;
> > +     unsigned int pos;
> > +};
> > +
> > +struct dw_hdmi_channel_conf {
> > +     u8 conf1;
> > +     u8 ca;
> > +};
> > +
> > +/*
> > + * The default mapping of ALSA channels to HDMI channels and speaker
> > + * allocation bits.  Note that we can't do channel remapping here -
> > + * channels must be in the same order.
> > + *
> > + * Mappings for alsa-lib pcm/surround*.conf files:
> > + *
> > + *           Front   Sur4.0  Sur4.1  Sur5.0  Sur5.1  Sur7.1
> > + * Channels  2       4       6       6       6       8
> > + *
> > + * Our mapping from ALSA channel to CEA686D speaker name and HDMI
> channel:
> > + *
> > + *                           Number of ALSA channels
> > + * ALSA Channel      2       3       4       5       6       7
> 8
> > + * 0         FL:0    =       =       =       =       =
> =
> > + * 1         FR:1    =       =       =       =       =
> =
> > + * 2                 FC:3    RL:4    LFE:2   =       =       =
> > + * 3                         RR:5    RL:4    FC:3    =       =
> > + * 4                                 RR:5    RL:4    =
> =
> > + * 5                                         RR:5    =
> =
> > + * 6                                                 RC:6
> =
> > + * 7                                                 RLC/FRC
> RLC/FRC
> > + */
> > +static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
> > +     { 0x03, 0x00 }, /* FL,FR */
> > +     { 0x0b, 0x02 }, /* FL,FR,FC */
> > +     { 0x33, 0x08 }, /* FL,FR,RL,RR */
> > +     { 0x37, 0x09 }, /* FL,FR,LFE,RL,RR */
> > +     { 0x3f, 0x0b }, /* FL,FR,LFE,FC,RL,RR */
> > +     { 0x7f, 0x0f }, /* FL,FR,LFE,FC,RL,RR,RC */
> > +     { 0xff, 0x13 }, /* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */ };
> > +
> > +static int audio_hw_params(struct device *dev,  void *data,
> > +                        struct hdmi_codec_daifmt *daifmt,
> > +                        struct hdmi_codec_params *params) {
> > +     struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> > +     int ret = 0;
> > +     u8 ca;
> > +
> > +     dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
> > +
> > +     ca = default_hdmi_channel_config[params->channels - 2].ca;
> > +
> > +     dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
> > +     dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
> > +
> > +     dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
> > +                                params->iec.status[0] &
> IEC958_AES0_NONAUDIO);
> > +     dw_hdmi_set_sample_width(dw->data.hdmi,
> params->sample_width);
> > +
> > +     return ret;
> > +}
> > +
> > +static void audio_shutdown(struct device *dev, void *data) { }
> > +
> > +static int audio_mute_stream(struct device *dev, void *data,
> > +                           bool enable, int direction) {
> > +     struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> > +     int ret = 0;
> > +
> > +     if (!enable)
> > +             dw_hdmi_audio_enable(dw->data.hdmi);
> > +     else
> > +             dw_hdmi_audio_disable(dw->data.hdmi);
> > +
> > +     return ret;
> > +}
> > +
> > +static int audio_get_eld(struct device *dev, void *data,
> > +                      u8 *buf, size_t len) {
> > +     struct dw_hdmi_audio_data *audio = data;
> > +     u8 *eld;
> > +
> > +     eld = audio->get_eld(audio->hdmi);
> > +     if (eld)
> > +             memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
> > +     else
> > +             /* Pass en empty ELD if connector not available */
> > +             memset(buf, 0, len);
> > +
> > +     return 0;
> > +}
> > +
> > +static int audio_hook_plugged_cb(struct device *dev, void *data,
> > +                              hdmi_codec_plugged_cb fn,
> > +                              struct device *codec_dev) {
> > +     struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> > +
> > +     return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev); }
> > +
> > +static const struct hdmi_codec_ops audio_codec_ops = {
> > +     .hw_params = audio_hw_params,
> > +     .audio_shutdown = audio_shutdown,
> > +     .mute_stream = audio_mute_stream,
> > +     .get_eld = audio_get_eld,
> > +     .hook_plugged_cb = audio_hook_plugged_cb, };
> > +
> > +static int snd_dw_hdmi_probe(struct platform_device *pdev) {
> > +     struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
> > +     struct snd_dw_hdmi *dw;
> > +
> > +     const struct hdmi_codec_pdata codec_data = {
> > +             .i2s = 1,
> > +             .spdif = 0,
> > +             .ops = &audio_codec_ops,
> > +             .max_i2s_channels = 8,
> > +             .data = data,
> > +     };
> > +
> > +     dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
> > +     if (!dw)
> > +             return -ENOMEM;
> > +
> > +     dw->data = *data;
> > +
> > +     platform_set_drvdata(pdev, dw);
> > +
> > +     dw->audio_pdev = platform_device_register_data(&pdev->dev,
> > +
> HDMI_CODEC_DRV_NAME, 1,
> > +
> &codec_data,
> > +
> > + sizeof(codec_data));
> > +
> > +     return PTR_ERR_OR_ZERO(dw->audio_pdev); }
> > +
> > +static int snd_dw_hdmi_remove(struct platform_device *pdev) {
> > +     struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
> > +
> > +     platform_device_unregister(dw->audio_pdev);
> > +
> > +     return 0;
> > +}
> > +
> > +static struct platform_driver snd_dw_hdmi_driver = {
> > +     .probe  = snd_dw_hdmi_probe,
> > +     .remove = snd_dw_hdmi_remove,
> > +     .driver = {
> > +             .name = DRIVER_NAME,
> > +     },
> > +};
> > +
> > +module_platform_driver(snd_dw_hdmi_driver);
> > +
> > +MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
> > +MODULE_DESCRIPTION("Synopsis Designware HDMI GPA ALSA
> interface");
> > +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME);
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > index c6e701acd416..1385d8f7870e 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -191,7 +191,10 @@ struct dw_hdmi {
> >
> >       spinlock_t audio_lock;
> >       struct mutex audio_mutex;
> > +     unsigned int sample_non_pcm;
> > +     unsigned int sample_width;
> >       unsigned int sample_rate;
> > +     unsigned int channels;
> >       unsigned int audio_cts;
> >       unsigned int audio_n;
> >       bool audio_enable;
> > @@ -589,6 +592,8 @@ static unsigned int hdmi_compute_n(unsigned int
> freq, unsigned long pixel_clk)
> >                       n = 4096;
> >               else if (pixel_clk == 74176000 || pixel_clk == 148352000)
> >                       n = 11648;
> > +             else if (pixel_clk == 297000000)
> > +                     n = 3072;
> >               else
> >                       n = 4096;
> >               n *= mult;
> > @@ -601,6 +606,8 @@ static unsigned int hdmi_compute_n(unsigned int
> freq, unsigned long pixel_clk)
> >                       n = 17836;
> >               else if (pixel_clk == 148352000)
> >                       n = 8918;
> > +             else if (pixel_clk == 297000000)
> > +                     n = 4704;
> >               else
> >                       n = 6272;
> >               n *= mult;
> > @@ -615,6 +622,8 @@ static unsigned int hdmi_compute_n(unsigned int
> freq, unsigned long pixel_clk)
> >                       n = 11648;
> >               else if (pixel_clk == 148352000)
> >                       n = 5824;
> > +             else if (pixel_clk == 297000000)
> > +                     n = 5120;
> >               else
> >                       n = 6144;
> >               n *= mult;
> > @@ -660,7 +669,7 @@ static void hdmi_set_clk_regenerator(struct
> dw_hdmi *hdmi,
> >       config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
> >
> >       /* Only compute CTS when using internal AHB audio */
> > -     if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
> > +     if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 &
> > + HDMI_CONFIG3_GPAUD)) {
> 
> Update the comment to include GPAUD.
I will update it.
> 
> >               /*
> >                * Compute the CTS value from the N value.  Note that
> CTS and N
> >                * can be up to 20 bits in total, so we need 64-bit
> > math.  Also @@ -702,6 +711,22 @@ static void
> hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
> >       mutex_unlock(&hdmi->audio_mutex);
> >   }
> >
> > +void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int
> > +width) {
> > +     mutex_lock(&hdmi->audio_mutex);
> > +     hdmi->sample_width = width;
> > +     mutex_unlock(&hdmi->audio_mutex); }
> > +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
> > +
> > +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int
> > +non_pcm) {
> > +     mutex_lock(&hdmi->audio_mutex);
> > +     hdmi->sample_non_pcm = non_pcm;
> > +     mutex_unlock(&hdmi->audio_mutex); }
> > +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
> > +
> >   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int
> rate)
> >   {
> >       mutex_lock(&hdmi->audio_mutex);
> > @@ -717,6 +742,7 @@ void dw_hdmi_set_channel_count(struct dw_hdmi
> *hdmi, unsigned int cnt)
> >       u8 layout;
> >
> >       mutex_lock(&hdmi->audio_mutex);
> > +     hdmi->channels = cnt;
> >
> >       /*
> >        * For >2 channel PCM audio, we need to select layout 1 @@
> > -765,6 +791,87 @@ static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi)
> >       return hdmi->curr_conn->eld;
> >   }
> >
> > +static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi) {
> > +     int sample_freq = 0x2, org_sample_freq = 0xD;
> > +     int ch_mask = BIT(hdmi->channels) - 1;
> > +
> > +     switch (hdmi->sample_rate) {
> > +     case 32000:
> > +             sample_freq = 0x03;
> > +             org_sample_freq = 0x0C;
> > +             break;
> > +     case 44100:
> > +             sample_freq = 0x00;
> > +             org_sample_freq = 0x0F;
> > +             break;
> > +     case 48000:
> > +             sample_freq = 0x02;
> > +             org_sample_freq = 0x0D;
> > +             break;
> > +     case 88200:
> > +             sample_freq = 0x08;
> > +             org_sample_freq = 0x07;
> > +             break;
> > +     case 96000:
> > +             sample_freq = 0x0A;
> > +             org_sample_freq = 0x05;
> > +             break;
> > +     case 176400:
> > +             sample_freq = 0x0C;
> > +             org_sample_freq = 0x03;
> > +             break;
> > +     case 192000:
> > +             sample_freq = 0x0E;
> > +             org_sample_freq = 0x01;
> > +             break;
> > +     default:
> > +             break;
> > +     }
> > +
> > +     hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> > +     hdmi_enable_audio_clk(hdmi, true);
> > +
> > +     hdmi_writeb(hdmi, 0x1, HDMI_FC_AUDSCHNLS0);
> > +     hdmi_writeb(hdmi, hdmi->channels, HDMI_FC_AUDSCHNLS2);
> > +     hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS3);
> > +     hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS4);
> > +     hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS5);
> > +     hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS6);
> > +     hdmi_writeb(hdmi, (0x3 << 4) | sample_freq,
> HDMI_FC_AUDSCHNLS7);
> > +     hdmi_writeb(hdmi, (org_sample_freq << 4) | 0xb,
> > + HDMI_FC_AUDSCHNLS8);
> > +
> > +     hdmi_writeb(hdmi, ch_mask, HDMI_GP_CONF1);
> > +     hdmi_writeb(hdmi, 0x02, HDMI_GP_CONF2);
> > +     hdmi_writeb(hdmi, 0x01, HDMI_GP_CONF0);
> > +
> > +     hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
> > +
> > +     /* hbr */
> > +     if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
> > +         hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
> > +             hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
> > +     }
> > +
> > +     if (hdmi->phy.ops->enable_audio)
> > +             hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
> > +                                         hdmi->channels,
> > +                                         hdmi->sample_width,
> > +                                         hdmi->sample_rate,
> > +
> hdmi->sample_non_pcm); }
> > +
> > +static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi) {
> > +     hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
> > +
> > +     hdmi_modb(hdmi,  0, 0x3, HDMI_FC_DATAUTO3);
> > +     if (hdmi->phy.ops->disable_audio)
> > +             hdmi->phy.ops->disable_audio(hdmi, hdmi->phy.data);
> > +
> > +     hdmi_enable_audio_clk(hdmi, false); }
> > +
> >   static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
> >   {
> >       hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); @@
> -3259,6
> > +3366,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device
> *pdev,
> >       hdmi->plat_data = plat_data;
> >       hdmi->dev = dev;
> >       hdmi->sample_rate = 48000;
> > +     hdmi->channels = 2;
> >       hdmi->disabled = true;
> >       hdmi->rxsense = true;
> >       hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
> @@
> > -3482,6 +3590,24 @@ struct dw_hdmi *dw_hdmi_probe(struct
> platform_device *pdev,
> >               pdevinfo.size_data = sizeof(audio);
> >               pdevinfo.dma_mask = DMA_BIT_MASK(32);
> >               hdmi->audio = platform_device_register_full(&pdevinfo);
> > +     } else if (iores && config3 & HDMI_CONFIG3_GPAUD) {
> > +             struct dw_hdmi_audio_data audio;
> > +
> > +             audio.phys = iores->start;
> > +             audio.base = hdmi->regs;
> > +             audio.irq = irq;
> > +             audio.hdmi = hdmi;
> > +             audio.get_eld = hdmi_audio_get_eld;
> > +
> > +             hdmi->enable_audio = dw_hdmi_gp_audio_enable;
> > +             hdmi->disable_audio = dw_hdmi_gp_audio_disable;
> > +
> > +             pdevinfo.name = "dw-hdmi-gp-audio";
> > +             pdevinfo.id = PLATFORM_DEVID_NONE;
> > +             pdevinfo.data = &audio;
> > +             pdevinfo.size_data = sizeof(audio);
> > +             pdevinfo.dma_mask = DMA_BIT_MASK(32);
> > +             hdmi->audio = platform_device_register_full(&pdevinfo);
> >       }
> >
> >       if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) {
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > index 1999db05bc3b..99aa1c03343b 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > @@ -158,8 +158,17 @@
> >   #define HDMI_FC_SPDDEVICEINF                    0x1062
> >   #define HDMI_FC_AUDSCONF                        0x1063
> >   #define HDMI_FC_AUDSSTAT                        0x1064
> > -#define HDMI_FC_AUDSCHNLS7                      0x106e
> > -#define HDMI_FC_AUDSCHNLS8                      0x106f
> > +#define HDMI_FC_AUDSV                           0x1065
> > +#define HDMI_FC_AUDSU                           0x1066
> > +#define HDMI_FC_AUDSCHNLS0                       0x1067
> > +#define HDMI_FC_AUDSCHNLS1                       0x1068
> > +#define HDMI_FC_AUDSCHNLS2                       0x1069
> > +#define HDMI_FC_AUDSCHNLS3                       0x106A
> > +#define HDMI_FC_AUDSCHNLS4                       0x106B
> > +#define HDMI_FC_AUDSCHNLS5                       0x106C
> > +#define HDMI_FC_AUDSCHNLS6                       0x106D
> > +#define HDMI_FC_AUDSCHNLS7                       0x106E
> > +#define HDMI_FC_AUDSCHNLS8                       0x106F
> >   #define HDMI_FC_DATACH0FILL                     0x1070
> >   #define HDMI_FC_DATACH1FILL                     0x1071
> >   #define HDMI_FC_DATACH2FILL                     0x1072
> > diff --git a/include/drm/bridge/dw_hdmi.h
> > b/include/drm/bridge/dw_hdmi.h index 70082f80a8c8..7f73c3398a54
> 100644
> > --- a/include/drm/bridge/dw_hdmi.h
> > +++ b/include/drm/bridge/dw_hdmi.h
> > @@ -121,6 +121,9 @@ struct dw_hdmi_phy_ops {
> >       void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
> >                          bool force, bool disabled, bool rxsense);
> >       void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
> > +     void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel,
> > +                          int width, int rate, int non_pcm);
> > +     void (*disable_audio)(struct dw_hdmi *hdmi, void *data);
> >   };
> >
> >   struct dw_hdmi_plat_data {
> > @@ -173,6 +176,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi
> *hdmi,
> > bool hpd, bool rx_sense);
> >
> >   int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi,
> hdmi_codec_plugged_cb fn,
> >                          struct device *codec_dev);
> > +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int
> > +non_pcm); void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi,
> > +unsigned int width);
> >   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int
> rate);
> >   void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int
> cnt);
> >   void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8
> > *channel_status);
> 
> Thanks,
> Neil

Thanks,
Sandor

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

* RE: [EXT] Re: [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver
@ 2022-04-07  8:31       ` Sandor Yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07  8:31 UTC (permalink / raw)
  To: Neil Armstrong, dri-devel, linux-kernel, andrzej.hajda,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, amuel, cai.huoqing, maxime, hverkuil-cisco

Hi,

> -----Original Message-----
> From: Neil Armstrong <narmstrong@baylibre.com>
> Sent: 2022年4月6日 17:28
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> robert.foss@linaro.org; Laurent.pinchart@ideasonboard.com;
> jonas@kwiboo.se; jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; cai.huoqing@linux.dev;
> maxime@cerno.tech; harry.wentland@amd.com; hverkuil-cisco@xs4all.nl;
> amuel@sholland.org
> Subject: [EXT] Re: [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General
> Parallel Audio (GPA) driver
> 
> Caution: EXT Email
> 
> Hi,
> 
> On 06/04/2022 10:48, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > General Parallel Audio (GPA) interface is one of the supported audio
> > interface for synopsys HDMI module, which has verified for i.MX8MP
> > platform.
> > This is initial version for GPA.
> >
> > Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >   drivers/gpu/drm/bridge/synopsys/Kconfig       |  11 +
> >   drivers/gpu/drm/bridge/synopsys/Makefile      |   1 +
> >   .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    | 199
> ++++++++++++++++++
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 128 ++++++++++-
> >   drivers/gpu/drm/bridge/synopsys/dw-hdmi.h     |  13 +-
> >   include/drm/bridge/dw_hdmi.h                  |   5 +
> >   6 files changed, 354 insertions(+), 3 deletions(-)
> >   create mode 100644
> > drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig
> > b/drivers/gpu/drm/bridge/synopsys/Kconfig
> > index 21a1be3ced0f..e398b58c996d 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/Kconfig
> > +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
> > @@ -25,6 +25,17 @@ config DRM_DW_HDMI_I2S_AUDIO
> >         Support the I2S Audio interface which is part of the Synopsys
> >         Designware HDMI block.
> >
> > +config DRM_DW_HDMI_GP_AUDIO
> > +     tristate "Synopsys Designware GP Audio interface"
> > +     depends on DRM_DW_HDMI && SND
> > +     select SND_PCM
> > +     select SND_PCM_ELD
> > +     select SND_PCM_IEC958
> > +     help
> > +       Support the GP Audio interface which is part of the Synopsys
> > +       Designware HDMI block.  This is used in conjunction with
> > +       the i.MX865 HDMI driver.
> 
> What does that mean ? it can only be used with i.MX865 HDMI driver ?
> If not, remove reference to i.MX865 HDMI driver.
> 
GP audio driver could be used for different SOCs, i.MX865 specific description will be removed.
> > +
> >   config DRM_DW_HDMI_CEC
> >       tristate "Synopsis Designware CEC interface"
> >       depends on DRM_DW_HDMI
> > diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile
> > b/drivers/gpu/drm/bridge/synopsys/Makefile
> > index 91d746ad5de1..ce715562e9e5 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/Makefile
> > +++ b/drivers/gpu/drm/bridge/synopsys/Makefile
> > @@ -1,6 +1,7 @@
> >   # SPDX-License-Identifier: GPL-2.0-only
> >   obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
> >   obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
> > +obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o
> >   obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
> >   obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
> >
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> > new file mode 100644
> > index 000000000000..10a957c85a83
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
> > @@ -0,0 +1,199 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * dw-hdmi-gp-audio.c
> > + *
> > + * Copyright 2020-2022 NXP
> > + */
> > +#include <linux/io.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/dma-mapping.h>
> > +#include <drm/bridge/dw_hdmi.h>
> > +#include <drm/drm_edid.h>
> > +#include <drm/drm_connector.h>
> > +
> > +#include <sound/hdmi-codec.h>
> > +#include <sound/asoundef.h>
> > +#include <sound/core.h>
> > +#include <sound/initval.h>
> > +#include <sound/pcm.h>
> > +#include <sound/pcm_drm_eld.h>
> > +#include <sound/pcm_iec958.h>
> > +#include <sound/dmaengine_pcm.h>
> > +
> > +#include "dw-hdmi-audio.h"
> > +
> > +#define DRIVER_NAME "dw-hdmi-gp-audio"
> > +#define DRV_NAME    "hdmi-gp-audio"
> > +
> > +struct snd_dw_hdmi {
> > +     struct dw_hdmi_audio_data data;
> > +     struct platform_device  *audio_pdev;
> > +     unsigned int pos;
> > +};
> > +
> > +struct dw_hdmi_channel_conf {
> > +     u8 conf1;
> > +     u8 ca;
> > +};
> > +
> > +/*
> > + * The default mapping of ALSA channels to HDMI channels and speaker
> > + * allocation bits.  Note that we can't do channel remapping here -
> > + * channels must be in the same order.
> > + *
> > + * Mappings for alsa-lib pcm/surround*.conf files:
> > + *
> > + *           Front   Sur4.0  Sur4.1  Sur5.0  Sur5.1  Sur7.1
> > + * Channels  2       4       6       6       6       8
> > + *
> > + * Our mapping from ALSA channel to CEA686D speaker name and HDMI
> channel:
> > + *
> > + *                           Number of ALSA channels
> > + * ALSA Channel      2       3       4       5       6       7
> 8
> > + * 0         FL:0    =       =       =       =       =
> =
> > + * 1         FR:1    =       =       =       =       =
> =
> > + * 2                 FC:3    RL:4    LFE:2   =       =       =
> > + * 3                         RR:5    RL:4    FC:3    =       =
> > + * 4                                 RR:5    RL:4    =
> =
> > + * 5                                         RR:5    =
> =
> > + * 6                                                 RC:6
> =
> > + * 7                                                 RLC/FRC
> RLC/FRC
> > + */
> > +static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
> > +     { 0x03, 0x00 }, /* FL,FR */
> > +     { 0x0b, 0x02 }, /* FL,FR,FC */
> > +     { 0x33, 0x08 }, /* FL,FR,RL,RR */
> > +     { 0x37, 0x09 }, /* FL,FR,LFE,RL,RR */
> > +     { 0x3f, 0x0b }, /* FL,FR,LFE,FC,RL,RR */
> > +     { 0x7f, 0x0f }, /* FL,FR,LFE,FC,RL,RR,RC */
> > +     { 0xff, 0x13 }, /* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */ };
> > +
> > +static int audio_hw_params(struct device *dev,  void *data,
> > +                        struct hdmi_codec_daifmt *daifmt,
> > +                        struct hdmi_codec_params *params) {
> > +     struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> > +     int ret = 0;
> > +     u8 ca;
> > +
> > +     dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
> > +
> > +     ca = default_hdmi_channel_config[params->channels - 2].ca;
> > +
> > +     dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
> > +     dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
> > +
> > +     dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
> > +                                params->iec.status[0] &
> IEC958_AES0_NONAUDIO);
> > +     dw_hdmi_set_sample_width(dw->data.hdmi,
> params->sample_width);
> > +
> > +     return ret;
> > +}
> > +
> > +static void audio_shutdown(struct device *dev, void *data) { }
> > +
> > +static int audio_mute_stream(struct device *dev, void *data,
> > +                           bool enable, int direction) {
> > +     struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> > +     int ret = 0;
> > +
> > +     if (!enable)
> > +             dw_hdmi_audio_enable(dw->data.hdmi);
> > +     else
> > +             dw_hdmi_audio_disable(dw->data.hdmi);
> > +
> > +     return ret;
> > +}
> > +
> > +static int audio_get_eld(struct device *dev, void *data,
> > +                      u8 *buf, size_t len) {
> > +     struct dw_hdmi_audio_data *audio = data;
> > +     u8 *eld;
> > +
> > +     eld = audio->get_eld(audio->hdmi);
> > +     if (eld)
> > +             memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
> > +     else
> > +             /* Pass en empty ELD if connector not available */
> > +             memset(buf, 0, len);
> > +
> > +     return 0;
> > +}
> > +
> > +static int audio_hook_plugged_cb(struct device *dev, void *data,
> > +                              hdmi_codec_plugged_cb fn,
> > +                              struct device *codec_dev) {
> > +     struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
> > +
> > +     return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev); }
> > +
> > +static const struct hdmi_codec_ops audio_codec_ops = {
> > +     .hw_params = audio_hw_params,
> > +     .audio_shutdown = audio_shutdown,
> > +     .mute_stream = audio_mute_stream,
> > +     .get_eld = audio_get_eld,
> > +     .hook_plugged_cb = audio_hook_plugged_cb, };
> > +
> > +static int snd_dw_hdmi_probe(struct platform_device *pdev) {
> > +     struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
> > +     struct snd_dw_hdmi *dw;
> > +
> > +     const struct hdmi_codec_pdata codec_data = {
> > +             .i2s = 1,
> > +             .spdif = 0,
> > +             .ops = &audio_codec_ops,
> > +             .max_i2s_channels = 8,
> > +             .data = data,
> > +     };
> > +
> > +     dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
> > +     if (!dw)
> > +             return -ENOMEM;
> > +
> > +     dw->data = *data;
> > +
> > +     platform_set_drvdata(pdev, dw);
> > +
> > +     dw->audio_pdev = platform_device_register_data(&pdev->dev,
> > +
> HDMI_CODEC_DRV_NAME, 1,
> > +
> &codec_data,
> > +
> > + sizeof(codec_data));
> > +
> > +     return PTR_ERR_OR_ZERO(dw->audio_pdev); }
> > +
> > +static int snd_dw_hdmi_remove(struct platform_device *pdev) {
> > +     struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
> > +
> > +     platform_device_unregister(dw->audio_pdev);
> > +
> > +     return 0;
> > +}
> > +
> > +static struct platform_driver snd_dw_hdmi_driver = {
> > +     .probe  = snd_dw_hdmi_probe,
> > +     .remove = snd_dw_hdmi_remove,
> > +     .driver = {
> > +             .name = DRIVER_NAME,
> > +     },
> > +};
> > +
> > +module_platform_driver(snd_dw_hdmi_driver);
> > +
> > +MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
> > +MODULE_DESCRIPTION("Synopsis Designware HDMI GPA ALSA
> interface");
> > +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME);
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > index c6e701acd416..1385d8f7870e 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -191,7 +191,10 @@ struct dw_hdmi {
> >
> >       spinlock_t audio_lock;
> >       struct mutex audio_mutex;
> > +     unsigned int sample_non_pcm;
> > +     unsigned int sample_width;
> >       unsigned int sample_rate;
> > +     unsigned int channels;
> >       unsigned int audio_cts;
> >       unsigned int audio_n;
> >       bool audio_enable;
> > @@ -589,6 +592,8 @@ static unsigned int hdmi_compute_n(unsigned int
> freq, unsigned long pixel_clk)
> >                       n = 4096;
> >               else if (pixel_clk == 74176000 || pixel_clk == 148352000)
> >                       n = 11648;
> > +             else if (pixel_clk == 297000000)
> > +                     n = 3072;
> >               else
> >                       n = 4096;
> >               n *= mult;
> > @@ -601,6 +606,8 @@ static unsigned int hdmi_compute_n(unsigned int
> freq, unsigned long pixel_clk)
> >                       n = 17836;
> >               else if (pixel_clk == 148352000)
> >                       n = 8918;
> > +             else if (pixel_clk == 297000000)
> > +                     n = 4704;
> >               else
> >                       n = 6272;
> >               n *= mult;
> > @@ -615,6 +622,8 @@ static unsigned int hdmi_compute_n(unsigned int
> freq, unsigned long pixel_clk)
> >                       n = 11648;
> >               else if (pixel_clk == 148352000)
> >                       n = 5824;
> > +             else if (pixel_clk == 297000000)
> > +                     n = 5120;
> >               else
> >                       n = 6144;
> >               n *= mult;
> > @@ -660,7 +669,7 @@ static void hdmi_set_clk_regenerator(struct
> dw_hdmi *hdmi,
> >       config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
> >
> >       /* Only compute CTS when using internal AHB audio */
> > -     if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
> > +     if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 &
> > + HDMI_CONFIG3_GPAUD)) {
> 
> Update the comment to include GPAUD.
I will update it.
> 
> >               /*
> >                * Compute the CTS value from the N value.  Note that
> CTS and N
> >                * can be up to 20 bits in total, so we need 64-bit
> > math.  Also @@ -702,6 +711,22 @@ static void
> hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
> >       mutex_unlock(&hdmi->audio_mutex);
> >   }
> >
> > +void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int
> > +width) {
> > +     mutex_lock(&hdmi->audio_mutex);
> > +     hdmi->sample_width = width;
> > +     mutex_unlock(&hdmi->audio_mutex); }
> > +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
> > +
> > +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int
> > +non_pcm) {
> > +     mutex_lock(&hdmi->audio_mutex);
> > +     hdmi->sample_non_pcm = non_pcm;
> > +     mutex_unlock(&hdmi->audio_mutex); }
> > +EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
> > +
> >   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int
> rate)
> >   {
> >       mutex_lock(&hdmi->audio_mutex);
> > @@ -717,6 +742,7 @@ void dw_hdmi_set_channel_count(struct dw_hdmi
> *hdmi, unsigned int cnt)
> >       u8 layout;
> >
> >       mutex_lock(&hdmi->audio_mutex);
> > +     hdmi->channels = cnt;
> >
> >       /*
> >        * For >2 channel PCM audio, we need to select layout 1 @@
> > -765,6 +791,87 @@ static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi)
> >       return hdmi->curr_conn->eld;
> >   }
> >
> > +static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi) {
> > +     int sample_freq = 0x2, org_sample_freq = 0xD;
> > +     int ch_mask = BIT(hdmi->channels) - 1;
> > +
> > +     switch (hdmi->sample_rate) {
> > +     case 32000:
> > +             sample_freq = 0x03;
> > +             org_sample_freq = 0x0C;
> > +             break;
> > +     case 44100:
> > +             sample_freq = 0x00;
> > +             org_sample_freq = 0x0F;
> > +             break;
> > +     case 48000:
> > +             sample_freq = 0x02;
> > +             org_sample_freq = 0x0D;
> > +             break;
> > +     case 88200:
> > +             sample_freq = 0x08;
> > +             org_sample_freq = 0x07;
> > +             break;
> > +     case 96000:
> > +             sample_freq = 0x0A;
> > +             org_sample_freq = 0x05;
> > +             break;
> > +     case 176400:
> > +             sample_freq = 0x0C;
> > +             org_sample_freq = 0x03;
> > +             break;
> > +     case 192000:
> > +             sample_freq = 0x0E;
> > +             org_sample_freq = 0x01;
> > +             break;
> > +     default:
> > +             break;
> > +     }
> > +
> > +     hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> > +     hdmi_enable_audio_clk(hdmi, true);
> > +
> > +     hdmi_writeb(hdmi, 0x1, HDMI_FC_AUDSCHNLS0);
> > +     hdmi_writeb(hdmi, hdmi->channels, HDMI_FC_AUDSCHNLS2);
> > +     hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS3);
> > +     hdmi_writeb(hdmi, 0x22, HDMI_FC_AUDSCHNLS4);
> > +     hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS5);
> > +     hdmi_writeb(hdmi, 0x11, HDMI_FC_AUDSCHNLS6);
> > +     hdmi_writeb(hdmi, (0x3 << 4) | sample_freq,
> HDMI_FC_AUDSCHNLS7);
> > +     hdmi_writeb(hdmi, (org_sample_freq << 4) | 0xb,
> > + HDMI_FC_AUDSCHNLS8);
> > +
> > +     hdmi_writeb(hdmi, ch_mask, HDMI_GP_CONF1);
> > +     hdmi_writeb(hdmi, 0x02, HDMI_GP_CONF2);
> > +     hdmi_writeb(hdmi, 0x01, HDMI_GP_CONF0);
> > +
> > +     hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
> > +
> > +     /* hbr */
> > +     if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
> > +         hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
> > +             hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
> > +     }
> > +
> > +     if (hdmi->phy.ops->enable_audio)
> > +             hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
> > +                                         hdmi->channels,
> > +                                         hdmi->sample_width,
> > +                                         hdmi->sample_rate,
> > +
> hdmi->sample_non_pcm); }
> > +
> > +static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi) {
> > +     hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
> > +
> > +     hdmi_modb(hdmi,  0, 0x3, HDMI_FC_DATAUTO3);
> > +     if (hdmi->phy.ops->disable_audio)
> > +             hdmi->phy.ops->disable_audio(hdmi, hdmi->phy.data);
> > +
> > +     hdmi_enable_audio_clk(hdmi, false); }
> > +
> >   static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
> >   {
> >       hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); @@
> -3259,6
> > +3366,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device
> *pdev,
> >       hdmi->plat_data = plat_data;
> >       hdmi->dev = dev;
> >       hdmi->sample_rate = 48000;
> > +     hdmi->channels = 2;
> >       hdmi->disabled = true;
> >       hdmi->rxsense = true;
> >       hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
> @@
> > -3482,6 +3590,24 @@ struct dw_hdmi *dw_hdmi_probe(struct
> platform_device *pdev,
> >               pdevinfo.size_data = sizeof(audio);
> >               pdevinfo.dma_mask = DMA_BIT_MASK(32);
> >               hdmi->audio = platform_device_register_full(&pdevinfo);
> > +     } else if (iores && config3 & HDMI_CONFIG3_GPAUD) {
> > +             struct dw_hdmi_audio_data audio;
> > +
> > +             audio.phys = iores->start;
> > +             audio.base = hdmi->regs;
> > +             audio.irq = irq;
> > +             audio.hdmi = hdmi;
> > +             audio.get_eld = hdmi_audio_get_eld;
> > +
> > +             hdmi->enable_audio = dw_hdmi_gp_audio_enable;
> > +             hdmi->disable_audio = dw_hdmi_gp_audio_disable;
> > +
> > +             pdevinfo.name = "dw-hdmi-gp-audio";
> > +             pdevinfo.id = PLATFORM_DEVID_NONE;
> > +             pdevinfo.data = &audio;
> > +             pdevinfo.size_data = sizeof(audio);
> > +             pdevinfo.dma_mask = DMA_BIT_MASK(32);
> > +             hdmi->audio = platform_device_register_full(&pdevinfo);
> >       }
> >
> >       if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) {
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > index 1999db05bc3b..99aa1c03343b 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> > @@ -158,8 +158,17 @@
> >   #define HDMI_FC_SPDDEVICEINF                    0x1062
> >   #define HDMI_FC_AUDSCONF                        0x1063
> >   #define HDMI_FC_AUDSSTAT                        0x1064
> > -#define HDMI_FC_AUDSCHNLS7                      0x106e
> > -#define HDMI_FC_AUDSCHNLS8                      0x106f
> > +#define HDMI_FC_AUDSV                           0x1065
> > +#define HDMI_FC_AUDSU                           0x1066
> > +#define HDMI_FC_AUDSCHNLS0                       0x1067
> > +#define HDMI_FC_AUDSCHNLS1                       0x1068
> > +#define HDMI_FC_AUDSCHNLS2                       0x1069
> > +#define HDMI_FC_AUDSCHNLS3                       0x106A
> > +#define HDMI_FC_AUDSCHNLS4                       0x106B
> > +#define HDMI_FC_AUDSCHNLS5                       0x106C
> > +#define HDMI_FC_AUDSCHNLS6                       0x106D
> > +#define HDMI_FC_AUDSCHNLS7                       0x106E
> > +#define HDMI_FC_AUDSCHNLS8                       0x106F
> >   #define HDMI_FC_DATACH0FILL                     0x1070
> >   #define HDMI_FC_DATACH1FILL                     0x1071
> >   #define HDMI_FC_DATACH2FILL                     0x1072
> > diff --git a/include/drm/bridge/dw_hdmi.h
> > b/include/drm/bridge/dw_hdmi.h index 70082f80a8c8..7f73c3398a54
> 100644
> > --- a/include/drm/bridge/dw_hdmi.h
> > +++ b/include/drm/bridge/dw_hdmi.h
> > @@ -121,6 +121,9 @@ struct dw_hdmi_phy_ops {
> >       void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
> >                          bool force, bool disabled, bool rxsense);
> >       void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
> > +     void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel,
> > +                          int width, int rate, int non_pcm);
> > +     void (*disable_audio)(struct dw_hdmi *hdmi, void *data);
> >   };
> >
> >   struct dw_hdmi_plat_data {
> > @@ -173,6 +176,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi
> *hdmi,
> > bool hpd, bool rx_sense);
> >
> >   int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi,
> hdmi_codec_plugged_cb fn,
> >                          struct device *codec_dev);
> > +void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int
> > +non_pcm); void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi,
> > +unsigned int width);
> >   void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int
> rate);
> >   void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int
> cnt);
> >   void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8
> > *channel_status);
> 
> Thanks,
> Neil

Thanks,
Sandor

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

* Re: [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix
  2022-04-06  8:48 ` Sandor.yu
@ 2022-04-07  8:43   ` Philipp Zabel
  -1 siblings, 0 replies; 32+ messages in thread
From: Philipp Zabel @ 2022-04-07  8:43 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, narmstrong,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: shengjiu.wang, amuel, cai.huoqing, maxime, hverkuil-cisco

Hi Sandor,

On Mi, 2022-04-06 at 16:48 +0800, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> It is new features and bug fix patch set for DW_HDMI DRM bridge driver
> that has verified by NXP iMX865.

Is that iMX865 or i.MX865? Both are used in different places of this
patchset, I'd pick the official spelling and use it everywhere.

regards
Philipp

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

* Re: [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix
@ 2022-04-07  8:43   ` Philipp Zabel
  0 siblings, 0 replies; 32+ messages in thread
From: Philipp Zabel @ 2022-04-07  8:43 UTC (permalink / raw)
  To: Sandor.yu, dri-devel, linux-kernel, andrzej.hajda, narmstrong,
	robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: hverkuil-cisco, amuel, shengjiu.wang, cai.huoqing, maxime

Hi Sandor,

On Mi, 2022-04-06 at 16:48 +0800, Sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> It is new features and bug fix patch set for DW_HDMI DRM bridge driver
> that has verified by NXP iMX865.

Is that iMX865 or i.MX865? Both are used in different places of this
patchset, I'd pick the official spelling and use it everywhere.

regards
Philipp

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

* RE: [EXT] Re: [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix
  2022-04-07  8:43   ` Philipp Zabel
@ 2022-04-07 11:46     ` Sandor Yu
  -1 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07 11:46 UTC (permalink / raw)
  To: Philipp Zabel, dri-devel, linux-kernel, andrzej.hajda,
	narmstrong, robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: S.J. Wang, amuel, cai.huoqing, maxime, hverkuil-cisco

Hi Philipp

> -----Original Message-----
> From: Philipp Zabel <p.zabel@pengutronix.de>
> Sent: 2022年4月7日 16:43
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> narmstrong@baylibre.com; robert.foss@linaro.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; amuel@sholland.org;
> cai.huoqing@linux.dev; maxime@cerno.tech; hverkuil-cisco@xs4all.nl
> Subject: [EXT] Re: [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features
> and bug fix
> 
> Caution: EXT Email
> 
> Hi Sandor,
> 
> On Mi, 2022-04-06 at 16:48 +0800, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > It is new features and bug fix patch set for DW_HDMI DRM bridge driver
> > that has verified by NXP iMX865.
> 
> Is that iMX865 or i.MX865? Both are used in different places of this patchset,
> I'd pick the official spelling and use it everywhere.
> 
Check it in NXP internal, the i.MX865 official name in community should be i.MX 8M Plus or i.MX8MPlus
I will use i.MX8MPlus in the patch set later.
Thanks for your comments.

> regards
> Philipp

B.R
Sandor

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

* RE: [EXT] Re: [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix
@ 2022-04-07 11:46     ` Sandor Yu
  0 siblings, 0 replies; 32+ messages in thread
From: Sandor Yu @ 2022-04-07 11:46 UTC (permalink / raw)
  To: Philipp Zabel, dri-devel, linux-kernel, andrzej.hajda,
	narmstrong, robert.foss, Laurent.pinchart, jonas, jernej.skrabec
  Cc: hverkuil-cisco, amuel, S.J. Wang, cai.huoqing, maxime

Hi Philipp

> -----Original Message-----
> From: Philipp Zabel <p.zabel@pengutronix.de>
> Sent: 2022年4月7日 16:43
> To: Sandor Yu <sandor.yu@nxp.com>; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; andrzej.hajda@intel.com;
> narmstrong@baylibre.com; robert.foss@linaro.org;
> Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se;
> jernej.skrabec@gmail.com
> Cc: S.J. Wang <shengjiu.wang@nxp.com>; amuel@sholland.org;
> cai.huoqing@linux.dev; maxime@cerno.tech; hverkuil-cisco@xs4all.nl
> Subject: [EXT] Re: [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features
> and bug fix
> 
> Caution: EXT Email
> 
> Hi Sandor,
> 
> On Mi, 2022-04-06 at 16:48 +0800, Sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > It is new features and bug fix patch set for DW_HDMI DRM bridge driver
> > that has verified by NXP iMX865.
> 
> Is that iMX865 or i.MX865? Both are used in different places of this patchset,
> I'd pick the official spelling and use it everywhere.
> 
Check it in NXP internal, the i.MX865 official name in community should be i.MX 8M Plus or i.MX8MPlus
I will use i.MX8MPlus in the patch set later.
Thanks for your comments.

> regards
> Philipp

B.R
Sandor

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

end of thread, other threads:[~2022-04-07 11:46 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-06  8:48 [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix Sandor.yu
2022-04-06  8:48 ` Sandor.yu
2022-04-06  8:48 ` [PATCH v1 1/5] drm: bridge: dw_hdmi: cec: Add cec suspend/resume function Sandor.yu
2022-04-06  8:48   ` Sandor.yu
2022-04-06  9:46   ` Hans Verkuil
2022-04-06  9:46     ` Hans Verkuil
2022-04-07  8:30     ` [EXT] " Sandor Yu
2022-04-07  8:30       ` Sandor Yu
2022-04-06  8:48 ` [PATCH v1 2/5] drm: bridge: dw_hdmi: enable overflow workaround for v2.13a Sandor.yu
2022-04-06  8:48   ` Sandor.yu
2022-04-06  9:17   ` Neil Armstrong
2022-04-06  9:17     ` Neil Armstrong
2022-04-07  8:30     ` [EXT] " Sandor Yu
2022-04-07  8:30       ` Sandor Yu
2022-04-06  8:48 ` [PATCH v1 3/5] drm: bridge: dw_hdmi: Enable GCP only for Deep Color Sandor.yu
2022-04-06  8:48   ` Sandor.yu
2022-04-06  9:20   ` Neil Armstrong
2022-04-06  9:20     ` Neil Armstrong
2022-04-07  8:31     ` [EXT] " Sandor Yu
2022-04-07  8:31       ` Sandor Yu
2022-04-06  8:48 ` [PATCH v1 4/5] drm: bridge: dw_hdmi: add reset function for PHY GEN1 Sandor.yu
2022-04-06  8:48   ` Sandor.yu
2022-04-06  8:48 ` [PATCH v1 5/5] drm: bridge: dw_hdmi: Audio: Add General Parallel Audio (GPA) driver Sandor.yu
2022-04-06  8:48   ` Sandor.yu
2022-04-06  9:27   ` Neil Armstrong
2022-04-06  9:27     ` Neil Armstrong
2022-04-07  8:31     ` [EXT] " Sandor Yu
2022-04-07  8:31       ` Sandor Yu
2022-04-07  8:43 ` [PATCH v1 0/5] DRM: Bridge: DW_HDMI: Add new features and bug fix Philipp Zabel
2022-04-07  8:43   ` Philipp Zabel
2022-04-07 11:46   ` [EXT] " Sandor Yu
2022-04-07 11:46     ` Sandor Yu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.