public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure
@ 2025-01-24 21:47 Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 1/7] drm/msm/hdmi: switch to atomic bridge callbacks Dmitry Baryshkov
                   ` (6 more replies)
  0 siblings, 7 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

This patchset sits on top Maxime's HDMI connector patchset ([1]).

Currently this is an RFC exploring the interface between HDMI bridges
and HDMI connector code. This has been lightly verified on the Qualcomm
DB820c, which has native HDMI output. If this approach is considered to
be acceptable, I'll finish MSM HDMI bridge conversion (reworking the
Audio Infoframe code). Other bridges can follow the same approach (we
have lt9611 / lt9611uxc / adv7511 on Qualcomm hardware).

[1] https://patchwork.freedesktop.org/series/122421/

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
Changes in v6:
- Moved HDMI timing engine programming to the end of the atomic_prepare
  (Abhinav)
- Rebased on top of drm-misc-next, incorporating changes to
  drm_bridge_connector
- Switched to the DRM HDMI Audio framework for the HDMI codec
  implementation
- Link to v5: https://lore.kernel.org/r/20240607-bridge-hdmi-connector-v5-0-ab384e6021af@linaro.org

Changes in v5:
- Made drm_bridge_funcs::hdmi_clear_infoframe() callback mandatory for
  DRM_BRIDGE_OP_HDMI bridges (Maxime)
- Added drm_atomic_helper_connector_hdmi_disable_audio_infoframe()
  instead of passing NULL frame to
  drm_atomic_helper_connector_hdmi_update_audio_infoframe() (Maxime)
- Disable Audio Infoframe in MSM HDMI driver on audio shutdown.
- Link to v4: https://lore.kernel.org/r/20240531-bridge-hdmi-connector-v4-0-5110f7943622@linaro.org

Changes in v4:
- Reworked drm_bridge_connector functions to remove ternary operators
  and to reduce indentation level (Maxime)
- Added hdmi_ prefix to all HDMI-related drm_bridge_funcs calls (Maxime)
- Made vendor and product mandatory to the HDMI bridges (Maxime)
- Documented that max_bpc can be 8, 10 or 12 (Maxime)
- Changed hdmi->pixclock to be set using tmds_char_rate instead of
  calculating that manually (Maxime)
- Changed mode_valid to use helper function instead of manually
  doing mode->clock * 1000
- Removed hdmi_mode in favour of connector->display_info.is_hdmi
- Link to v3: https://lore.kernel.org/r/20240530-bridge-hdmi-connector-v3-0-a1d184d68fe3@linaro.org

Changes in v3:
- Rebased on top of the merged HDMI connector patchset.
- Changed drm_bridge_connector to use drmm_connector_init() (Maxime)
- Added a check that write_infoframe callback is present if
  BRIDGE_OP_HDMI is set.
- Moved drm_atomic_helper_connector_hdmi_check() call from
  drm_bridge_connector to the HDMI bridge driver to remove dependency
  from drm_kms_helpers on the optional HDMI state helpers.
- Converted Audio InfoFrame handling code.
- Added support for HDMI Vendor Specific and SPD InfoFrames.
- Link to v2: https://lore.kernel.org/r/20240309-bridge-hdmi-connector-v2-0-1380bea3ee70@linaro.org

Changes in v2:
- Dropped drm_connector_hdmi_setup(). Instead added
  drm_connector_hdmi_init() to be used by drm_bridge_connector.
- Changed the drm_bridge_connector to act as a proxy for the HDMI
  connector  infrastructure. This removes most of the logic from
  the bridge drivers.
- Link to v1: https://lore.kernel.org/r/20240308-bridge-hdmi-connector-v1-0-90b693550260@linaro.org

---
Dmitry Baryshkov (7):
      drm/msm/hdmi: switch to atomic bridge callbacks
      drm/msm/hdmi: program HDMI timings during atomic_pre_enable
      drm/msm/hdmi: make use of the drm_connector_hdmi framework
      drm/msm/hdmi: get rid of hdmi_mode
      drm/msm/hdmi: update HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE definition
      drm/msm/hdmi: also send the SPD and HDMI Vendor Specific InfoFrames
      drm/msm/hdmi: use DRM HDMI Audio framework

 drivers/gpu/drm/msm/Kconfig                    |   2 +
 drivers/gpu/drm/msm/hdmi/hdmi.c                | 120 +--------
 drivers/gpu/drm/msm/hdmi/hdmi.h                |  34 +--
 drivers/gpu/drm/msm/hdmi/hdmi_audio.c          | 131 +++++-----
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c         | 325 +++++++++++++++++++------
 drivers/gpu/drm/msm/registers/display/hdmi.xml |   2 +-
 6 files changed, 337 insertions(+), 277 deletions(-)
---
base-commit: 04db8124620ddca01d2fdc48d15471dd77efeff0
change-id: 20240307-bridge-hdmi-connector-7e3754e661d0

Best regards,
-- 
Dmitry Baryshkov <dmitry.baryshkov@linaro.org>


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

* [PATCH v6 1/7] drm/msm/hdmi: switch to atomic bridge callbacks
  2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
@ 2025-01-24 21:47 ` Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable Dmitry Baryshkov
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

Change MSM HDMI bridge to use atomic_* callbacks in preparation to
enablign the HDMI connector support.

Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 4a5b5112227f516dfc4279d0f319ec1e5b17f240..d839c71091dcdc3b020fcbba8d698d58ee7fc749 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -126,7 +126,8 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
 	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
 }
 
-static void msm_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
+static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+					      struct drm_bridge_state *old_bridge_state)
 {
 	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
 	struct hdmi *hdmi = hdmi_bridge->hdmi;
@@ -152,7 +153,8 @@ static void msm_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
 		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
 }
 
-static void msm_hdmi_bridge_post_disable(struct drm_bridge *bridge)
+static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
+						struct drm_bridge_state *old_bridge_state)
 {
 	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
 	struct hdmi *hdmi = hdmi_bridge->hdmi;
@@ -299,8 +301,11 @@ static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge
 }
 
 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
-	.pre_enable = msm_hdmi_bridge_pre_enable,
-	.post_disable = msm_hdmi_bridge_post_disable,
+	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+	.atomic_reset = drm_atomic_helper_bridge_reset,
+	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
+	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
 	.mode_set = msm_hdmi_bridge_mode_set,
 	.mode_valid = msm_hdmi_bridge_mode_valid,
 	.edid_read = msm_hdmi_bridge_edid_read,

-- 
2.39.5


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

* [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 1/7] drm/msm/hdmi: switch to atomic bridge callbacks Dmitry Baryshkov
@ 2025-01-24 21:47 ` Dmitry Baryshkov
  2025-01-26 16:41   ` Maxime Ripard
  2025-02-03 19:34   ` Abhinav Kumar
  2025-01-24 21:47 ` [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework Dmitry Baryshkov
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

The mode_set callback is deprecated, it doesn't get the
drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
that HDMI timings should be programmed after setting up HDMI PHY and
PLL. Rework the code to program HDMI timings at the end of
atomic_pre_enable().

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index d839c71091dcdc3b020fcbba8d698d58ee7fc749..d5ab1f74c0e6f47dc59872c016104e9a84d85e9e 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -126,15 +126,26 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
 	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
 }
 
+static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
+					       const struct drm_display_mode *mode);
 static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
 					      struct drm_bridge_state *old_bridge_state)
 {
+	struct drm_atomic_state *state = old_bridge_state->base.state;
 	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
 	struct hdmi *hdmi = hdmi_bridge->hdmi;
 	struct hdmi_phy *phy = hdmi->phy;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	struct drm_crtc_state *crtc_state;
 
 	DBG("power up");
 
+	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+
 	if (!hdmi->power_on) {
 		msm_hdmi_phy_resource_enable(phy);
 		msm_hdmi_power_on(bridge);
@@ -151,6 +162,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
 
 	if (hdmi->hdcp_ctrl)
 		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
+
+	msm_hdmi_bridge_atomic_set_timings(hdmi, &crtc_state->adjusted_mode);
 }
 
 static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
@@ -177,17 +190,12 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
 	}
 }
 
-static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge,
-		 const struct drm_display_mode *mode,
-		 const struct drm_display_mode *adjusted_mode)
+static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
+					       const struct drm_display_mode *mode)
 {
-	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
-	struct hdmi *hdmi = hdmi_bridge->hdmi;
 	int hstart, hend, vstart, vend;
 	uint32_t frame_ctrl;
 
-	mode = adjusted_mode;
-
 	hdmi->pixclock = mode->clock * 1000;
 
 	hstart = mode->htotal - mode->hsync_start;
@@ -306,7 +314,6 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
 	.atomic_reset = drm_atomic_helper_bridge_reset,
 	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
 	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
-	.mode_set = msm_hdmi_bridge_mode_set,
 	.mode_valid = msm_hdmi_bridge_mode_valid,
 	.edid_read = msm_hdmi_bridge_edid_read,
 	.detect = msm_hdmi_bridge_detect,

-- 
2.39.5


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

* [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework
  2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 1/7] drm/msm/hdmi: switch to atomic bridge callbacks Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable Dmitry Baryshkov
@ 2025-01-24 21:47 ` Dmitry Baryshkov
  2025-02-04  0:25   ` Abhinav Kumar
  2025-01-24 21:47 ` [PATCH v6 4/7] drm/msm/hdmi: get rid of hdmi_mode Dmitry Baryshkov
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

Setup the HDMI connector on the MSM HDMI outputs. Make use of
atomic_check hook and of the provided Infoframe infrastructure.

Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/Kconfig            |   2 +
 drivers/gpu/drm/msm/hdmi/hdmi.c        |  45 ++-------
 drivers/gpu/drm/msm/hdmi/hdmi.h        |  16 +--
 drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  74 ++++----------
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 180 +++++++++++++++++++++++----------
 5 files changed, 162 insertions(+), 155 deletions(-)

diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce9039d6f26f290d0 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -170,6 +170,8 @@ config DRM_MSM_HDMI
 	bool "Enable HDMI support in MSM DRM driver"
 	depends on DRM_MSM
 	default y
+	select DRM_DISPLAY_HDMI_HELPER
+	select DRM_DISPLAY_HDMI_STATE_HELPER
 	help
 	  Compile in support for the HDMI output MSM DRM driver. It can
 	  be a primary or a secondary display on device. Note that this is used
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe9b69c0da594bd 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -12,6 +12,7 @@
 
 #include <drm/drm_bridge_connector.h>
 #include <drm/drm_of.h>
+#include <drm/display/drm_hdmi_state_helper.h>
 
 #include <sound/hdmi-codec.h>
 #include "hdmi.h"
@@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
 	hdmi->dev = dev;
 	hdmi->encoder = encoder;
 
-	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
-
 	ret = msm_hdmi_bridge_init(hdmi);
 	if (ret) {
 		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
@@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
 				    struct hdmi_codec_params *params)
 {
 	struct hdmi *hdmi = dev_get_drvdata(dev);
-	unsigned int chan;
-	unsigned int channel_allocation = 0;
 	unsigned int rate;
-	unsigned int level_shift  = 0; /* 0dB */
-	bool down_mix = false;
+	int ret;
 
 	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
 		 params->sample_width, params->cea.channels);
 
-	switch (params->cea.channels) {
-	case 2:
-		/* FR and FL speakers */
-		channel_allocation  = 0;
-		chan = MSM_HDMI_AUDIO_CHANNEL_2;
-		break;
-	case 4:
-		/* FC, LFE, FR and FL speakers */
-		channel_allocation  = 0x3;
-		chan = MSM_HDMI_AUDIO_CHANNEL_4;
-		break;
-	case 6:
-		/* RR, RL, FC, LFE, FR and FL speakers */
-		channel_allocation  = 0x0B;
-		chan = MSM_HDMI_AUDIO_CHANNEL_6;
-		break;
-	case 8:
-		/* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
-		channel_allocation  = 0x1F;
-		chan = MSM_HDMI_AUDIO_CHANNEL_8;
-		break;
-	default:
-		return -EINVAL;
-	}
-
 	switch (params->sample_rate) {
 	case 32000:
 		rate = HDMI_SAMPLE_RATE_32KHZ;
@@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
 		return -EINVAL;
 	}
 
-	msm_hdmi_audio_set_sample_rate(hdmi, rate);
-	msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
-			      level_shift, down_mix);
+	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
+								      &params->cea);
+	if (ret)
+		return ret;
+
+	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
 
 	return 0;
 }
@@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
 {
 	struct hdmi *hdmi = dev_get_drvdata(dev);
 
-	msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
+	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
+	msm_hdmi_audio_disable(hdmi);
 }
 
 static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index a62d2aedfbb7239d37c826c4f96762f100a2be4a..53b52351d0eddf4a5c87a5290016bb53ed4d29f7 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -24,8 +24,8 @@ struct hdmi_platform_config;
 
 struct hdmi_audio {
 	bool enabled;
-	struct hdmi_audio_infoframe infoframe;
 	int rate;
+	int channels;
 };
 
 struct hdmi_hdcp_ctrl;
@@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
 /*
  * audio:
  */
-/* Supported HDMI Audio channels and rates */
-#define	MSM_HDMI_AUDIO_CHANNEL_2	0
-#define	MSM_HDMI_AUDIO_CHANNEL_4	1
-#define	MSM_HDMI_AUDIO_CHANNEL_6	2
-#define	MSM_HDMI_AUDIO_CHANNEL_8	3
-
 #define	HDMI_SAMPLE_RATE_32KHZ		0
 #define	HDMI_SAMPLE_RATE_44_1KHZ	1
 #define	HDMI_SAMPLE_RATE_48KHZ		2
@@ -221,12 +215,8 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
 #define	HDMI_SAMPLE_RATE_176_4KHZ	5
 #define	HDMI_SAMPLE_RATE_192KHZ		6
 
-int msm_hdmi_audio_update(struct hdmi *hdmi);
-int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
-	uint32_t num_of_channels, uint32_t channel_allocation,
-	uint32_t level_shift, bool down_mix);
-void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
-
+int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
+int msm_hdmi_audio_disable(struct hdmi *hdmi);
 
 /*
  * hdmi bridge:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..924654bfb48cf17feadea1c0661ee6ee4e1b4589 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
@@ -7,9 +7,6 @@
 #include <linux/hdmi.h>
 #include "hdmi.h"
 
-/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
-static int nchannels[] = { 2, 4, 6, 8 };
-
 /* Supported HDMI Audio sample rates */
 #define MSM_HDMI_SAMPLE_RATE_32KHZ		0
 #define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1
@@ -71,19 +68,20 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
 	return NULL;
 }
 
-int msm_hdmi_audio_update(struct hdmi *hdmi)
+static int msm_hdmi_audio_update(struct hdmi *hdmi)
 {
 	struct hdmi_audio *audio = &hdmi->audio;
-	struct hdmi_audio_infoframe *info = &audio->infoframe;
 	const struct hdmi_msm_audio_arcs *arcs = NULL;
 	bool enabled = audio->enabled;
 	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
-	uint32_t infofrm_ctrl, audio_config;
+	uint32_t audio_config;
+
+	if (!hdmi->connector->display_info.is_hdmi)
+		return -EINVAL;
+
+	DBG("audio: enabled=%d, channels=%d, rate=%d",
+	    audio->enabled, audio->channels, audio->rate);
 
-	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
-		"level_shift_value=%d, downmix_inhibit=%d, rate=%d",
-		audio->enabled, info->channels,  info->channel_allocation,
-		info->level_shift_value, info->downmix_inhibit, audio->rate);
 	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
 
 	if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
@@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
 	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
 	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
 	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
-	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
 	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
 
 	/* Clear N/CTS selection bits */
@@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
 	if (enabled) {
 		uint32_t n, cts, multiplier;
 		enum hdmi_acr_cts select;
-		uint8_t buf[14];
 
 		n   = arcs->lut[audio->rate].n;
 		cts = arcs->lut[audio->rate].cts;
@@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
 				HDMI_ACR_1_N(n));
 
 		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
-				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
+				COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
 				HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
 
 		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
 		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
 
-		/* configure infoframe: */
-		hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
-		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
-				(buf[3] <<  0) | (buf[4] <<  8) |
-				(buf[5] << 16) | (buf[6] << 24));
-		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
-				(buf[7] <<  0) | (buf[8] << 8));
-
 		hdmi_write(hdmi, REG_HDMI_GC, 0);
 
 		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
@@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
 
 		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
 
-		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
-		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
-		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
-		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
-
 		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
 		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
 		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
@@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
 		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
 		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
 		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
-		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
-		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
-		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
-		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
 		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
 	}
 
 	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
 	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
 	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
-	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
 
 	hdmi_write(hdmi, REG_HDMI_AUD_INT,
 			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
@@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
 	return 0;
 }
 
-int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
-	uint32_t num_of_channels, uint32_t channel_allocation,
-	uint32_t level_shift, bool down_mix)
+int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
 {
-	struct hdmi_audio *audio;
-
 	if (!hdmi)
 		return -ENXIO;
 
-	audio = &hdmi->audio;
-
-	if (num_of_channels >= ARRAY_SIZE(nchannels))
+	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
 		return -EINVAL;
 
-	audio->enabled = enabled;
-	audio->infoframe.channels = nchannels[num_of_channels];
-	audio->infoframe.channel_allocation = channel_allocation;
-	audio->infoframe.level_shift_value = level_shift;
-	audio->infoframe.downmix_inhibit = down_mix;
+	hdmi->audio.rate = rate;
+	hdmi->audio.channels = channels;
+	hdmi->audio.enabled = true;
 
 	return msm_hdmi_audio_update(hdmi);
 }
 
-void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
+int msm_hdmi_audio_disable(struct hdmi *hdmi)
 {
-	struct hdmi_audio *audio;
-
 	if (!hdmi)
-		return;
-
-	audio = &hdmi->audio;
+		return -ENXIO;
 
-	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
-		return;
+	hdmi->audio.rate = 0;
+	hdmi->audio.channels = 2;
+	hdmi->audio.enabled = false;
 
-	audio->rate = rate;
-	msm_hdmi_audio_update(hdmi);
+	return msm_hdmi_audio_update(hdmi);
 }
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index d5ab1f74c0e6f47dc59872c016104e9a84d85e9e..168b4104e705e8217f5d7ca5f902d7557c55ae24 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -7,6 +7,8 @@
 #include <linux/delay.h>
 #include <drm/drm_bridge_connector.h>
 #include <drm/drm_edid.h>
+#include <drm/display/drm_hdmi_helper.h>
+#include <drm/display/drm_hdmi_state_helper.h>
 
 #include "msm_kms.h"
 #include "hdmi.h"
@@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge)
 
 #define AVI_IFRAME_LINE_NUMBER 1
 
-static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
+static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
+					 const u8 *buffer, size_t len)
 {
-	struct drm_crtc *crtc = hdmi->encoder->crtc;
-	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-	union hdmi_infoframe frame;
-	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
+	u32 buf[4] = {};
 	u32 val;
-	int len;
+	int i;
 
-	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-						 hdmi->connector, mode);
-
-	len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
-	if (len < 0) {
+	if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
 		DRM_DEV_ERROR(&hdmi->pdev->dev,
 			"failed to configure avi infoframe\n");
-		return;
+		return -EINVAL;
 	}
 
 	/*
@@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
 	 * written to the LSB byte of AVI_INFO0 and the version is written to
 	 * the third byte from the LSB of AVI_INFO3
 	 */
-	hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
+	memcpy(buf, &buffer[3], len - 3);
+
+	buf[3] |= buffer[1] << 24;
+
+	for (i = 0; i < ARRAY_SIZE(buf); i++)
+		hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
+
+	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
+	val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
+		HDMI_INFOFRAME_CTRL0_AVI_CONT;
+	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
+
+	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
+	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
+	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
+	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
+
+	return 0;
+}
+
+static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
+					   const u8 *buffer, size_t len)
+{
+	u32 val;
+
+	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
+		DRM_DEV_ERROR(&hdmi->pdev->dev,
+			"failed to configure audio infoframe\n");
+		return -EINVAL;
+	}
+
+	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
 		   buffer[3] |
 		   buffer[4] << 8 |
 		   buffer[5] << 16 |
 		   buffer[6] << 24);
 
-	hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
+	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
 		   buffer[7] |
 		   buffer[8] << 8 |
 		   buffer[9] << 16 |
 		   buffer[10] << 24);
 
-	hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
-		   buffer[11] |
-		   buffer[12] << 8 |
-		   buffer[13] << 16 |
-		   buffer[14] << 24);
+	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
+	val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
+		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
+		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
+		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
+	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
+
+	return 0;
+}
+
+static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
+					   enum hdmi_infoframe_type type)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	u32 val;
+
+	switch (type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
+		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
+			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
+		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
 
-	hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
-		   buffer[15] |
-		   buffer[16] << 8 |
-		   buffer[1] << 24);
+		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
+		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
+		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
 
-	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
-		   HDMI_INFOFRAME_CTRL0_AVI_SEND |
-		   HDMI_INFOFRAME_CTRL0_AVI_CONT);
+		break;
 
-	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
-	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
-	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
-	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
+		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
+			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
+			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
+			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
+		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
+
+		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
+		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
+		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
+
+		break;
+
+	default:
+		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
+	}
+
+	return 0;
+}
+
+static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
+					   enum hdmi_infoframe_type type,
+					   const u8 *buffer, size_t len)
+{
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+
+	msm_hdmi_bridge_clear_infoframe(bridge, type);
+
+	switch (type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
+	default:
+		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
+		return 0;
+	}
 }
 
 static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
@@ -146,16 +223,16 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
 	conn_state = drm_atomic_get_new_connector_state(state, connector);
 	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
 
+	hdmi->pixclock = conn_state->hdmi.tmds_char_rate;
+
 	if (!hdmi->power_on) {
 		msm_hdmi_phy_resource_enable(phy);
 		msm_hdmi_power_on(bridge);
 		hdmi->power_on = true;
-		if (hdmi->hdmi_mode) {
-			msm_hdmi_config_avi_infoframe(hdmi);
-			msm_hdmi_audio_update(hdmi);
-		}
 	}
 
+	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+
 	msm_hdmi_phy_powerup(phy, hdmi->pixclock);
 
 	msm_hdmi_set_mode(hdmi, true);
@@ -184,8 +261,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
 	if (hdmi->power_on) {
 		power_off(bridge);
 		hdmi->power_on = false;
-		if (hdmi->hdmi_mode)
-			msm_hdmi_audio_update(hdmi);
 		msm_hdmi_phy_resource_disable(phy);
 	}
 }
@@ -196,8 +271,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
 	int hstart, hend, vstart, vend;
 	uint32_t frame_ctrl;
 
-	hdmi->pixclock = mode->clock * 1000;
-
 	hstart = mode->htotal - mode->hsync_start;
 	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
 
@@ -241,9 +314,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
 		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
 	DBG("frame_ctrl=%08x", frame_ctrl);
 	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
-
-	if (hdmi->hdmi_mode)
-		msm_hdmi_audio_update(hdmi);
 }
 
 static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridge,
@@ -275,18 +345,16 @@ static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridg
 	return drm_edid;
 }
 
-static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
-		const struct drm_display_info *info,
-		const struct drm_display_mode *mode)
+static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
+								 const struct drm_display_mode *mode,
+								 unsigned long long tmds_rate)
 {
 	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
 	struct hdmi *hdmi = hdmi_bridge->hdmi;
 	const struct hdmi_platform_config *config = hdmi->config;
 	struct msm_drm_private *priv = bridge->dev->dev_private;
 	struct msm_kms *kms = priv->kms;
-	long actual, requested;
-
-	requested = 1000 * mode->clock;
+	long actual;
 
 	/* for mdp5/apq8074, we manage our own pixel clk (as opposed to
 	 * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
@@ -294,15 +362,16 @@ static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge
 	 */
 	if (kms->funcs->round_pixclk)
 		actual = kms->funcs->round_pixclk(kms,
-			requested, hdmi_bridge->hdmi->encoder);
+						  tmds_rate,
+						  hdmi_bridge->hdmi->encoder);
 	else if (config->pwr_clk_cnt > 0)
-		actual = clk_round_rate(hdmi->pwr_clks[0], requested);
+		actual = clk_round_rate(hdmi->pwr_clks[0], tmds_rate);
 	else
-		actual = requested;
+		actual = tmds_rate;
 
-	DBG("requested=%ld, actual=%ld", requested, actual);
+	DBG("requested=%lld, actual=%ld", tmds_rate, actual);
 
-	if (actual != requested)
+	if (actual != tmds_rate)
 		return MODE_CLOCK_RANGE;
 
 	return 0;
@@ -314,9 +383,11 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
 	.atomic_reset = drm_atomic_helper_bridge_reset,
 	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
 	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
-	.mode_valid = msm_hdmi_bridge_mode_valid,
 	.edid_read = msm_hdmi_bridge_edid_read,
 	.detect = msm_hdmi_bridge_detect,
+	.hdmi_tmds_char_rate_valid = msm_hdmi_bridge_tmds_char_rate_valid,
+	.hdmi_clear_infoframe = msm_hdmi_bridge_clear_infoframe,
+	.hdmi_write_infoframe = msm_hdmi_bridge_write_infoframe,
 };
 
 static void
@@ -348,8 +419,11 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi)
 	bridge->funcs = &msm_hdmi_bridge_funcs;
 	bridge->ddc = hdmi->i2c;
 	bridge->type = DRM_MODE_CONNECTOR_HDMIA;
+	bridge->vendor = "Qualcomm";
+	bridge->product = "Snapdragon";
 	bridge->ops = DRM_BRIDGE_OP_HPD |
 		DRM_BRIDGE_OP_DETECT |
+		DRM_BRIDGE_OP_HDMI |
 		DRM_BRIDGE_OP_EDID;
 
 	ret = devm_drm_bridge_add(hdmi->dev->dev, bridge);

-- 
2.39.5


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

* [PATCH v6 4/7] drm/msm/hdmi: get rid of hdmi_mode
  2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
                   ` (2 preceding siblings ...)
  2025-01-24 21:47 ` [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework Dmitry Baryshkov
@ 2025-01-24 21:47 ` Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 5/7] drm/msm/hdmi: update HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE definition Dmitry Baryshkov
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

Use connector->display_info.is_hdmi instead of manually using
drm_detect_hdmi_monitor().

Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/hdmi/hdmi.c        |  2 +-
 drivers/gpu/drm/msm/hdmi/hdmi.h        |  2 --
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 11 -----------
 3 files changed, 1 insertion(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index b14205cb9e977edd0d849e0eafe9b69c0da594bd..6b77e0fb8d5ec218dfbf58215e2e12ad1dfb1b85 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -25,7 +25,7 @@ void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
 	spin_lock_irqsave(&hdmi->reg_lock, flags);
 	if (power_on) {
 		ctrl |= HDMI_CTRL_ENABLE;
-		if (!hdmi->hdmi_mode) {
+		if (!hdmi->connector->display_info.is_hdmi) {
 			ctrl |= HDMI_CTRL_HDMI;
 			hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
 			ctrl &= ~HDMI_CTRL_HDMI;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 53b52351d0eddf4a5c87a5290016bb53ed4d29f7..ab169b77377097dc22c0c718f65024cb8ad1d317 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -67,8 +67,6 @@ struct hdmi {
 	/* the encoder we are hooked to (outside of hdmi block) */
 	struct drm_encoder *encoder;
 
-	bool hdmi_mode;               /* are we in hdmi mode? */
-
 	int irq;
 	struct workqueue_struct *workq;
 
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 168b4104e705e8217f5d7ca5f902d7557c55ae24..d2b25bcd8eb8f5cf4623e11c87ac5eea6e4b363d 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -331,17 +331,6 @@ static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridg
 
 	hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
 
-	if (drm_edid) {
-		/*
-		 * FIXME: This should use connector->display_info.is_hdmi from a
-		 * path that has read the EDID and called
-		 * drm_edid_connector_update().
-		 */
-		const struct edid *edid = drm_edid_raw(drm_edid);
-
-		hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
-	}
-
 	return drm_edid;
 }
 

-- 
2.39.5


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

* [PATCH v6 5/7] drm/msm/hdmi: update HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE definition
  2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
                   ` (3 preceding siblings ...)
  2025-01-24 21:47 ` [PATCH v6 4/7] drm/msm/hdmi: get rid of hdmi_mode Dmitry Baryshkov
@ 2025-01-24 21:47 ` Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 6/7] drm/msm/hdmi: also send the SPD and HDMI Vendor Specific InfoFrames Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 7/7] drm/msm/hdmi: use DRM HDMI Audio framework Dmitry Baryshkov
  6 siblings, 0 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

The GENERIC0_UPDATE field is a single bit. Redefine it as boolean to
simplify its usage in the driver.

Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/registers/display/hdmi.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/registers/display/hdmi.xml b/drivers/gpu/drm/msm/registers/display/hdmi.xml
index 1cf1b14fbd919e041fd7ac8a0731d554d4468f4f..0ebb96297dae80940dc8a918d26cd58ff2e6f81a 100644
--- a/drivers/gpu/drm/msm/registers/display/hdmi.xml
+++ b/drivers/gpu/drm/msm/registers/display/hdmi.xml
@@ -131,7 +131,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
 		 -->
 		<bitfield name="GENERIC0_SEND" pos="0" type="boolean"/>
 		<bitfield name="GENERIC0_CONT" pos="1" type="boolean"/>
-		<bitfield name="GENERIC0_UPDATE" low="2" high="3" type="uint"/> <!-- ??? -->
+		<bitfield name="GENERIC0_UPDATE" pos="2" type="boolean"/>
 		<bitfield name="GENERIC1_SEND" pos="4" type="boolean"/>
 		<bitfield name="GENERIC1_CONT" pos="5" type="boolean"/>
 		<bitfield name="GENERIC0_LINE" low="16" high="21" type="uint"/>

-- 
2.39.5


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

* [PATCH v6 6/7] drm/msm/hdmi: also send the SPD and HDMI Vendor Specific InfoFrames
  2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
                   ` (4 preceding siblings ...)
  2025-01-24 21:47 ` [PATCH v6 5/7] drm/msm/hdmi: update HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE definition Dmitry Baryshkov
@ 2025-01-24 21:47 ` Dmitry Baryshkov
  2025-01-24 21:47 ` [PATCH v6 7/7] drm/msm/hdmi: use DRM HDMI Audio framework Dmitry Baryshkov
  6 siblings, 0 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

Extend the driver to send SPD and HDMI Vendor Specific InfoFrames.

While the HDMI block has special block to send HVS InfoFrame, use
GENERIC0 block instead. VENSPEC_INFO registers pack frame data in a way
that requires manual repacking in the driver, while GENERIC0 doesn't
have such format requirements. The msm-4.4 kernel uses GENERIC0 to send
HDR InfoFrame which we do not at this point anyway.

Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 93 ++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index d2b25bcd8eb8f5cf4623e11c87ac5eea6e4b363d..c31e1d33593de6480c0c2b7cb322a85e645ff332 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -69,6 +69,8 @@ static void power_off(struct drm_bridge *bridge)
 }
 
 #define AVI_IFRAME_LINE_NUMBER 1
+#define SPD_IFRAME_LINE_NUMBER 1
+#define VENSPEC_IFRAME_LINE_NUMBER 3
 
 static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
 					 const u8 *buffer, size_t len)
@@ -142,6 +144,74 @@ static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
 	return 0;
 }
 
+static int msm_hdmi_config_spd_infoframe(struct hdmi *hdmi,
+					 const u8 *buffer, size_t len)
+{
+	u32 buf[7] = {};
+	u32 val;
+	int i;
+
+	if (len != HDMI_INFOFRAME_SIZE(SPD) || len - 3 > sizeof(buf)) {
+		DRM_DEV_ERROR(&hdmi->pdev->dev,
+			"failed to configure SPD infoframe\n");
+		return -EINVAL;
+	}
+
+	/* checksum gets written together with the body of the frame */
+	hdmi_write(hdmi, REG_HDMI_GENERIC1_HDR,
+		   buffer[0] |
+		   buffer[1] << 8 |
+		   buffer[2] << 16);
+
+	memcpy(buf, &buffer[3], len - 3);
+
+	for (i = 0; i < ARRAY_SIZE(buf); i++)
+		hdmi_write(hdmi, REG_HDMI_GENERIC1(i), buf[i]);
+
+	val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
+	val |= HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
+		 HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
+		 HDMI_GEN_PKT_CTRL_GENERIC1_LINE(SPD_IFRAME_LINE_NUMBER);
+	hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
+
+	return 0;
+}
+
+static int msm_hdmi_config_hdmi_infoframe(struct hdmi *hdmi,
+					  const u8 *buffer, size_t len)
+{
+	u32 buf[7] = {};
+	u32 val;
+	int i;
+
+	if (len < HDMI_INFOFRAME_HEADER_SIZE + HDMI_VENDOR_INFOFRAME_SIZE ||
+	    len - 3 > sizeof(buf)) {
+		DRM_DEV_ERROR(&hdmi->pdev->dev,
+			"failed to configure HDMI infoframe\n");
+		return -EINVAL;
+	}
+
+	/* checksum gets written together with the body of the frame */
+	hdmi_write(hdmi, REG_HDMI_GENERIC0_HDR,
+		   buffer[0] |
+		   buffer[1] << 8 |
+		   buffer[2] << 16);
+
+	memcpy(buf, &buffer[3], len - 3);
+
+	for (i = 0; i < ARRAY_SIZE(buf); i++)
+		hdmi_write(hdmi, REG_HDMI_GENERIC0(i), buf[i]);
+
+	val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
+	val |= HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
+		 HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
+		 HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
+		 HDMI_GEN_PKT_CTRL_GENERIC0_LINE(VENSPEC_IFRAME_LINE_NUMBER);
+	hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
+
+	return 0;
+}
+
 static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
 					   enum hdmi_infoframe_type type)
 {
@@ -176,6 +246,25 @@ static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
 
 		break;
 
+	case HDMI_INFOFRAME_TYPE_SPD:
+		val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
+		val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
+			 HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
+			 HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
+		hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
+
+		break;
+
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
+		val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
+			 HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
+			 HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
+			 HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
+		hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
+
+		break;
+
 	default:
 		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
 	}
@@ -197,6 +286,10 @@ static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
 		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
 	case HDMI_INFOFRAME_TYPE_AUDIO:
 		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return msm_hdmi_config_spd_infoframe(hdmi, buffer, len);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return msm_hdmi_config_hdmi_infoframe(hdmi, buffer, len);
 	default:
 		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
 		return 0;

-- 
2.39.5


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

* [PATCH v6 7/7] drm/msm/hdmi: use DRM HDMI Audio framework
  2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
                   ` (5 preceding siblings ...)
  2025-01-24 21:47 ` [PATCH v6 6/7] drm/msm/hdmi: also send the SPD and HDMI Vendor Specific InfoFrames Dmitry Baryshkov
@ 2025-01-24 21:47 ` Dmitry Baryshkov
  2025-01-27 10:10   ` Maxime Ripard
  6 siblings, 1 reply; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-01-24 21:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel

In order to simplify the driver even further and to remove the
boilerplate code, rewrite the audio interface to use the DRM HDMI Audio
framework.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/hdmi/hdmi.c        | 91 ----------------------------------
 drivers/gpu/drm/msm/hdmi/hdmi.h        | 20 ++++----
 drivers/gpu/drm/msm/hdmi/hdmi_audio.c  | 75 +++++++++++++++++++++++-----
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c |  5 ++
 4 files changed, 76 insertions(+), 115 deletions(-)

diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 6b77e0fb8d5ec218dfbf58215e2e12ad1dfb1b85..248541ff449204c72cd444458dadb9ae4a0a53d1 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -14,7 +14,6 @@
 #include <drm/drm_of.h>
 #include <drm/display/drm_hdmi_state_helper.h>
 
-#include <sound/hdmi-codec.h>
 #include "hdmi.h"
 
 void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
@@ -245,87 +244,6 @@ static const struct hdmi_platform_config hdmi_tx_8974_config = {
 		.hpd_freq      = hpd_clk_freq_8x74,
 };
 
-/*
- * HDMI audio codec callbacks
- */
-static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
-				    struct hdmi_codec_daifmt *daifmt,
-				    struct hdmi_codec_params *params)
-{
-	struct hdmi *hdmi = dev_get_drvdata(dev);
-	unsigned int rate;
-	int ret;
-
-	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
-		 params->sample_width, params->cea.channels);
-
-	switch (params->sample_rate) {
-	case 32000:
-		rate = HDMI_SAMPLE_RATE_32KHZ;
-		break;
-	case 44100:
-		rate = HDMI_SAMPLE_RATE_44_1KHZ;
-		break;
-	case 48000:
-		rate = HDMI_SAMPLE_RATE_48KHZ;
-		break;
-	case 88200:
-		rate = HDMI_SAMPLE_RATE_88_2KHZ;
-		break;
-	case 96000:
-		rate = HDMI_SAMPLE_RATE_96KHZ;
-		break;
-	case 176400:
-		rate = HDMI_SAMPLE_RATE_176_4KHZ;
-		break;
-	case 192000:
-		rate = HDMI_SAMPLE_RATE_192KHZ;
-		break;
-	default:
-		DRM_DEV_ERROR(dev, "rate[%d] not supported!\n",
-			params->sample_rate);
-		return -EINVAL;
-	}
-
-	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
-								      &params->cea);
-	if (ret)
-		return ret;
-
-	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
-
-	return 0;
-}
-
-static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
-{
-	struct hdmi *hdmi = dev_get_drvdata(dev);
-
-	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
-	msm_hdmi_audio_disable(hdmi);
-}
-
-static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
-	.hw_params = msm_hdmi_audio_hw_params,
-	.audio_shutdown = msm_hdmi_audio_shutdown,
-};
-
-static struct hdmi_codec_pdata codec_data = {
-	.ops = &msm_hdmi_audio_codec_ops,
-	.max_i2s_channels = 8,
-	.i2s = 1,
-};
-
-static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev)
-{
-	hdmi->audio_pdev = platform_device_register_data(dev,
-							 HDMI_CODEC_DRV_NAME,
-							 PLATFORM_DEVID_AUTO,
-							 &codec_data,
-							 sizeof(codec_data));
-	return PTR_ERR_OR_ZERO(hdmi->audio_pdev);
-}
-
 static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
 {
 	struct msm_drm_private *priv = dev_get_drvdata(master);
@@ -337,12 +255,6 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
 		return err;
 	priv->hdmi = hdmi;
 
-	err = msm_hdmi_register_audio_driver(hdmi, dev);
-	if (err) {
-		DRM_ERROR("Failed to attach an audio codec %d\n", err);
-		hdmi->audio_pdev = NULL;
-	}
-
 	return 0;
 }
 
@@ -352,9 +264,6 @@ static void msm_hdmi_unbind(struct device *dev, struct device *master,
 	struct msm_drm_private *priv = dev_get_drvdata(master);
 
 	if (priv->hdmi) {
-		if (priv->hdmi->audio_pdev)
-			platform_device_unregister(priv->hdmi->audio_pdev);
-
 		if (priv->hdmi->bridge)
 			msm_hdmi_hpd_disable(priv->hdmi);
 
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index ab169b77377097dc22c0c718f65024cb8ad1d317..88a41be7c6fc2f878a1c372a0c75b3277f24f893 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -33,7 +33,6 @@ struct hdmi_hdcp_ctrl;
 struct hdmi {
 	struct drm_device *dev;
 	struct platform_device *pdev;
-	struct platform_device *audio_pdev;
 
 	const struct hdmi_platform_config *config;
 
@@ -205,16 +204,15 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
 /*
  * audio:
  */
-#define	HDMI_SAMPLE_RATE_32KHZ		0
-#define	HDMI_SAMPLE_RATE_44_1KHZ	1
-#define	HDMI_SAMPLE_RATE_48KHZ		2
-#define	HDMI_SAMPLE_RATE_88_2KHZ	3
-#define	HDMI_SAMPLE_RATE_96KHZ		4
-#define	HDMI_SAMPLE_RATE_176_4KHZ	5
-#define	HDMI_SAMPLE_RATE_192KHZ		6
-
-int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
-int msm_hdmi_audio_disable(struct hdmi *hdmi);
+struct hdmi_codec_daifmt;
+struct hdmi_codec_params;
+
+int msm_hdmi_bridge_audio_prepare(struct drm_connector *connector,
+				  struct drm_bridge *bridge,
+				  struct hdmi_codec_daifmt *daifmt,
+				  struct hdmi_codec_params *params);
+void msm_hdmi_bridge_audio_shutdown(struct drm_connector *connector,
+				    struct drm_bridge *bridge);
 
 /*
  * hdmi bridge:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
index 924654bfb48cf17feadea1c0661ee6ee4e1b4589..9c5b5310bfeb54902d7d0687909afc79e320f560 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
@@ -4,7 +4,12 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <drm/display/drm_hdmi_state_helper.h>
+
 #include <linux/hdmi.h>
+
+#include <sound/hdmi-codec.h>
+
 #include "hdmi.h"
 
 /* Supported HDMI Audio sample rates */
@@ -68,7 +73,8 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
 	return NULL;
 }
 
-static int msm_hdmi_audio_update(struct hdmi *hdmi)
+static int msm_hdmi_audio_update(struct hdmi *hdmi,
+				 struct drm_connector *connector)
 {
 	struct hdmi_audio *audio = &hdmi->audio;
 	const struct hdmi_msm_audio_arcs *arcs = NULL;
@@ -76,7 +82,7 @@ static int msm_hdmi_audio_update(struct hdmi *hdmi)
 	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
 	uint32_t audio_config;
 
-	if (!hdmi->connector->display_info.is_hdmi)
+	if (!connector->display_info.is_hdmi)
 		return -EINVAL;
 
 	DBG("audio: enabled=%d, channels=%d, rate=%d",
@@ -192,29 +198,72 @@ static int msm_hdmi_audio_update(struct hdmi *hdmi)
 	return 0;
 }
 
-int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
+int msm_hdmi_bridge_audio_prepare(struct drm_connector *connector,
+				  struct drm_bridge *bridge,
+				  struct hdmi_codec_daifmt *daifmt,
+				  struct hdmi_codec_params *params)
 {
-	if (!hdmi)
-		return -ENXIO;
-
-	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+	unsigned int rate;
+	int ret;
+
+	drm_dbg_driver(bridge->dev, "%u Hz, %d bit, %d channels\n",
+		       params->sample_rate,
+		       params->sample_width,
+		       params->cea.channels);
+
+	switch (params->sample_rate) {
+	case 32000:
+		rate = MSM_HDMI_SAMPLE_RATE_32KHZ;
+		break;
+	case 44100:
+		rate = MSM_HDMI_SAMPLE_RATE_44_1KHZ;
+		break;
+	case 48000:
+		rate = MSM_HDMI_SAMPLE_RATE_48KHZ;
+		break;
+	case 88200:
+		rate = MSM_HDMI_SAMPLE_RATE_88_2KHZ;
+		break;
+	case 96000:
+		rate = MSM_HDMI_SAMPLE_RATE_96KHZ;
+		break;
+	case 176400:
+		rate = MSM_HDMI_SAMPLE_RATE_176_4KHZ;
+		break;
+	case 192000:
+		rate = MSM_HDMI_SAMPLE_RATE_192KHZ;
+		break;
+	default:
+		drm_err(bridge->dev, "rate[%d] not supported!\n",
+			params->sample_rate);
 		return -EINVAL;
+	}
+
+	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
+								      &params->cea);
+	if (ret)
+		return ret;
 
 	hdmi->audio.rate = rate;
-	hdmi->audio.channels = channels;
+	hdmi->audio.channels = params->cea.channels;
 	hdmi->audio.enabled = true;
 
-	return msm_hdmi_audio_update(hdmi);
+	return msm_hdmi_audio_update(hdmi, connector);
 }
 
-int msm_hdmi_audio_disable(struct hdmi *hdmi)
+void msm_hdmi_bridge_audio_shutdown(struct drm_connector *connector,
+				    struct drm_bridge *bridge)
 {
-	if (!hdmi)
-		return -ENXIO;
+	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+	struct hdmi *hdmi = hdmi_bridge->hdmi;
+
+	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
 
 	hdmi->audio.rate = 0;
 	hdmi->audio.channels = 2;
 	hdmi->audio.enabled = false;
 
-	return msm_hdmi_audio_update(hdmi);
+	msm_hdmi_audio_update(hdmi, connector);
 }
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index c31e1d33593de6480c0c2b7cb322a85e645ff332..8a1bbcf578b0749480799d9e5b2baf3778322edc 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -470,6 +470,8 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
 	.hdmi_tmds_char_rate_valid = msm_hdmi_bridge_tmds_char_rate_valid,
 	.hdmi_clear_infoframe = msm_hdmi_bridge_clear_infoframe,
 	.hdmi_write_infoframe = msm_hdmi_bridge_write_infoframe,
+	.hdmi_audio_prepare = msm_hdmi_bridge_audio_prepare,
+	.hdmi_audio_shutdown = msm_hdmi_bridge_audio_shutdown,
 };
 
 static void
@@ -507,6 +509,9 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi)
 		DRM_BRIDGE_OP_DETECT |
 		DRM_BRIDGE_OP_HDMI |
 		DRM_BRIDGE_OP_EDID;
+	bridge->hdmi_audio_max_i2s_playback_channels = 8;
+	bridge->hdmi_audio_dev = &hdmi->pdev->dev;
+	bridge->hdmi_audio_dai_port = -1;
 
 	ret = devm_drm_bridge_add(hdmi->dev->dev, bridge);
 	if (ret)

-- 
2.39.5


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

* Re: [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-01-24 21:47 ` [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable Dmitry Baryshkov
@ 2025-01-26 16:41   ` Maxime Ripard
  2025-02-03 19:34   ` Abhinav Kumar
  1 sibling, 0 replies; 22+ messages in thread
From: Maxime Ripard @ 2025-01-26 16:41 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter,
	dri-devel, linux-arm-msm, freedreno, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 487 bytes --]

On Fri, Jan 24, 2025 at 11:47:42PM +0200, Dmitry Baryshkov wrote:
> The mode_set callback is deprecated, it doesn't get the
> drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
> that HDMI timings should be programmed after setting up HDMI PHY and
> PLL. Rework the code to program HDMI timings at the end of
> atomic_pre_enable().
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

Reviewed-by: Maxime Ripard <mripard@kernel.org>
Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

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

* Re: [PATCH v6 7/7] drm/msm/hdmi: use DRM HDMI Audio framework
  2025-01-24 21:47 ` [PATCH v6 7/7] drm/msm/hdmi: use DRM HDMI Audio framework Dmitry Baryshkov
@ 2025-01-27 10:10   ` Maxime Ripard
  0 siblings, 0 replies; 22+ messages in thread
From: Maxime Ripard @ 2025-01-27 10:10 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst,
	Thomas Zimmermann, David Airlie, Rob Clark, Abhinav Kumar,
	Sean Paul, Marijn Suijten, Simona Vetter, Simona Vetter,
	dri-devel, linux-arm-msm, freedreno, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 352 bytes --]

On Fri, Jan 24, 2025 at 11:47:47PM +0200, Dmitry Baryshkov wrote:
> In order to simplify the driver even further and to remove the
> boilerplate code, rewrite the audio interface to use the DRM HDMI Audio
> framework.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

Reviewed-by: Maxime Ripard <mripard@kernel.org>

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

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

* Re: [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-01-24 21:47 ` [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable Dmitry Baryshkov
  2025-01-26 16:41   ` Maxime Ripard
@ 2025-02-03 19:34   ` Abhinav Kumar
  2025-02-04  0:59     ` Dmitry Baryshkov
  1 sibling, 1 reply; 22+ messages in thread
From: Abhinav Kumar @ 2025-02-03 19:34 UTC (permalink / raw)
  To: Dmitry Baryshkov, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Rob Clark, Sean Paul, Marijn Suijten, Simona Vetter,
	Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel



On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> The mode_set callback is deprecated, it doesn't get the
> drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
> that HDMI timings should be programmed after setting up HDMI PHY and
> PLL. Rework the code to program HDMI timings at the end of
> atomic_pre_enable().
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>   drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 23 +++++++++++++++--------
>   1 file changed, 15 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index d839c71091dcdc3b020fcbba8d698d58ee7fc749..d5ab1f74c0e6f47dc59872c016104e9a84d85e9e 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -126,15 +126,26 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>   	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>   }
>   
> +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> +					       const struct drm_display_mode *mode);
>   static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>   					      struct drm_bridge_state *old_bridge_state)
>   {
> +	struct drm_atomic_state *state = old_bridge_state->base.state;
>   	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>   	struct hdmi *hdmi = hdmi_bridge->hdmi;
>   	struct hdmi_phy *phy = hdmi->phy;
> +	struct drm_encoder *encoder = bridge->encoder;
> +	struct drm_connector *connector;
> +	struct drm_connector_state *conn_state;
> +	struct drm_crtc_state *crtc_state;
>   
>   	DBG("power up");
>   
> +	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> +
>   	if (!hdmi->power_on) {
>   		msm_hdmi_phy_resource_enable(phy);
>   		msm_hdmi_power_on(bridge);
> @@ -151,6 +162,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>   
>   	if (hdmi->hdcp_ctrl)
>   		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
> +
> +	msm_hdmi_bridge_atomic_set_timings(hdmi, &crtc_state->adjusted_mode);
>   }
>   

This addresses my comment about setting up the HDMI timing registers 
before setting up the timing engine registers.

But prior to this change, mode_set was doing the same thing as 
msm_hdmi_bridge_atomic_set_timings() which means 
msm_hdmi_bridge_atomic_set_timings() should be called at the beginning 
of pre_enable()?

The controller is enabled in msm_hdmi_set_mode(). So this should be done 
before that.

>   static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> @@ -177,17 +190,12 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
>   	}
>   }
>   
> -static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge,
> -		 const struct drm_display_mode *mode,
> -		 const struct drm_display_mode *adjusted_mode)
> +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> +					       const struct drm_display_mode *mode)
>   {
> -	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> -	struct hdmi *hdmi = hdmi_bridge->hdmi;
>   	int hstart, hend, vstart, vend;
>   	uint32_t frame_ctrl;
>   
> -	mode = adjusted_mode;
> -
>   	hdmi->pixclock = mode->clock * 1000;
>   
>   	hstart = mode->htotal - mode->hsync_start;
> @@ -306,7 +314,6 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
>   	.atomic_reset = drm_atomic_helper_bridge_reset,
>   	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
>   	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
> -	.mode_set = msm_hdmi_bridge_mode_set,
>   	.mode_valid = msm_hdmi_bridge_mode_valid,
>   	.edid_read = msm_hdmi_bridge_edid_read,
>   	.detect = msm_hdmi_bridge_detect,
> 

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

* Re: [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework
  2025-01-24 21:47 ` [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework Dmitry Baryshkov
@ 2025-02-04  0:25   ` Abhinav Kumar
  2025-02-04  1:30     ` Dmitry Baryshkov
  0 siblings, 1 reply; 22+ messages in thread
From: Abhinav Kumar @ 2025-02-04  0:25 UTC (permalink / raw)
  To: Dmitry Baryshkov, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Rob Clark, Sean Paul, Marijn Suijten, Simona Vetter,
	Simona Vetter
  Cc: dri-devel, linux-arm-msm, freedreno, linux-kernel



On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> Setup the HDMI connector on the MSM HDMI outputs. Make use of
> atomic_check hook and of the provided Infoframe infrastructure.
> 

By atomic_check are you referring to the 
msm_hdmi_bridge_tmds_char_rate_valid()?

Also please confirm if HDMI audio was re-tested with these changes.

> Acked-by: Maxime Ripard <mripard@kernel.org>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>   drivers/gpu/drm/msm/Kconfig            |   2 +
>   drivers/gpu/drm/msm/hdmi/hdmi.c        |  45 ++-------
>   drivers/gpu/drm/msm/hdmi/hdmi.h        |  16 +--
>   drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  74 ++++----------
>   drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 180 +++++++++++++++++++++++----------
>   5 files changed, 162 insertions(+), 155 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
> index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce9039d6f26f290d0 100644
> --- a/drivers/gpu/drm/msm/Kconfig
> +++ b/drivers/gpu/drm/msm/Kconfig
> @@ -170,6 +170,8 @@ config DRM_MSM_HDMI
>   	bool "Enable HDMI support in MSM DRM driver"
>   	depends on DRM_MSM
>   	default y
> +	select DRM_DISPLAY_HDMI_HELPER
> +	select DRM_DISPLAY_HDMI_STATE_HELPER
>   	help
>   	  Compile in support for the HDMI output MSM DRM driver. It can
>   	  be a primary or a secondary display on device. Note that this is used
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe9b69c0da594bd 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> @@ -12,6 +12,7 @@
>   
>   #include <drm/drm_bridge_connector.h>
>   #include <drm/drm_of.h>
> +#include <drm/display/drm_hdmi_state_helper.h>
>   
>   #include <sound/hdmi-codec.h>
>   #include "hdmi.h"
> @@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
>   	hdmi->dev = dev;
>   	hdmi->encoder = encoder;
>   
> -	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
> -
>   	ret = msm_hdmi_bridge_init(hdmi);
>   	if (ret) {
>   		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
> @@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
>   				    struct hdmi_codec_params *params)
>   {
>   	struct hdmi *hdmi = dev_get_drvdata(dev);
> -	unsigned int chan;
> -	unsigned int channel_allocation = 0;
>   	unsigned int rate;
> -	unsigned int level_shift  = 0; /* 0dB */
> -	bool down_mix = false;
> +	int ret;
>   
>   	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
>   		 params->sample_width, params->cea.channels);
>   
> -	switch (params->cea.channels) {
> -	case 2:
> -		/* FR and FL speakers */
> -		channel_allocation  = 0;
> -		chan = MSM_HDMI_AUDIO_CHANNEL_2;
> -		break;
> -	case 4:
> -		/* FC, LFE, FR and FL speakers */
> -		channel_allocation  = 0x3;
> -		chan = MSM_HDMI_AUDIO_CHANNEL_4;
> -		break;
> -	case 6:
> -		/* RR, RL, FC, LFE, FR and FL speakers */
> -		channel_allocation  = 0x0B;
> -		chan = MSM_HDMI_AUDIO_CHANNEL_6;
> -		break;
> -	case 8:
> -		/* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
> -		channel_allocation  = 0x1F;
> -		chan = MSM_HDMI_AUDIO_CHANNEL_8;
> -		break;
> -	default:
> -		return -EINVAL;
> -	}

This mapping table was doing two things:

1) drop the conversion of channels to an index to nchannels[] and use 
the channels directly. This part is fine but could have been a separate 
change by itself to show the redundancy.

2) drop the mapping table of channels to channel_allocation.
I am not fully sure of this. Was this done because 
hdmi_codec_channel_alloc[] table in hdmi-codec does this for us?
hdmi_codec_get_ch_alloc_table_idx() uses channels and the flags to come 
up with the idx into this table. But it seems like current MSM HDMI code 
did not consider the flags. So for example, it seems like for 6 
channels, we could return any of the below based on the flags but MSM 
HDMI always used 0x0B so will the values match?

202 	{ .ca_id = 0x0b, .n_ch = 6,
203 	  .mask = FL | FR | LFE | FC | RL | RR},
204 	/* surround40 */
205 	{ .ca_id = 0x08, .n_ch = 6,
206 	  .mask = FL | FR | RL | RR },
207 	/* surround41 */
208 	{ .ca_id = 0x09, .n_ch = 6,
209 	  .mask = FL | FR | LFE | RL | RR },
210 	/* surround50 */
211 	{ .ca_id = 0x0a, .n_ch = 6,
212 	  .mask = FL | FR | FC | RL | RR },
213 	/* 6.1 */


> -
>   	switch (params->sample_rate) {
>   	case 32000:
>   		rate = HDMI_SAMPLE_RATE_32KHZ;
> @@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
>   		return -EINVAL;
>   	}
>   
> -	msm_hdmi_audio_set_sample_rate(hdmi, rate);
> -	msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
> -			      level_shift, down_mix);
> +	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
> +								      &params->cea);
> +	if (ret)
> +		return ret;
> +
> +	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
>   
>   	return 0;
>   }
> @@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
>   {
>   	struct hdmi *hdmi = dev_get_drvdata(dev);
>   
> -	msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
> +	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
> +	msm_hdmi_audio_disable(hdmi);
>   }
>   
>   static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> index a62d2aedfbb7239d37c826c4f96762f100a2be4a..53b52351d0eddf4a5c87a5290016bb53ed4d29f7 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> @@ -24,8 +24,8 @@ struct hdmi_platform_config;
>   
>   struct hdmi_audio {
>   	bool enabled;
> -	struct hdmi_audio_infoframe infoframe;
>   	int rate;
> +	int channels;
>   };
>   
>   struct hdmi_hdcp_ctrl;
> @@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
>   /*
>    * audio:
>    */
> -/* Supported HDMI Audio channels and rates */
> -#define	MSM_HDMI_AUDIO_CHANNEL_2	0
> -#define	MSM_HDMI_AUDIO_CHANNEL_4	1
> -#define	MSM_HDMI_AUDIO_CHANNEL_6	2
> -#define	MSM_HDMI_AUDIO_CHANNEL_8	3
> -
>   #define	HDMI_SAMPLE_RATE_32KHZ		0
>   #define	HDMI_SAMPLE_RATE_44_1KHZ	1
>   #define	HDMI_SAMPLE_RATE_48KHZ		2
> @@ -221,12 +215,8 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
>   #define	HDMI_SAMPLE_RATE_176_4KHZ	5
>   #define	HDMI_SAMPLE_RATE_192KHZ		6
>   
> -int msm_hdmi_audio_update(struct hdmi *hdmi);
> -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> -	uint32_t num_of_channels, uint32_t channel_allocation,
> -	uint32_t level_shift, bool down_mix);
> -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
> -
> +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
> +int msm_hdmi_audio_disable(struct hdmi *hdmi);
>   
>   /*
>    * hdmi bridge:
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..924654bfb48cf17feadea1c0661ee6ee4e1b4589 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> @@ -7,9 +7,6 @@
>   #include <linux/hdmi.h>
>   #include "hdmi.h"
>   
> -/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
> -static int nchannels[] = { 2, 4, 6, 8 };
> -
>   /* Supported HDMI Audio sample rates */
>   #define MSM_HDMI_SAMPLE_RATE_32KHZ		0
>   #define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1
> @@ -71,19 +68,20 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
>   	return NULL;
>   }
>   
> -int msm_hdmi_audio_update(struct hdmi *hdmi)
> +static int msm_hdmi_audio_update(struct hdmi *hdmi)
>   {
>   	struct hdmi_audio *audio = &hdmi->audio;
> -	struct hdmi_audio_infoframe *info = &audio->infoframe;
>   	const struct hdmi_msm_audio_arcs *arcs = NULL;
>   	bool enabled = audio->enabled;
>   	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
> -	uint32_t infofrm_ctrl, audio_config;
> +	uint32_t audio_config;
> +
> +	if (!hdmi->connector->display_info.is_hdmi)
> +		return -EINVAL;
> +
> +	DBG("audio: enabled=%d, channels=%d, rate=%d",
> +	    audio->enabled, audio->channels, audio->rate);
>   
> -	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
> -		"level_shift_value=%d, downmix_inhibit=%d, rate=%d",
> -		audio->enabled, info->channels,  info->channel_allocation,
> -		info->level_shift_value, info->downmix_inhibit, audio->rate);
>   	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
>   
>   	if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
> @@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>   	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
>   	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
>   	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
> -	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
>   	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
>   
>   	/* Clear N/CTS selection bits */
> @@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>   	if (enabled) {
>   		uint32_t n, cts, multiplier;
>   		enum hdmi_acr_cts select;
> -		uint8_t buf[14];
>   
>   		n   = arcs->lut[audio->rate].n;
>   		cts = arcs->lut[audio->rate].cts;
> @@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>   				HDMI_ACR_1_N(n));
>   
>   		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
> -				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
> +				COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
>   				HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
>   
>   		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
>   		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
>   
> -		/* configure infoframe: */
> -		hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
> -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
> -				(buf[3] <<  0) | (buf[4] <<  8) |
> -				(buf[5] << 16) | (buf[6] << 24));
> -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
> -				(buf[7] <<  0) | (buf[8] << 8));
> -
>   		hdmi_write(hdmi, REG_HDMI_GC, 0);
>   
>   		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
> @@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>   
>   		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
>   
> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> -
>   		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
>   		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
>   		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
> @@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>   		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
>   		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
>   		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
>   		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
>   	}
>   
>   	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
>   	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
>   	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
>   
>   	hdmi_write(hdmi, REG_HDMI_AUD_INT,
>   			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
> @@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>   	return 0;
>   }
>   
> -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> -	uint32_t num_of_channels, uint32_t channel_allocation,
> -	uint32_t level_shift, bool down_mix)
> +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
>   {
> -	struct hdmi_audio *audio;
> -
>   	if (!hdmi)
>   		return -ENXIO;
>   
> -	audio = &hdmi->audio;
> -
> -	if (num_of_channels >= ARRAY_SIZE(nchannels))
> +	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
>   		return -EINVAL;
>   
> -	audio->enabled = enabled;
> -	audio->infoframe.channels = nchannels[num_of_channels];
> -	audio->infoframe.channel_allocation = channel_allocation;
> -	audio->infoframe.level_shift_value = level_shift;
> -	audio->infoframe.downmix_inhibit = down_mix;
> +	hdmi->audio.rate = rate;
> +	hdmi->audio.channels = channels;
> +	hdmi->audio.enabled = true;
>   
>   	return msm_hdmi_audio_update(hdmi);
>   }
>   
> -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
> +int msm_hdmi_audio_disable(struct hdmi *hdmi)
>   {
> -	struct hdmi_audio *audio;
> -
>   	if (!hdmi)
> -		return;
> -
> -	audio = &hdmi->audio;
> +		return -ENXIO;
>   
> -	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
> -		return;
> +	hdmi->audio.rate = 0;
> +	hdmi->audio.channels = 2;
> +	hdmi->audio.enabled = false;
>   
> -	audio->rate = rate;
> -	msm_hdmi_audio_update(hdmi);
> +	return msm_hdmi_audio_update(hdmi);
>   }
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index d5ab1f74c0e6f47dc59872c016104e9a84d85e9e..168b4104e705e8217f5d7ca5f902d7557c55ae24 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -7,6 +7,8 @@
>   #include <linux/delay.h>
>   #include <drm/drm_bridge_connector.h>
>   #include <drm/drm_edid.h>
> +#include <drm/display/drm_hdmi_helper.h>
> +#include <drm/display/drm_hdmi_state_helper.h>
>   
>   #include "msm_kms.h"
>   #include "hdmi.h"
> @@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge)
>   
>   #define AVI_IFRAME_LINE_NUMBER 1
>   
> -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
> +					 const u8 *buffer, size_t len)
>   {
> -	struct drm_crtc *crtc = hdmi->encoder->crtc;
> -	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> -	union hdmi_infoframe frame;
> -	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
> +	u32 buf[4] = {};
>   	u32 val;
> -	int len;
> +	int i;
>   
> -	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
> -						 hdmi->connector, mode);
> -
> -	len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
> -	if (len < 0) {
> +	if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
>   		DRM_DEV_ERROR(&hdmi->pdev->dev,
>   			"failed to configure avi infoframe\n");
> -		return;
> +		return -EINVAL;
>   	}
>   
>   	/*
> @@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>   	 * written to the LSB byte of AVI_INFO0 and the version is written to
>   	 * the third byte from the LSB of AVI_INFO3
>   	 */
> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
> +	memcpy(buf, &buffer[3], len - 3);
> +
> +	buf[3] |= buffer[1] << 24;
> +
> +	for (i = 0; i < ARRAY_SIZE(buf); i++)
> +		hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
> +
> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> +	val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
> +		HDMI_INFOFRAME_CTRL0_AVI_CONT;
> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> +
> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> +	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> +	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> +
> +	return 0;
> +}
> +
> +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
> +					   const u8 *buffer, size_t len)
> +{
> +	u32 val;
> +
> +	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
> +		DRM_DEV_ERROR(&hdmi->pdev->dev,
> +			"failed to configure audio infoframe\n");
> +		return -EINVAL;
> +	}
> +
> +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
>   		   buffer[3] |
>   		   buffer[4] << 8 |
>   		   buffer[5] << 16 |
>   		   buffer[6] << 24);
>   
> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
> +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
>   		   buffer[7] |
>   		   buffer[8] << 8 |
>   		   buffer[9] << 16 |
>   		   buffer[10] << 24);
>   
> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
> -		   buffer[11] |
> -		   buffer[12] << 8 |
> -		   buffer[13] << 16 |
> -		   buffer[14] << 24);
> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> +	val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> +
> +	return 0;
> +}
> +
> +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
> +					   enum hdmi_infoframe_type type)
> +{
> +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> +	u32 val;
> +
> +	switch (type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> +		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
> +			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>   
> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
> -		   buffer[15] |
> -		   buffer[16] << 8 |
> -		   buffer[1] << 24);
> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> +		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>   
> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
> -		   HDMI_INFOFRAME_CTRL0_AVI_SEND |
> -		   HDMI_INFOFRAME_CTRL0_AVI_CONT);
> +		break;
>   
> -	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> -	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> -	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> +		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> +
> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> +		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> +
> +		break;
> +
> +	default:
> +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> +	}
> +
> +	return 0;
> +}
> +
> +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
> +					   enum hdmi_infoframe_type type,
> +					   const u8 *buffer, size_t len)
> +{
> +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> +
> +	msm_hdmi_bridge_clear_infoframe(bridge, type);
> +
> +	switch (type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
> +	default:
> +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> +		return 0;
> +	}
>   }
>   
>   static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> @@ -146,16 +223,16 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>   	conn_state = drm_atomic_get_new_connector_state(state, connector);
>   	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
>   
> +	hdmi->pixclock = conn_state->hdmi.tmds_char_rate;
> +
>   	if (!hdmi->power_on) {
>   		msm_hdmi_phy_resource_enable(phy);
>   		msm_hdmi_power_on(bridge);
>   		hdmi->power_on = true;
> -		if (hdmi->hdmi_mode) {
> -			msm_hdmi_config_avi_infoframe(hdmi);
> -			msm_hdmi_audio_update(hdmi);
> -		}
>   	}
>   
> +	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
> +
>   	msm_hdmi_phy_powerup(phy, hdmi->pixclock);
>   
>   	msm_hdmi_set_mode(hdmi, true);
> @@ -184,8 +261,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
>   	if (hdmi->power_on) {
>   		power_off(bridge);
>   		hdmi->power_on = false;
> -		if (hdmi->hdmi_mode)
> -			msm_hdmi_audio_update(hdmi);
>   		msm_hdmi_phy_resource_disable(phy);
>   	}
>   }
> @@ -196,8 +271,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>   	int hstart, hend, vstart, vend;
>   	uint32_t frame_ctrl;
>   
> -	hdmi->pixclock = mode->clock * 1000;
> -
>   	hstart = mode->htotal - mode->hsync_start;
>   	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
>   
> @@ -241,9 +314,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>   		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
>   	DBG("frame_ctrl=%08x", frame_ctrl);
>   	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
> -
> -	if (hdmi->hdmi_mode)
> -		msm_hdmi_audio_update(hdmi);
>   }
>   
>   static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridge,
> @@ -275,18 +345,16 @@ static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridg
>   	return drm_edid;
>   }
>   
> -static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
> -		const struct drm_display_info *info,
> -		const struct drm_display_mode *mode)
> +static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
> +								 const struct drm_display_mode *mode,
> +								 unsigned long long tmds_rate)
>   {
>   	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>   	struct hdmi *hdmi = hdmi_bridge->hdmi;
>   	const struct hdmi_platform_config *config = hdmi->config;
>   	struct msm_drm_private *priv = bridge->dev->dev_private;
>   	struct msm_kms *kms = priv->kms;
> -	long actual, requested;
> -
> -	requested = 1000 * mode->clock;
> +	long actual;
>   
>   	/* for mdp5/apq8074, we manage our own pixel clk (as opposed to
>   	 * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
> @@ -294,15 +362,16 @@ static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge
>   	 */
>   	if (kms->funcs->round_pixclk)
>   		actual = kms->funcs->round_pixclk(kms,
> -			requested, hdmi_bridge->hdmi->encoder);
> +						  tmds_rate,
> +						  hdmi_bridge->hdmi->encoder);
>   	else if (config->pwr_clk_cnt > 0)
> -		actual = clk_round_rate(hdmi->pwr_clks[0], requested);
> +		actual = clk_round_rate(hdmi->pwr_clks[0], tmds_rate);
>   	else
> -		actual = requested;
> +		actual = tmds_rate;
>   
> -	DBG("requested=%ld, actual=%ld", requested, actual);
> +	DBG("requested=%lld, actual=%ld", tmds_rate, actual);
>   
> -	if (actual != requested)
> +	if (actual != tmds_rate)
>   		return MODE_CLOCK_RANGE;
>   
>   	return 0;
> @@ -314,9 +383,11 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
>   	.atomic_reset = drm_atomic_helper_bridge_reset,
>   	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
>   	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
> -	.mode_valid = msm_hdmi_bridge_mode_valid,
>   	.edid_read = msm_hdmi_bridge_edid_read,
>   	.detect = msm_hdmi_bridge_detect,
> +	.hdmi_tmds_char_rate_valid = msm_hdmi_bridge_tmds_char_rate_valid,
> +	.hdmi_clear_infoframe = msm_hdmi_bridge_clear_infoframe,
> +	.hdmi_write_infoframe = msm_hdmi_bridge_write_infoframe,
>   };
>   
>   static void
> @@ -348,8 +419,11 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi)
>   	bridge->funcs = &msm_hdmi_bridge_funcs;
>   	bridge->ddc = hdmi->i2c;
>   	bridge->type = DRM_MODE_CONNECTOR_HDMIA;
> +	bridge->vendor = "Qualcomm";
> +	bridge->product = "Snapdragon";
>   	bridge->ops = DRM_BRIDGE_OP_HPD |
>   		DRM_BRIDGE_OP_DETECT |
> +		DRM_BRIDGE_OP_HDMI |
>   		DRM_BRIDGE_OP_EDID;
>   
>   	ret = devm_drm_bridge_add(hdmi->dev->dev, bridge);
> 

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

* Re: [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-02-03 19:34   ` Abhinav Kumar
@ 2025-02-04  0:59     ` Dmitry Baryshkov
  2025-02-06 20:41       ` Abhinav Kumar
  0 siblings, 1 reply; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-02-04  0:59 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel

On Mon, Feb 03, 2025 at 11:34:00AM -0800, Abhinav Kumar wrote:
> 
> 
> On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> > The mode_set callback is deprecated, it doesn't get the
> > drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
> > that HDMI timings should be programmed after setting up HDMI PHY and
> > PLL. Rework the code to program HDMI timings at the end of
> > atomic_pre_enable().
> > 
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> >   drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 23 +++++++++++++++--------
> >   1 file changed, 15 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > index d839c71091dcdc3b020fcbba8d698d58ee7fc749..d5ab1f74c0e6f47dc59872c016104e9a84d85e9e 100644
> > --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > @@ -126,15 +126,26 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> >   	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> >   }
> > +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > +					       const struct drm_display_mode *mode);
> >   static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> >   					      struct drm_bridge_state *old_bridge_state)
> >   {
> > +	struct drm_atomic_state *state = old_bridge_state->base.state;
> >   	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> >   	struct hdmi *hdmi = hdmi_bridge->hdmi;
> >   	struct hdmi_phy *phy = hdmi->phy;
> > +	struct drm_encoder *encoder = bridge->encoder;
> > +	struct drm_connector *connector;
> > +	struct drm_connector_state *conn_state;
> > +	struct drm_crtc_state *crtc_state;
> >   	DBG("power up");
> > +	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
> > +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > +
> >   	if (!hdmi->power_on) {
> >   		msm_hdmi_phy_resource_enable(phy);
> >   		msm_hdmi_power_on(bridge);
> > @@ -151,6 +162,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> >   	if (hdmi->hdcp_ctrl)
> >   		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
> > +
> > +	msm_hdmi_bridge_atomic_set_timings(hdmi, &crtc_state->adjusted_mode);
> >   }
> 
> This addresses my comment about setting up the HDMI timing registers before
> setting up the timing engine registers.
> 
> But prior to this change, mode_set was doing the same thing as
> msm_hdmi_bridge_atomic_set_timings() which means
> msm_hdmi_bridge_atomic_set_timings() should be called at the beginning of
> pre_enable()?
> 
> The controller is enabled in msm_hdmi_set_mode(). So this should be done
> before that.

In [1] you provided the following order:

1) setup HDMI PHY and PLL
2) setup HDMI video path correctly (HDMI timing registers)
3) setup timing generator to match the HDMI video in (2)
4) Enable timing engine

This means htat msm_hdmi_bridge_atomic_set_timings() should come at the
end of msm_hdmi_bridge_atomic_pre_enable(), not in the beginning /
middle of it.

[1] https://lore.kernel.org/dri-devel/8dd4a43e-d83c-1f36-21ff-61e13ff751e7@quicinc.com/


> 
> >   static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> > @@ -177,17 +190,12 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> >   	}
> >   }
> > -static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge,
> > -		 const struct drm_display_mode *mode,
> > -		 const struct drm_display_mode *adjusted_mode)
> > +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > +					       const struct drm_display_mode *mode)
> >   {
> > -	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > -	struct hdmi *hdmi = hdmi_bridge->hdmi;
> >   	int hstart, hend, vstart, vend;
> >   	uint32_t frame_ctrl;
> > -	mode = adjusted_mode;
> > -
> >   	hdmi->pixclock = mode->clock * 1000;
> >   	hstart = mode->htotal - mode->hsync_start;
> > @@ -306,7 +314,6 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
> >   	.atomic_reset = drm_atomic_helper_bridge_reset,
> >   	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
> >   	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
> > -	.mode_set = msm_hdmi_bridge_mode_set,
> >   	.mode_valid = msm_hdmi_bridge_mode_valid,
> >   	.edid_read = msm_hdmi_bridge_edid_read,
> >   	.detect = msm_hdmi_bridge_detect,
> > 

-- 
With best wishes
Dmitry

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

* Re: [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework
  2025-02-04  0:25   ` Abhinav Kumar
@ 2025-02-04  1:30     ` Dmitry Baryshkov
  2025-02-07 21:34       ` Abhinav Kumar
  0 siblings, 1 reply; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-02-04  1:30 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel

On Mon, Feb 03, 2025 at 04:25:59PM -0800, Abhinav Kumar wrote:
> 
> 
> On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> > Setup the HDMI connector on the MSM HDMI outputs. Make use of
> > atomic_check hook and of the provided Infoframe infrastructure.
> > 
> 
> By atomic_check are you referring to the
> msm_hdmi_bridge_tmds_char_rate_valid()?

No, I mean drm_atomic_helper_connector_hdmi_check() being called from
drm_bridge_connector (inthe previous versions it was called from this
driver).

> 
> Also please confirm if HDMI audio was re-tested with these changes.

Yes, although not the channels allocation for the multi-channel audio. I
don't have corresponding equipment. If you think that we should start
testing that, I will check if I can get the 6.1 or 8.1 receiver and the
speakers :-)

> 
> > Acked-by: Maxime Ripard <mripard@kernel.org>
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> >   drivers/gpu/drm/msm/Kconfig            |   2 +
> >   drivers/gpu/drm/msm/hdmi/hdmi.c        |  45 ++-------
> >   drivers/gpu/drm/msm/hdmi/hdmi.h        |  16 +--
> >   drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  74 ++++----------
> >   drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 180 +++++++++++++++++++++++----------
> >   5 files changed, 162 insertions(+), 155 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
> > index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce9039d6f26f290d0 100644
> > --- a/drivers/gpu/drm/msm/Kconfig
> > +++ b/drivers/gpu/drm/msm/Kconfig
> > @@ -170,6 +170,8 @@ config DRM_MSM_HDMI
> >   	bool "Enable HDMI support in MSM DRM driver"
> >   	depends on DRM_MSM
> >   	default y
> > +	select DRM_DISPLAY_HDMI_HELPER
> > +	select DRM_DISPLAY_HDMI_STATE_HELPER
> >   	help
> >   	  Compile in support for the HDMI output MSM DRM driver. It can
> >   	  be a primary or a secondary display on device. Note that this is used
> > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe9b69c0da594bd 100644
> > --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> > +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > @@ -12,6 +12,7 @@
> >   #include <drm/drm_bridge_connector.h>
> >   #include <drm/drm_of.h>
> > +#include <drm/display/drm_hdmi_state_helper.h>
> >   #include <sound/hdmi-codec.h>
> >   #include "hdmi.h"
> > @@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
> >   	hdmi->dev = dev;
> >   	hdmi->encoder = encoder;
> > -	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
> > -
> >   	ret = msm_hdmi_bridge_init(hdmi);
> >   	if (ret) {
> >   		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
> > @@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
> >   				    struct hdmi_codec_params *params)
> >   {
> >   	struct hdmi *hdmi = dev_get_drvdata(dev);
> > -	unsigned int chan;
> > -	unsigned int channel_allocation = 0;
> >   	unsigned int rate;
> > -	unsigned int level_shift  = 0; /* 0dB */
> > -	bool down_mix = false;
> > +	int ret;
> >   	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
> >   		 params->sample_width, params->cea.channels);
> > -	switch (params->cea.channels) {
> > -	case 2:
> > -		/* FR and FL speakers */
> > -		channel_allocation  = 0;
> > -		chan = MSM_HDMI_AUDIO_CHANNEL_2;
> > -		break;
> > -	case 4:
> > -		/* FC, LFE, FR and FL speakers */
> > -		channel_allocation  = 0x3;
> > -		chan = MSM_HDMI_AUDIO_CHANNEL_4;
> > -		break;
> > -	case 6:
> > -		/* RR, RL, FC, LFE, FR and FL speakers */
> > -		channel_allocation  = 0x0B;
> > -		chan = MSM_HDMI_AUDIO_CHANNEL_6;
> > -		break;
> > -	case 8:
> > -		/* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
> > -		channel_allocation  = 0x1F;
> > -		chan = MSM_HDMI_AUDIO_CHANNEL_8;
> > -		break;
> > -	default:
> > -		return -EINVAL;
> > -	}
> 
> This mapping table was doing two things:
> 
> 1) drop the conversion of channels to an index to nchannels[] and use the
> channels directly. This part is fine but could have been a separate change
> by itself to show the redundancy.
> 
> 2) drop the mapping table of channels to channel_allocation.
> I am not fully sure of this. Was this done because
> hdmi_codec_channel_alloc[] table in hdmi-codec does this for us?
> hdmi_codec_get_ch_alloc_table_idx() uses channels and the flags to come up
> with the idx into this table. But it seems like current MSM HDMI code did
> not consider the flags. So for example, it seems like for 6 channels, we
> could return any of the below based on the flags but MSM HDMI always used
> 0x0B so will the values match?

Do they have to match? The correct value is being calculated by the HDMI
code in ASoC and then being written into the Audio InfoFrame. If the MSM
HDMI code wasn't taking ELD data into account, then it's a bug. But... I
don't think it's worth spending too much time on fixing it separately.

In the end, that is exactly the purpose of the frameworks - to make code
error prone and to remove the need to reimplement same things over and
over again, making differnt kinds of mistakes. For example, MSM HDMI
code also doesn't implement plugged_cb support. It doesn't provide ELD
to the HDMI codec code, etc. All of that is being fixed by using the
framework. It's not worth implementing those functions in the MSM HDMI
code first only to drop them in the next commit.

> 
> 202 	{ .ca_id = 0x0b, .n_ch = 6,
> 203 	  .mask = FL | FR | LFE | FC | RL | RR},
> 204 	/* surround40 */
> 205 	{ .ca_id = 0x08, .n_ch = 6,
> 206 	  .mask = FL | FR | RL | RR },
> 207 	/* surround41 */
> 208 	{ .ca_id = 0x09, .n_ch = 6,
> 209 	  .mask = FL | FR | LFE | RL | RR },
> 210 	/* surround50 */
> 211 	{ .ca_id = 0x0a, .n_ch = 6,
> 212 	  .mask = FL | FR | FC | RL | RR },
> 213 	/* 6.1 */
> 
> 
> > -
> >   	switch (params->sample_rate) {
> >   	case 32000:
> >   		rate = HDMI_SAMPLE_RATE_32KHZ;
> > @@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
> >   		return -EINVAL;
> >   	}
> > -	msm_hdmi_audio_set_sample_rate(hdmi, rate);
> > -	msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
> > -			      level_shift, down_mix);
> > +	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
> > +								      &params->cea);
> > +	if (ret)
> > +		return ret;
> > +
> > +	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
> >   	return 0;
> >   }
> > @@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
> >   {
> >   	struct hdmi *hdmi = dev_get_drvdata(dev);
> > -	msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
> > +	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
> > +	msm_hdmi_audio_disable(hdmi);
> >   }
> >   static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
> > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> > index a62d2aedfbb7239d37c826c4f96762f100a2be4a..53b52351d0eddf4a5c87a5290016bb53ed4d29f7 100644
> > --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> > +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> > @@ -24,8 +24,8 @@ struct hdmi_platform_config;
> >   struct hdmi_audio {
> >   	bool enabled;
> > -	struct hdmi_audio_infoframe infoframe;
> >   	int rate;
> > +	int channels;
> >   };
> >   struct hdmi_hdcp_ctrl;
> > @@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
> >   /*
> >    * audio:
> >    */
> > -/* Supported HDMI Audio channels and rates */
> > -#define	MSM_HDMI_AUDIO_CHANNEL_2	0
> > -#define	MSM_HDMI_AUDIO_CHANNEL_4	1
> > -#define	MSM_HDMI_AUDIO_CHANNEL_6	2
> > -#define	MSM_HDMI_AUDIO_CHANNEL_8	3
> > -
> >   #define	HDMI_SAMPLE_RATE_32KHZ		0
> >   #define	HDMI_SAMPLE_RATE_44_1KHZ	1
> >   #define	HDMI_SAMPLE_RATE_48KHZ		2
> > @@ -221,12 +215,8 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
> >   #define	HDMI_SAMPLE_RATE_176_4KHZ	5
> >   #define	HDMI_SAMPLE_RATE_192KHZ		6
> > -int msm_hdmi_audio_update(struct hdmi *hdmi);
> > -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> > -	uint32_t num_of_channels, uint32_t channel_allocation,
> > -	uint32_t level_shift, bool down_mix);
> > -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
> > -
> > +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
> > +int msm_hdmi_audio_disable(struct hdmi *hdmi);
> >   /*
> >    * hdmi bridge:
> > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..924654bfb48cf17feadea1c0661ee6ee4e1b4589 100644
> > --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > @@ -7,9 +7,6 @@
> >   #include <linux/hdmi.h>
> >   #include "hdmi.h"
> > -/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
> > -static int nchannels[] = { 2, 4, 6, 8 };
> > -
> >   /* Supported HDMI Audio sample rates */
> >   #define MSM_HDMI_SAMPLE_RATE_32KHZ		0
> >   #define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1
> > @@ -71,19 +68,20 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
> >   	return NULL;
> >   }
> > -int msm_hdmi_audio_update(struct hdmi *hdmi)
> > +static int msm_hdmi_audio_update(struct hdmi *hdmi)
> >   {
> >   	struct hdmi_audio *audio = &hdmi->audio;
> > -	struct hdmi_audio_infoframe *info = &audio->infoframe;
> >   	const struct hdmi_msm_audio_arcs *arcs = NULL;
> >   	bool enabled = audio->enabled;
> >   	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
> > -	uint32_t infofrm_ctrl, audio_config;
> > +	uint32_t audio_config;
> > +
> > +	if (!hdmi->connector->display_info.is_hdmi)
> > +		return -EINVAL;
> > +
> > +	DBG("audio: enabled=%d, channels=%d, rate=%d",
> > +	    audio->enabled, audio->channels, audio->rate);
> > -	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
> > -		"level_shift_value=%d, downmix_inhibit=%d, rate=%d",
> > -		audio->enabled, info->channels,  info->channel_allocation,
> > -		info->level_shift_value, info->downmix_inhibit, audio->rate);
> >   	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
> >   	if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
> > @@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> >   	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
> >   	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
> >   	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
> > -	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> >   	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
> >   	/* Clear N/CTS selection bits */
> > @@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> >   	if (enabled) {
> >   		uint32_t n, cts, multiplier;
> >   		enum hdmi_acr_cts select;
> > -		uint8_t buf[14];
> >   		n   = arcs->lut[audio->rate].n;
> >   		cts = arcs->lut[audio->rate].cts;
> > @@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> >   				HDMI_ACR_1_N(n));
> >   		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
> > -				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
> > +				COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
> >   				HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
> >   		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
> >   		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
> > -		/* configure infoframe: */
> > -		hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
> > -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
> > -				(buf[3] <<  0) | (buf[4] <<  8) |
> > -				(buf[5] << 16) | (buf[6] << 24));
> > -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
> > -				(buf[7] <<  0) | (buf[8] << 8));
> > -
> >   		hdmi_write(hdmi, REG_HDMI_GC, 0);
> >   		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
> > @@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> >   		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
> > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > -
> >   		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
> >   		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
> >   		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
> > @@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> >   		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
> >   		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
> >   		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
> > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> >   		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
> >   	}
> >   	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
> >   	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
> >   	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
> > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
> >   	hdmi_write(hdmi, REG_HDMI_AUD_INT,
> >   			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
> > @@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> >   	return 0;
> >   }
> > -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> > -	uint32_t num_of_channels, uint32_t channel_allocation,
> > -	uint32_t level_shift, bool down_mix)
> > +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
> >   {
> > -	struct hdmi_audio *audio;
> > -
> >   	if (!hdmi)
> >   		return -ENXIO;
> > -	audio = &hdmi->audio;
> > -
> > -	if (num_of_channels >= ARRAY_SIZE(nchannels))
> > +	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
> >   		return -EINVAL;
> > -	audio->enabled = enabled;
> > -	audio->infoframe.channels = nchannels[num_of_channels];
> > -	audio->infoframe.channel_allocation = channel_allocation;
> > -	audio->infoframe.level_shift_value = level_shift;
> > -	audio->infoframe.downmix_inhibit = down_mix;
> > +	hdmi->audio.rate = rate;
> > +	hdmi->audio.channels = channels;
> > +	hdmi->audio.enabled = true;
> >   	return msm_hdmi_audio_update(hdmi);
> >   }
> > -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
> > +int msm_hdmi_audio_disable(struct hdmi *hdmi)
> >   {
> > -	struct hdmi_audio *audio;
> > -
> >   	if (!hdmi)
> > -		return;
> > -
> > -	audio = &hdmi->audio;
> > +		return -ENXIO;
> > -	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
> > -		return;
> > +	hdmi->audio.rate = 0;
> > +	hdmi->audio.channels = 2;
> > +	hdmi->audio.enabled = false;
> > -	audio->rate = rate;
> > -	msm_hdmi_audio_update(hdmi);
> > +	return msm_hdmi_audio_update(hdmi);
> >   }
> > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > index d5ab1f74c0e6f47dc59872c016104e9a84d85e9e..168b4104e705e8217f5d7ca5f902d7557c55ae24 100644
> > --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > @@ -7,6 +7,8 @@
> >   #include <linux/delay.h>
> >   #include <drm/drm_bridge_connector.h>
> >   #include <drm/drm_edid.h>
> > +#include <drm/display/drm_hdmi_helper.h>
> > +#include <drm/display/drm_hdmi_state_helper.h>
> >   #include "msm_kms.h"
> >   #include "hdmi.h"
> > @@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge)
> >   #define AVI_IFRAME_LINE_NUMBER 1
> > -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> > +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
> > +					 const u8 *buffer, size_t len)
> >   {
> > -	struct drm_crtc *crtc = hdmi->encoder->crtc;
> > -	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> > -	union hdmi_infoframe frame;
> > -	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
> > +	u32 buf[4] = {};
> >   	u32 val;
> > -	int len;
> > +	int i;
> > -	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
> > -						 hdmi->connector, mode);
> > -
> > -	len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
> > -	if (len < 0) {
> > +	if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
> >   		DRM_DEV_ERROR(&hdmi->pdev->dev,
> >   			"failed to configure avi infoframe\n");
> > -		return;
> > +		return -EINVAL;
> >   	}
> >   	/*
> > @@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> >   	 * written to the LSB byte of AVI_INFO0 and the version is written to
> >   	 * the third byte from the LSB of AVI_INFO3
> >   	 */
> > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
> > +	memcpy(buf, &buffer[3], len - 3);
> > +
> > +	buf[3] |= buffer[1] << 24;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(buf); i++)
> > +		hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
> > +
> > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > +	val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > +		HDMI_INFOFRAME_CTRL0_AVI_CONT;
> > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > +
> > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > +	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > +	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > +
> > +	return 0;
> > +}
> > +
> > +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
> > +					   const u8 *buffer, size_t len)
> > +{
> > +	u32 val;
> > +
> > +	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
> > +		DRM_DEV_ERROR(&hdmi->pdev->dev,
> > +			"failed to configure audio infoframe\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
> >   		   buffer[3] |
> >   		   buffer[4] << 8 |
> >   		   buffer[5] << 16 |
> >   		   buffer[6] << 24);
> > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
> > +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
> >   		   buffer[7] |
> >   		   buffer[8] << 8 |
> >   		   buffer[9] << 16 |
> >   		   buffer[10] << 24);
> > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
> > -		   buffer[11] |
> > -		   buffer[12] << 8 |
> > -		   buffer[13] << 16 |
> > -		   buffer[14] << 24);
> > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > +	val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > +
> > +	return 0;
> > +}
> > +
> > +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
> > +					   enum hdmi_infoframe_type type)
> > +{
> > +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > +	u32 val;
> > +
> > +	switch (type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > +		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > +			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
> > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
> > -		   buffer[15] |
> > -		   buffer[16] << 8 |
> > -		   buffer[1] << 24);
> > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > +		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
> > -		   HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > -		   HDMI_INFOFRAME_CTRL0_AVI_CONT);
> > +		break;
> > -	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > -	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > -	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > +		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
> > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > +
> > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > +		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
> > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > +
> > +		break;
> > +
> > +	default:
> > +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
> > +					   enum hdmi_infoframe_type type,
> > +					   const u8 *buffer, size_t len)
> > +{
> > +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > +
> > +	msm_hdmi_bridge_clear_infoframe(bridge, type);
> > +
> > +	switch (type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
> > +	default:
> > +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> > +		return 0;
> > +	}
> >   }
> >   static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > @@ -146,16 +223,16 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> >   	conn_state = drm_atomic_get_new_connector_state(state, connector);
> >   	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > +	hdmi->pixclock = conn_state->hdmi.tmds_char_rate;
> > +
> >   	if (!hdmi->power_on) {
> >   		msm_hdmi_phy_resource_enable(phy);
> >   		msm_hdmi_power_on(bridge);
> >   		hdmi->power_on = true;
> > -		if (hdmi->hdmi_mode) {
> > -			msm_hdmi_config_avi_infoframe(hdmi);
> > -			msm_hdmi_audio_update(hdmi);
> > -		}
> >   	}
> > +	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
> > +
> >   	msm_hdmi_phy_powerup(phy, hdmi->pixclock);
> >   	msm_hdmi_set_mode(hdmi, true);
> > @@ -184,8 +261,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> >   	if (hdmi->power_on) {
> >   		power_off(bridge);
> >   		hdmi->power_on = false;
> > -		if (hdmi->hdmi_mode)
> > -			msm_hdmi_audio_update(hdmi);
> >   		msm_hdmi_phy_resource_disable(phy);
> >   	}
> >   }
> > @@ -196,8 +271,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> >   	int hstart, hend, vstart, vend;
> >   	uint32_t frame_ctrl;
> > -	hdmi->pixclock = mode->clock * 1000;
> > -
> >   	hstart = mode->htotal - mode->hsync_start;
> >   	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
> > @@ -241,9 +314,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> >   		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
> >   	DBG("frame_ctrl=%08x", frame_ctrl);
> >   	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
> > -
> > -	if (hdmi->hdmi_mode)
> > -		msm_hdmi_audio_update(hdmi);
> >   }
> >   static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridge,
> > @@ -275,18 +345,16 @@ static const struct drm_edid *msm_hdmi_bridge_edid_read(struct drm_bridge *bridg
> >   	return drm_edid;
> >   }
> > -static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
> > -		const struct drm_display_info *info,
> > -		const struct drm_display_mode *mode)
> > +static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
> > +								 const struct drm_display_mode *mode,
> > +								 unsigned long long tmds_rate)
> >   {
> >   	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> >   	struct hdmi *hdmi = hdmi_bridge->hdmi;
> >   	const struct hdmi_platform_config *config = hdmi->config;
> >   	struct msm_drm_private *priv = bridge->dev->dev_private;
> >   	struct msm_kms *kms = priv->kms;
> > -	long actual, requested;
> > -
> > -	requested = 1000 * mode->clock;
> > +	long actual;
> >   	/* for mdp5/apq8074, we manage our own pixel clk (as opposed to
> >   	 * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
> > @@ -294,15 +362,16 @@ static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge
> >   	 */
> >   	if (kms->funcs->round_pixclk)
> >   		actual = kms->funcs->round_pixclk(kms,
> > -			requested, hdmi_bridge->hdmi->encoder);
> > +						  tmds_rate,
> > +						  hdmi_bridge->hdmi->encoder);
> >   	else if (config->pwr_clk_cnt > 0)
> > -		actual = clk_round_rate(hdmi->pwr_clks[0], requested);
> > +		actual = clk_round_rate(hdmi->pwr_clks[0], tmds_rate);
> >   	else
> > -		actual = requested;
> > +		actual = tmds_rate;
> > -	DBG("requested=%ld, actual=%ld", requested, actual);
> > +	DBG("requested=%lld, actual=%ld", tmds_rate, actual);
> > -	if (actual != requested)
> > +	if (actual != tmds_rate)
> >   		return MODE_CLOCK_RANGE;
> >   	return 0;
> > @@ -314,9 +383,11 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
> >   	.atomic_reset = drm_atomic_helper_bridge_reset,
> >   	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
> >   	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
> > -	.mode_valid = msm_hdmi_bridge_mode_valid,
> >   	.edid_read = msm_hdmi_bridge_edid_read,
> >   	.detect = msm_hdmi_bridge_detect,
> > +	.hdmi_tmds_char_rate_valid = msm_hdmi_bridge_tmds_char_rate_valid,
> > +	.hdmi_clear_infoframe = msm_hdmi_bridge_clear_infoframe,
> > +	.hdmi_write_infoframe = msm_hdmi_bridge_write_infoframe,
> >   };
> >   static void
> > @@ -348,8 +419,11 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi)
> >   	bridge->funcs = &msm_hdmi_bridge_funcs;
> >   	bridge->ddc = hdmi->i2c;
> >   	bridge->type = DRM_MODE_CONNECTOR_HDMIA;
> > +	bridge->vendor = "Qualcomm";
> > +	bridge->product = "Snapdragon";
> >   	bridge->ops = DRM_BRIDGE_OP_HPD |
> >   		DRM_BRIDGE_OP_DETECT |
> > +		DRM_BRIDGE_OP_HDMI |
> >   		DRM_BRIDGE_OP_EDID;
> >   	ret = devm_drm_bridge_add(hdmi->dev->dev, bridge);
> > 

-- 
With best wishes
Dmitry

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

* Re: [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-02-04  0:59     ` Dmitry Baryshkov
@ 2025-02-06 20:41       ` Abhinav Kumar
  2025-02-07  1:19         ` Dmitry Baryshkov
  0 siblings, 1 reply; 22+ messages in thread
From: Abhinav Kumar @ 2025-02-06 20:41 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel



On 2/3/2025 4:59 PM, Dmitry Baryshkov wrote:
> On Mon, Feb 03, 2025 at 11:34:00AM -0800, Abhinav Kumar wrote:
>>
>>
>> On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
>>> The mode_set callback is deprecated, it doesn't get the
>>> drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
>>> that HDMI timings should be programmed after setting up HDMI PHY and
>>> PLL. Rework the code to program HDMI timings at the end of
>>> atomic_pre_enable().
>>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>>    drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 23 +++++++++++++++--------
>>>    1 file changed, 15 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>> index d839c71091dcdc3b020fcbba8d698d58ee7fc749..d5ab1f74c0e6f47dc59872c016104e9a84d85e9e 100644
>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>> @@ -126,15 +126,26 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>>>    	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>>    }
>>> +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>> +					       const struct drm_display_mode *mode);
>>>    static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>>>    					      struct drm_bridge_state *old_bridge_state)
>>>    {
>>> +	struct drm_atomic_state *state = old_bridge_state->base.state;
>>>    	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>>>    	struct hdmi *hdmi = hdmi_bridge->hdmi;
>>>    	struct hdmi_phy *phy = hdmi->phy;
>>> +	struct drm_encoder *encoder = bridge->encoder;
>>> +	struct drm_connector *connector;
>>> +	struct drm_connector_state *conn_state;
>>> +	struct drm_crtc_state *crtc_state;
>>>    	DBG("power up");
>>> +	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
>>> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
>>> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
>>> +
>>>    	if (!hdmi->power_on) {
>>>    		msm_hdmi_phy_resource_enable(phy);
>>>    		msm_hdmi_power_on(bridge);
>>> @@ -151,6 +162,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>>>    	if (hdmi->hdcp_ctrl)
>>>    		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
>>> +
>>> +	msm_hdmi_bridge_atomic_set_timings(hdmi, &crtc_state->adjusted_mode);
>>>    }
>>
>> This addresses my comment about setting up the HDMI timing registers before
>> setting up the timing engine registers.
>>
>> But prior to this change, mode_set was doing the same thing as
>> msm_hdmi_bridge_atomic_set_timings() which means
>> msm_hdmi_bridge_atomic_set_timings() should be called at the beginning of
>> pre_enable()?
>>
>> The controller is enabled in msm_hdmi_set_mode(). So this should be done
>> before that.
> 
> In [1] you provided the following order:
> 
> 1) setup HDMI PHY and PLL
> 2) setup HDMI video path correctly (HDMI timing registers)
> 3) setup timing generator to match the HDMI video in (2)
> 4) Enable timing engine
> 
> This means htat msm_hdmi_bridge_atomic_set_timings() should come at the
> end of msm_hdmi_bridge_atomic_pre_enable(), not in the beginning /
> middle of it.
> 
> [1] https://lore.kernel.org/dri-devel/8dd4a43e-d83c-1f36-21ff-61e13ff751e7@quicinc.com/
> 

Sequence given is correct and is exactly what is given in the docs. What 
is somewhat not clear in the docs is the location of the enable of the 
HDMI controller. This is not there in the above 4 steps. I am referring 
to the enable bit being programmed in msm_hdmi_set_mode(). Ideally till 
we enable the timing engine, it should be okay but what I wanted to do 
was to keep the msm_hdmi_set_mode() as the last call in this function 
that way we program everything and then enable the controller.

This can be done in either way, move it to the beginning of the function 
or move it right before msm_hdmi_set_mode(). I had suggested beginning 
because thats how it was when things were still in mode_set.



> 
>>
>>>    static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
>>> @@ -177,17 +190,12 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
>>>    	}
>>>    }
>>> -static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge,
>>> -		 const struct drm_display_mode *mode,
>>> -		 const struct drm_display_mode *adjusted_mode)
>>> +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>> +					       const struct drm_display_mode *mode)
>>>    {
>>> -	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>>> -	struct hdmi *hdmi = hdmi_bridge->hdmi;
>>>    	int hstart, hend, vstart, vend;
>>>    	uint32_t frame_ctrl;
>>> -	mode = adjusted_mode;
>>> -
>>>    	hdmi->pixclock = mode->clock * 1000;
>>>    	hstart = mode->htotal - mode->hsync_start;
>>> @@ -306,7 +314,6 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
>>>    	.atomic_reset = drm_atomic_helper_bridge_reset,
>>>    	.atomic_pre_enable = msm_hdmi_bridge_atomic_pre_enable,
>>>    	.atomic_post_disable = msm_hdmi_bridge_atomic_post_disable,
>>> -	.mode_set = msm_hdmi_bridge_mode_set,
>>>    	.mode_valid = msm_hdmi_bridge_mode_valid,
>>>    	.edid_read = msm_hdmi_bridge_edid_read,
>>>    	.detect = msm_hdmi_bridge_detect,
>>>
> 

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

* Re: [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-02-06 20:41       ` Abhinav Kumar
@ 2025-02-07  1:19         ` Dmitry Baryshkov
  2025-02-07 20:11           ` Abhinav Kumar
  0 siblings, 1 reply; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-02-07  1:19 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel

On Thu, Feb 06, 2025 at 12:41:30PM -0800, Abhinav Kumar wrote:
> 
> 
> On 2/3/2025 4:59 PM, Dmitry Baryshkov wrote:
> > On Mon, Feb 03, 2025 at 11:34:00AM -0800, Abhinav Kumar wrote:
> > > 
> > > 
> > > On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> > > > The mode_set callback is deprecated, it doesn't get the
> > > > drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
> > > > that HDMI timings should be programmed after setting up HDMI PHY and
> > > > PLL. Rework the code to program HDMI timings at the end of
> > > > atomic_pre_enable().
> > > > 
> > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > ---
> > > >    drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 23 +++++++++++++++--------
> > > >    1 file changed, 15 insertions(+), 8 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > index d839c71091dcdc3b020fcbba8d698d58ee7fc749..d5ab1f74c0e6f47dc59872c016104e9a84d85e9e 100644
> > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > @@ -126,15 +126,26 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> > > >    	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > >    }
> > > > +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > > +					       const struct drm_display_mode *mode);
> > > >    static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> > > >    					      struct drm_bridge_state *old_bridge_state)
> > > >    {
> > > > +	struct drm_atomic_state *state = old_bridge_state->base.state;
> > > >    	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > > >    	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > > >    	struct hdmi_phy *phy = hdmi->phy;
> > > > +	struct drm_encoder *encoder = bridge->encoder;
> > > > +	struct drm_connector *connector;
> > > > +	struct drm_connector_state *conn_state;
> > > > +	struct drm_crtc_state *crtc_state;
> > > >    	DBG("power up");
> > > > +	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
> > > > +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > > > +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > > > +
> > > >    	if (!hdmi->power_on) {
> > > >    		msm_hdmi_phy_resource_enable(phy);
> > > >    		msm_hdmi_power_on(bridge);
> > > > @@ -151,6 +162,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> > > >    	if (hdmi->hdcp_ctrl)
> > > >    		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
> > > > +
> > > > +	msm_hdmi_bridge_atomic_set_timings(hdmi, &crtc_state->adjusted_mode);
> > > >    }
> > > 
> > > This addresses my comment about setting up the HDMI timing registers before
> > > setting up the timing engine registers.
> > > 
> > > But prior to this change, mode_set was doing the same thing as
> > > msm_hdmi_bridge_atomic_set_timings() which means
> > > msm_hdmi_bridge_atomic_set_timings() should be called at the beginning of
> > > pre_enable()?
> > > 
> > > The controller is enabled in msm_hdmi_set_mode(). So this should be done
> > > before that.
> > 
> > In [1] you provided the following order:
> > 
> > 1) setup HDMI PHY and PLL
> > 2) setup HDMI video path correctly (HDMI timing registers)
> > 3) setup timing generator to match the HDMI video in (2)
> > 4) Enable timing engine
> > 
> > This means htat msm_hdmi_bridge_atomic_set_timings() should come at the
> > end of msm_hdmi_bridge_atomic_pre_enable(), not in the beginning /
> > middle of it.
> > 
> > [1] https://lore.kernel.org/dri-devel/8dd4a43e-d83c-1f36-21ff-61e13ff751e7@quicinc.com/
> > 
> 
> Sequence given is correct and is exactly what is given in the docs. What is
> somewhat not clear in the docs is the location of the enable of the HDMI
> controller. This is not there in the above 4 steps. I am referring to the
> enable bit being programmed in msm_hdmi_set_mode(). Ideally till we enable
> the timing engine, it should be okay but what I wanted to do was to keep the
> msm_hdmi_set_mode() as the last call in this function that way we program
> everything and then enable the controller.
> 
> This can be done in either way, move it to the beginning of the function or
> move it right before msm_hdmi_set_mode(). I had suggested beginning because
> thats how it was when things were still in mode_set.

Well.. following your description it might be better to put it after PHY
init. What do you think?

-- 
With best wishes
Dmitry

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

* Re: [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-02-07  1:19         ` Dmitry Baryshkov
@ 2025-02-07 20:11           ` Abhinav Kumar
  2025-02-07 22:07             ` Dmitry Baryshkov
  0 siblings, 1 reply; 22+ messages in thread
From: Abhinav Kumar @ 2025-02-07 20:11 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel



On 2/6/2025 5:19 PM, Dmitry Baryshkov wrote:
> On Thu, Feb 06, 2025 at 12:41:30PM -0800, Abhinav Kumar wrote:
>>
>>
>> On 2/3/2025 4:59 PM, Dmitry Baryshkov wrote:
>>> On Mon, Feb 03, 2025 at 11:34:00AM -0800, Abhinav Kumar wrote:
>>>>
>>>>
>>>> On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
>>>>> The mode_set callback is deprecated, it doesn't get the
>>>>> drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
>>>>> that HDMI timings should be programmed after setting up HDMI PHY and
>>>>> PLL. Rework the code to program HDMI timings at the end of
>>>>> atomic_pre_enable().
>>>>>
>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>> ---
>>>>>     drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 23 +++++++++++++++--------
>>>>>     1 file changed, 15 insertions(+), 8 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>>>> index d839c71091dcdc3b020fcbba8d698d58ee7fc749..d5ab1f74c0e6f47dc59872c016104e9a84d85e9e 100644
>>>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>>>> @@ -126,15 +126,26 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>>>>>     	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>>>>     }
>>>>> +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>>>> +					       const struct drm_display_mode *mode);
>>>>>     static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>>>>>     					      struct drm_bridge_state *old_bridge_state)
>>>>>     {
>>>>> +	struct drm_atomic_state *state = old_bridge_state->base.state;
>>>>>     	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>>>>>     	struct hdmi *hdmi = hdmi_bridge->hdmi;
>>>>>     	struct hdmi_phy *phy = hdmi->phy;
>>>>> +	struct drm_encoder *encoder = bridge->encoder;
>>>>> +	struct drm_connector *connector;
>>>>> +	struct drm_connector_state *conn_state;
>>>>> +	struct drm_crtc_state *crtc_state;
>>>>>     	DBG("power up");
>>>>> +	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
>>>>> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
>>>>> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
>>>>> +
>>>>>     	if (!hdmi->power_on) {
>>>>>     		msm_hdmi_phy_resource_enable(phy);
>>>>>     		msm_hdmi_power_on(bridge);
>>>>> @@ -151,6 +162,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>>>>>     	if (hdmi->hdcp_ctrl)
>>>>>     		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
>>>>> +
>>>>> +	msm_hdmi_bridge_atomic_set_timings(hdmi, &crtc_state->adjusted_mode);
>>>>>     }
>>>>
>>>> This addresses my comment about setting up the HDMI timing registers before
>>>> setting up the timing engine registers.
>>>>
>>>> But prior to this change, mode_set was doing the same thing as
>>>> msm_hdmi_bridge_atomic_set_timings() which means
>>>> msm_hdmi_bridge_atomic_set_timings() should be called at the beginning of
>>>> pre_enable()?
>>>>
>>>> The controller is enabled in msm_hdmi_set_mode(). So this should be done
>>>> before that.
>>>
>>> In [1] you provided the following order:
>>>
>>> 1) setup HDMI PHY and PLL
>>> 2) setup HDMI video path correctly (HDMI timing registers)
>>> 3) setup timing generator to match the HDMI video in (2)
>>> 4) Enable timing engine
>>>
>>> This means htat msm_hdmi_bridge_atomic_set_timings() should come at the
>>> end of msm_hdmi_bridge_atomic_pre_enable(), not in the beginning /
>>> middle of it.
>>>
>>> [1] https://lore.kernel.org/dri-devel/8dd4a43e-d83c-1f36-21ff-61e13ff751e7@quicinc.com/
>>>
>>
>> Sequence given is correct and is exactly what is given in the docs. What is
>> somewhat not clear in the docs is the location of the enable of the HDMI
>> controller. This is not there in the above 4 steps. I am referring to the
>> enable bit being programmed in msm_hdmi_set_mode(). Ideally till we enable
>> the timing engine, it should be okay but what I wanted to do was to keep the
>> msm_hdmi_set_mode() as the last call in this function that way we program
>> everything and then enable the controller.
>>
>> This can be done in either way, move it to the beginning of the function or
>> move it right before msm_hdmi_set_mode(). I had suggested beginning because
>> thats how it was when things were still in mode_set.
> 
> Well.. following your description it might be better to put it after PHY
> init. What do you think?
> 

Are you referring to after msm_hdmi_phy_powerup()? Yes, thats fine too.


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

* Re: [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework
  2025-02-04  1:30     ` Dmitry Baryshkov
@ 2025-02-07 21:34       ` Abhinav Kumar
  2025-02-07 22:03         ` Dmitry Baryshkov
  0 siblings, 1 reply; 22+ messages in thread
From: Abhinav Kumar @ 2025-02-07 21:34 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel



On 2/3/2025 5:30 PM, Dmitry Baryshkov wrote:
> On Mon, Feb 03, 2025 at 04:25:59PM -0800, Abhinav Kumar wrote:
>>
>>
>> On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
>>> Setup the HDMI connector on the MSM HDMI outputs. Make use of
>>> atomic_check hook and of the provided Infoframe infrastructure.
>>>
>>
>> By atomic_check are you referring to the
>> msm_hdmi_bridge_tmds_char_rate_valid()?
> 
> No, I mean drm_atomic_helper_connector_hdmi_check() being called from
> drm_bridge_connector (inthe previous versions it was called from this
> driver).
> 

Ack.
>>
>> Also please confirm if HDMI audio was re-tested with these changes.
> 
> Yes, although not the channels allocation for the multi-channel audio. I
> don't have corresponding equipment. If you think that we should start
> testing that, I will check if I can get the 6.1 or 8.1 receiver and the
> speakers :-)
> 

We should but I am fine with basic audio validation for now.

>>
>>> Acked-by: Maxime Ripard <mripard@kernel.org>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>>    drivers/gpu/drm/msm/Kconfig            |   2 +
>>>    drivers/gpu/drm/msm/hdmi/hdmi.c        |  45 ++-------
>>>    drivers/gpu/drm/msm/hdmi/hdmi.h        |  16 +--
>>>    drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  74 ++++----------
>>>    drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 180 +++++++++++++++++++++++----------
>>>    5 files changed, 162 insertions(+), 155 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
>>> index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce9039d6f26f290d0 100644
>>> --- a/drivers/gpu/drm/msm/Kconfig
>>> +++ b/drivers/gpu/drm/msm/Kconfig
>>> @@ -170,6 +170,8 @@ config DRM_MSM_HDMI
>>>    	bool "Enable HDMI support in MSM DRM driver"
>>>    	depends on DRM_MSM
>>>    	default y
>>> +	select DRM_DISPLAY_HDMI_HELPER
>>> +	select DRM_DISPLAY_HDMI_STATE_HELPER
>>>    	help
>>>    	  Compile in support for the HDMI output MSM DRM driver. It can
>>>    	  be a primary or a secondary display on device. Note that this is used
>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
>>> index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe9b69c0da594bd 100644
>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
>>> @@ -12,6 +12,7 @@
>>>    #include <drm/drm_bridge_connector.h>
>>>    #include <drm/drm_of.h>
>>> +#include <drm/display/drm_hdmi_state_helper.h>
>>>    #include <sound/hdmi-codec.h>
>>>    #include "hdmi.h"
>>> @@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
>>>    	hdmi->dev = dev;
>>>    	hdmi->encoder = encoder;
>>> -	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
>>> -
>>>    	ret = msm_hdmi_bridge_init(hdmi);
>>>    	if (ret) {
>>>    		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
>>> @@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
>>>    				    struct hdmi_codec_params *params)
>>>    {
>>>    	struct hdmi *hdmi = dev_get_drvdata(dev);
>>> -	unsigned int chan;
>>> -	unsigned int channel_allocation = 0;
>>>    	unsigned int rate;
>>> -	unsigned int level_shift  = 0; /* 0dB */
>>> -	bool down_mix = false;
>>> +	int ret;
>>>    	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
>>>    		 params->sample_width, params->cea.channels);
>>> -	switch (params->cea.channels) {
>>> -	case 2:
>>> -		/* FR and FL speakers */
>>> -		channel_allocation  = 0;
>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_2;
>>> -		break;
>>> -	case 4:
>>> -		/* FC, LFE, FR and FL speakers */
>>> -		channel_allocation  = 0x3;
>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_4;
>>> -		break;
>>> -	case 6:
>>> -		/* RR, RL, FC, LFE, FR and FL speakers */
>>> -		channel_allocation  = 0x0B;
>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_6;
>>> -		break;
>>> -	case 8:
>>> -		/* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
>>> -		channel_allocation  = 0x1F;
>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_8;
>>> -		break;
>>> -	default:
>>> -		return -EINVAL;
>>> -	}
>>
>> This mapping table was doing two things:
>>
>> 1) drop the conversion of channels to an index to nchannels[] and use the
>> channels directly. This part is fine but could have been a separate change
>> by itself to show the redundancy.
>>
>> 2) drop the mapping table of channels to channel_allocation.
>> I am not fully sure of this. Was this done because
>> hdmi_codec_channel_alloc[] table in hdmi-codec does this for us?
>> hdmi_codec_get_ch_alloc_table_idx() uses channels and the flags to come up
>> with the idx into this table. But it seems like current MSM HDMI code did
>> not consider the flags. So for example, it seems like for 6 channels, we
>> could return any of the below based on the flags but MSM HDMI always used
>> 0x0B so will the values match?
> 
> Do they have to match? The correct value is being calculated by the HDMI
> code in ASoC and then being written into the Audio InfoFrame. If the MSM
> HDMI code wasn't taking ELD data into account, then it's a bug. But... I
> don't think it's worth spending too much time on fixing it separately.
> 

Its a change in values which are passed to the audio infoframe but I 
dont know if it will change the behavior of what has been working so far 
(I hope not).

I agree, that msm hdmi driver not considering the flags in the mask is a 
bug so for that reason, we should use the channels and channel 
allocation supplied to us by hdmi_codec.

If it does result in an issue (due to it incorrectly working today), we 
will atleast know where to look at.

Some more questions below.

> In the end, that is exactly the purpose of the frameworks - to make code
> error prone and to remove the need to reimplement same things over and
> over again, making differnt kinds of mistakes. For example, MSM HDMI
> code also doesn't implement plugged_cb support. It doesn't provide ELD
> to the HDMI codec code, etc. All of that is being fixed by using the
> framework. It's not worth implementing those functions in the MSM HDMI
> code first only to drop them in the next commit.
> 
>>
>> 202 	{ .ca_id = 0x0b, .n_ch = 6,
>> 203 	  .mask = FL | FR | LFE | FC | RL | RR},
>> 204 	/* surround40 */
>> 205 	{ .ca_id = 0x08, .n_ch = 6,
>> 206 	  .mask = FL | FR | RL | RR },
>> 207 	/* surround41 */
>> 208 	{ .ca_id = 0x09, .n_ch = 6,
>> 209 	  .mask = FL | FR | LFE | RL | RR },
>> 210 	/* surround50 */
>> 211 	{ .ca_id = 0x0a, .n_ch = 6,
>> 212 	  .mask = FL | FR | FC | RL | RR },
>> 213 	/* 6.1 */
>>
>>
>>> -
>>>    	switch (params->sample_rate) {
>>>    	case 32000:
>>>    		rate = HDMI_SAMPLE_RATE_32KHZ;
>>> @@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
>>>    		return -EINVAL;
>>>    	}
>>> -	msm_hdmi_audio_set_sample_rate(hdmi, rate);
>>> -	msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
>>> -			      level_shift, down_mix);
>>> +	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
>>> +								      &params->cea);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
>>>    	return 0;
>>>    }
>>> @@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
>>>    {
>>>    	struct hdmi *hdmi = dev_get_drvdata(dev);
>>> -	msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
>>> +	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
>>> +	msm_hdmi_audio_disable(hdmi);
>>>    }
>>>    static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
>>> index a62d2aedfbb7239d37c826c4f96762f100a2be4a..53b52351d0eddf4a5c87a5290016bb53ed4d29f7 100644
>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
>>> @@ -24,8 +24,8 @@ struct hdmi_platform_config;
>>>    struct hdmi_audio {
>>>    	bool enabled;
>>> -	struct hdmi_audio_infoframe infoframe;
>>>    	int rate;
>>> +	int channels;
>>>    };
>>>    struct hdmi_hdcp_ctrl;
>>> @@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
>>>    /*
>>>     * audio:
>>>     */
>>> -/* Supported HDMI Audio channels and rates */
>>> -#define	MSM_HDMI_AUDIO_CHANNEL_2	0
>>> -#define	MSM_HDMI_AUDIO_CHANNEL_4	1
>>> -#define	MSM_HDMI_AUDIO_CHANNEL_6	2
>>> -#define	MSM_HDMI_AUDIO_CHANNEL_8	3
>>> -
>>>    #define	HDMI_SAMPLE_RATE_32KHZ		0
>>>    #define	HDMI_SAMPLE_RATE_44_1KHZ	1
>>>    #define	HDMI_SAMPLE_RATE_48KHZ		2
>>> @@ -221,12 +215,8 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
>>>    #define	HDMI_SAMPLE_RATE_176_4KHZ	5
>>>    #define	HDMI_SAMPLE_RATE_192KHZ		6
>>> -int msm_hdmi_audio_update(struct hdmi *hdmi);
>>> -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
>>> -	uint32_t num_of_channels, uint32_t channel_allocation,
>>> -	uint32_t level_shift, bool down_mix);
>>> -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
>>> -
>>> +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
>>> +int msm_hdmi_audio_disable(struct hdmi *hdmi);
>>>    /*
>>>     * hdmi bridge:
>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
>>> index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..924654bfb48cf17feadea1c0661ee6ee4e1b4589 100644
>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
>>> @@ -7,9 +7,6 @@
>>>    #include <linux/hdmi.h>
>>>    #include "hdmi.h"
>>> -/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
>>> -static int nchannels[] = { 2, 4, 6, 8 };
>>> -
>>>    /* Supported HDMI Audio sample rates */
>>>    #define MSM_HDMI_SAMPLE_RATE_32KHZ		0
>>>    #define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1
>>> @@ -71,19 +68,20 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
>>>    	return NULL;
>>>    }
>>> -int msm_hdmi_audio_update(struct hdmi *hdmi)
>>> +static int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>    {
>>>    	struct hdmi_audio *audio = &hdmi->audio;
>>> -	struct hdmi_audio_infoframe *info = &audio->infoframe;
>>>    	const struct hdmi_msm_audio_arcs *arcs = NULL;
>>>    	bool enabled = audio->enabled;
>>>    	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
>>> -	uint32_t infofrm_ctrl, audio_config;
>>> +	uint32_t audio_config;
>>> +
>>> +	if (!hdmi->connector->display_info.is_hdmi)
>>> +		return -EINVAL;
>>> +
>>> +	DBG("audio: enabled=%d, channels=%d, rate=%d",
>>> +	    audio->enabled, audio->channels, audio->rate);
>>> -	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
>>> -		"level_shift_value=%d, downmix_inhibit=%d, rate=%d",
>>> -		audio->enabled, info->channels,  info->channel_allocation,
>>> -		info->level_shift_value, info->downmix_inhibit, audio->rate);
>>>    	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
>>>    	if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
>>> @@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>    	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
>>>    	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
>>>    	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
>>> -	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
>>>    	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
>>>    	/* Clear N/CTS selection bits */
>>> @@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>    	if (enabled) {
>>>    		uint32_t n, cts, multiplier;
>>>    		enum hdmi_acr_cts select;
>>> -		uint8_t buf[14];
>>>    		n   = arcs->lut[audio->rate].n;
>>>    		cts = arcs->lut[audio->rate].cts;
>>> @@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>    				HDMI_ACR_1_N(n));
>>>    		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
>>> -				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
>>> +				COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
>>>    				HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
>>>    		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
>>>    		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
>>> -		/* configure infoframe: */
>>> -		hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
>>> -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
>>> -				(buf[3] <<  0) | (buf[4] <<  8) |
>>> -				(buf[5] << 16) | (buf[6] << 24));
>>> -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
>>> -				(buf[7] <<  0) | (buf[8] << 8));
>>> -
>>>    		hdmi_write(hdmi, REG_HDMI_GC, 0);
>>>    		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
>>> @@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>    		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
>>> -
>>>    		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
>>>    		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
>>>    		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
>>> @@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>    		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
>>>    		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
>>>    		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
>>>    		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
>>>    	}
>>>    	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
>>>    	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
>>>    	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
>>> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
>>>    	hdmi_write(hdmi, REG_HDMI_AUD_INT,
>>>    			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
>>> @@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>    	return 0;
>>>    }
>>> -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
>>> -	uint32_t num_of_channels, uint32_t channel_allocation,
>>> -	uint32_t level_shift, bool down_mix)
>>> +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
>>>    {
>>> -	struct hdmi_audio *audio;
>>> -
>>>    	if (!hdmi)
>>>    		return -ENXIO;
>>> -	audio = &hdmi->audio;
>>> -
>>> -	if (num_of_channels >= ARRAY_SIZE(nchannels))
>>> +	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
>>>    		return -EINVAL;
>>> -	audio->enabled = enabled;
>>> -	audio->infoframe.channels = nchannels[num_of_channels];
>>> -	audio->infoframe.channel_allocation = channel_allocation;
>>> -	audio->infoframe.level_shift_value = level_shift;
>>> -	audio->infoframe.downmix_inhibit = down_mix;
>>> +	hdmi->audio.rate = rate;
>>> +	hdmi->audio.channels = channels;
>>> +	hdmi->audio.enabled = true;
>>>    	return msm_hdmi_audio_update(hdmi);
>>>    }
>>> -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
>>> +int msm_hdmi_audio_disable(struct hdmi *hdmi)
>>>    {
>>> -	struct hdmi_audio *audio;
>>> -
>>>    	if (!hdmi)
>>> -		return;
>>> -
>>> -	audio = &hdmi->audio;
>>> +		return -ENXIO;
>>> -	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
>>> -		return;
>>> +	hdmi->audio.rate = 0;
>>> +	hdmi->audio.channels = 2;
>>> +	hdmi->audio.enabled = false;
>>> -	audio->rate = rate;
>>> -	msm_hdmi_audio_update(hdmi);
>>> +	return msm_hdmi_audio_update(hdmi);
>>>    }
>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>> index d5ab1f74c0e6f47dc59872c016104e9a84d85e9e..168b4104e705e8217f5d7ca5f902d7557c55ae24 100644
>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>> @@ -7,6 +7,8 @@
>>>    #include <linux/delay.h>
>>>    #include <drm/drm_bridge_connector.h>
>>>    #include <drm/drm_edid.h>
>>> +#include <drm/display/drm_hdmi_helper.h>
>>> +#include <drm/display/drm_hdmi_state_helper.h>
>>>    #include "msm_kms.h"
>>>    #include "hdmi.h"
>>> @@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge)
>>>    #define AVI_IFRAME_LINE_NUMBER 1
>>> -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>>> +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
>>> +					 const u8 *buffer, size_t len)
>>>    {
>>> -	struct drm_crtc *crtc = hdmi->encoder->crtc;
>>> -	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
>>> -	union hdmi_infoframe frame;
>>> -	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
>>> +	u32 buf[4] = {};
>>>    	u32 val;
>>> -	int len;
>>> +	int i;
>>> -	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
>>> -						 hdmi->connector, mode);
>>> -
>>> -	len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
>>> -	if (len < 0) {
>>> +	if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
>>>    		DRM_DEV_ERROR(&hdmi->pdev->dev,
>>>    			"failed to configure avi infoframe\n");
>>> -		return;
>>> +		return -EINVAL;
>>>    	}
>>>    	/*
>>> @@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>>>    	 * written to the LSB byte of AVI_INFO0 and the version is written to
>>>    	 * the third byte from the LSB of AVI_INFO3
>>>    	 */
>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
>>> +	memcpy(buf, &buffer[3], len - 3);
>>> +
>>> +	buf[3] |= buffer[1] << 24;
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(buf); i++)
>>> +		hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
>>> +
>>> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>> +	val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
>>> +		HDMI_INFOFRAME_CTRL0_AVI_CONT;
>>> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>> +
>>> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>> +	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
>>> +	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
>>> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
>>> +					   const u8 *buffer, size_t len)
>>> +{
>>> +	u32 val;
>>> +
>>> +	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
>>> +		DRM_DEV_ERROR(&hdmi->pdev->dev,
>>> +			"failed to configure audio infoframe\n");
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
>>>    		   buffer[3] |
>>>    		   buffer[4] << 8 |
>>>    		   buffer[5] << 16 |
>>>    		   buffer[6] << 24);
>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
>>> +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
>>>    		   buffer[7] |
>>>    		   buffer[8] << 8 |
>>>    		   buffer[9] << 16 |
>>>    		   buffer[10] << 24);
>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
>>> -		   buffer[11] |
>>> -		   buffer[12] << 8 |
>>> -		   buffer[13] << 16 |
>>> -		   buffer[14] << 24);
>>> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>> +	val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
>>> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
>>> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
>>> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
>>> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
>>> +					   enum hdmi_infoframe_type type)
>>> +{
>>> +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>>> +	struct hdmi *hdmi = hdmi_bridge->hdmi;
>>> +	u32 val;
>>> +
>>> +	switch (type) {
>>> +	case HDMI_INFOFRAME_TYPE_AVI:
>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
>>> +		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
>>> +			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
>>> -		   buffer[15] |
>>> -		   buffer[16] << 8 |
>>> -		   buffer[1] << 24);
>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>> +		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
>>> -		   HDMI_INFOFRAME_CTRL0_AVI_SEND |
>>> -		   HDMI_INFOFRAME_CTRL0_AVI_CONT);
>>> +		break;
>>> -	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>> -	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
>>> -	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
>>> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
>>> +		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
>>> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
>>> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
>>> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>> +
>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>> +		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>> +
>>> +		break;
>>> +
>>> +	default:
>>> +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
>>> +					   enum hdmi_infoframe_type type,
>>> +					   const u8 *buffer, size_t len)
>>> +{
>>> +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>>> +	struct hdmi *hdmi = hdmi_bridge->hdmi;
>>> +
>>> +	msm_hdmi_bridge_clear_infoframe(bridge, type);
>>> +
>>> +	switch (type) {
>>> +	case HDMI_INFOFRAME_TYPE_AVI:
>>> +		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
>>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>>> +		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
>>> +	default:
>>> +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
>>> +		return 0;
>>> +	}
>>>    }
>>>    static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>> @@ -146,16 +223,16 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>>>    	conn_state = drm_atomic_get_new_connector_state(state, connector);
>>>    	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
>>> +	hdmi->pixclock = conn_state->hdmi.tmds_char_rate;
>>> +
>>>    	if (!hdmi->power_on) {
>>>    		msm_hdmi_phy_resource_enable(phy);
>>>    		msm_hdmi_power_on(bridge);
>>>    		hdmi->power_on = true;
>>> -		if (hdmi->hdmi_mode) {
>>> -			msm_hdmi_config_avi_infoframe(hdmi);
>>> -			msm_hdmi_audio_update(hdmi);
>>> -		}
>>>    	}
>>> +	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
>>> +
>>>    	msm_hdmi_phy_powerup(phy, hdmi->pixclock);
>>>    	msm_hdmi_set_mode(hdmi, true);
>>> @@ -184,8 +261,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
>>>    	if (hdmi->power_on) {
>>>    		power_off(bridge);
>>>    		hdmi->power_on = false;
>>> -		if (hdmi->hdmi_mode)
>>> -			msm_hdmi_audio_update(hdmi);
>>>    		msm_hdmi_phy_resource_disable(phy);
>>>    	}
>>>    }
>>> @@ -196,8 +271,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>>    	int hstart, hend, vstart, vend;
>>>    	uint32_t frame_ctrl;
>>> -	hdmi->pixclock = mode->clock * 1000;
>>> -
>>>    	hstart = mode->htotal - mode->hsync_start;
>>>    	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
>>> @@ -241,9 +314,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>>    		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
>>>    	DBG("frame_ctrl=%08x", frame_ctrl);
>>>    	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
>>> -
>>> -	if (hdmi->hdmi_mode)
>>> -		msm_hdmi_audio_update(hdmi);
>>>    }

Overall, I would like to know how the sequence was broken up:

HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND/CONT/UPDATE was moved from 
msm_hdmi_audio_update() to msm_hdmi_config_audio_infoframe() which is 
involed by drm_atomic_helper_connector_hdmi_update_infoframes() / 
drm_atomic_helper_connector_hdmi_clear_audio_infoframe().

But,HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND bit of 
REG_HDMI_AUDIO_PKT_CTRL1 remained in msm_hdmi_audio_update().

If this is correct, are we not missing msm_hdmi_audio_update() in some 
places like pre_enable() / post_disable()?

Was this done because those calls were anyway bailing out audio->enabled 
was not set by then?

This seems to be another change which could have been done by itself to 
drop those calls first and then make this change to make it more clear.

OR atleast please explain these things better in the commit text.

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

* Re: [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework
  2025-02-07 21:34       ` Abhinav Kumar
@ 2025-02-07 22:03         ` Dmitry Baryshkov
  2025-02-07 22:27           ` Abhinav Kumar
  0 siblings, 1 reply; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-02-07 22:03 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel

On Fri, Feb 07, 2025 at 01:34:35PM -0800, Abhinav Kumar wrote:
> 
> 
> On 2/3/2025 5:30 PM, Dmitry Baryshkov wrote:
> > On Mon, Feb 03, 2025 at 04:25:59PM -0800, Abhinav Kumar wrote:
> > > 
> > > 
> > > On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> > > > Setup the HDMI connector on the MSM HDMI outputs. Make use of
> > > > atomic_check hook and of the provided Infoframe infrastructure.
> > > > 
> > > 
> > > By atomic_check are you referring to the
> > > msm_hdmi_bridge_tmds_char_rate_valid()?
> > 
> > No, I mean drm_atomic_helper_connector_hdmi_check() being called from
> > drm_bridge_connector (inthe previous versions it was called from this
> > driver).
> > 
> 
> Ack.
> > > 
> > > Also please confirm if HDMI audio was re-tested with these changes.
> > 
> > Yes, although not the channels allocation for the multi-channel audio. I
> > don't have corresponding equipment. If you think that we should start
> > testing that, I will check if I can get the 6.1 or 8.1 receiver and the
> > speakers :-)
> > 
> 
> We should but I am fine with basic audio validation for now.
> 
> > > 
> > > > Acked-by: Maxime Ripard <mripard@kernel.org>
> > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > ---
> > > >    drivers/gpu/drm/msm/Kconfig            |   2 +
> > > >    drivers/gpu/drm/msm/hdmi/hdmi.c        |  45 ++-------
> > > >    drivers/gpu/drm/msm/hdmi/hdmi.h        |  16 +--
> > > >    drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  74 ++++----------
> > > >    drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 180 +++++++++++++++++++++++----------
> > > >    5 files changed, 162 insertions(+), 155 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
> > > > index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce9039d6f26f290d0 100644
> > > > --- a/drivers/gpu/drm/msm/Kconfig
> > > > +++ b/drivers/gpu/drm/msm/Kconfig
> > > > @@ -170,6 +170,8 @@ config DRM_MSM_HDMI
> > > >    	bool "Enable HDMI support in MSM DRM driver"
> > > >    	depends on DRM_MSM
> > > >    	default y
> > > > +	select DRM_DISPLAY_HDMI_HELPER
> > > > +	select DRM_DISPLAY_HDMI_STATE_HELPER
> > > >    	help
> > > >    	  Compile in support for the HDMI output MSM DRM driver. It can
> > > >    	  be a primary or a secondary display on device. Note that this is used
> > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > > > index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe9b69c0da594bd 100644
> > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > > > @@ -12,6 +12,7 @@
> > > >    #include <drm/drm_bridge_connector.h>
> > > >    #include <drm/drm_of.h>
> > > > +#include <drm/display/drm_hdmi_state_helper.h>
> > > >    #include <sound/hdmi-codec.h>
> > > >    #include "hdmi.h"
> > > > @@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
> > > >    	hdmi->dev = dev;
> > > >    	hdmi->encoder = encoder;
> > > > -	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
> > > > -
> > > >    	ret = msm_hdmi_bridge_init(hdmi);
> > > >    	if (ret) {
> > > >    		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
> > > > @@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
> > > >    				    struct hdmi_codec_params *params)
> > > >    {
> > > >    	struct hdmi *hdmi = dev_get_drvdata(dev);
> > > > -	unsigned int chan;
> > > > -	unsigned int channel_allocation = 0;
> > > >    	unsigned int rate;
> > > > -	unsigned int level_shift  = 0; /* 0dB */
> > > > -	bool down_mix = false;
> > > > +	int ret;
> > > >    	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
> > > >    		 params->sample_width, params->cea.channels);
> > > > -	switch (params->cea.channels) {
> > > > -	case 2:
> > > > -		/* FR and FL speakers */
> > > > -		channel_allocation  = 0;
> > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_2;
> > > > -		break;
> > > > -	case 4:
> > > > -		/* FC, LFE, FR and FL speakers */
> > > > -		channel_allocation  = 0x3;
> > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_4;
> > > > -		break;
> > > > -	case 6:
> > > > -		/* RR, RL, FC, LFE, FR and FL speakers */
> > > > -		channel_allocation  = 0x0B;
> > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_6;
> > > > -		break;
> > > > -	case 8:
> > > > -		/* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
> > > > -		channel_allocation  = 0x1F;
> > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_8;
> > > > -		break;
> > > > -	default:
> > > > -		return -EINVAL;
> > > > -	}
> > > 
> > > This mapping table was doing two things:
> > > 
> > > 1) drop the conversion of channels to an index to nchannels[] and use the
> > > channels directly. This part is fine but could have been a separate change
> > > by itself to show the redundancy.
> > > 
> > > 2) drop the mapping table of channels to channel_allocation.
> > > I am not fully sure of this. Was this done because
> > > hdmi_codec_channel_alloc[] table in hdmi-codec does this for us?
> > > hdmi_codec_get_ch_alloc_table_idx() uses channels and the flags to come up
> > > with the idx into this table. But it seems like current MSM HDMI code did
> > > not consider the flags. So for example, it seems like for 6 channels, we
> > > could return any of the below based on the flags but MSM HDMI always used
> > > 0x0B so will the values match?
> > 
> > Do they have to match? The correct value is being calculated by the HDMI
> > code in ASoC and then being written into the Audio InfoFrame. If the MSM
> > HDMI code wasn't taking ELD data into account, then it's a bug. But... I
> > don't think it's worth spending too much time on fixing it separately.
> > 
> 
> Its a change in values which are passed to the audio infoframe but I dont
> know if it will change the behavior of what has been working so far (I hope
> not).
> 
> I agree, that msm hdmi driver not considering the flags in the mask is a bug
> so for that reason, we should use the channels and channel allocation
> supplied to us by hdmi_codec.
> 
> If it does result in an issue (due to it incorrectly working today), we will
> atleast know where to look at.
> 
> Some more questions below.

Ack

> 
> > In the end, that is exactly the purpose of the frameworks - to make code
> > error prone and to remove the need to reimplement same things over and
> > over again, making differnt kinds of mistakes. For example, MSM HDMI
> > code also doesn't implement plugged_cb support. It doesn't provide ELD
> > to the HDMI codec code, etc. All of that is being fixed by using the
> > framework. It's not worth implementing those functions in the MSM HDMI
> > code first only to drop them in the next commit.
> > 
> > > 
> > > 202 	{ .ca_id = 0x0b, .n_ch = 6,
> > > 203 	  .mask = FL | FR | LFE | FC | RL | RR},
> > > 204 	/* surround40 */
> > > 205 	{ .ca_id = 0x08, .n_ch = 6,
> > > 206 	  .mask = FL | FR | RL | RR },
> > > 207 	/* surround41 */
> > > 208 	{ .ca_id = 0x09, .n_ch = 6,
> > > 209 	  .mask = FL | FR | LFE | RL | RR },
> > > 210 	/* surround50 */
> > > 211 	{ .ca_id = 0x0a, .n_ch = 6,
> > > 212 	  .mask = FL | FR | FC | RL | RR },
> > > 213 	/* 6.1 */
> > > 
> > > 
> > > > -
> > > >    	switch (params->sample_rate) {
> > > >    	case 32000:
> > > >    		rate = HDMI_SAMPLE_RATE_32KHZ;
> > > > @@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
> > > >    		return -EINVAL;
> > > >    	}
> > > > -	msm_hdmi_audio_set_sample_rate(hdmi, rate);
> > > > -	msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
> > > > -			      level_shift, down_mix);
> > > > +	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
> > > > +								      &params->cea);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
> > > >    	return 0;
> > > >    }
> > > > @@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
> > > >    {
> > > >    	struct hdmi *hdmi = dev_get_drvdata(dev);
> > > > -	msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
> > > > +	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
> > > > +	msm_hdmi_audio_disable(hdmi);
> > > >    }
> > > >    static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
> > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> > > > index a62d2aedfbb7239d37c826c4f96762f100a2be4a..53b52351d0eddf4a5c87a5290016bb53ed4d29f7 100644
> > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> > > > @@ -24,8 +24,8 @@ struct hdmi_platform_config;
> > > >    struct hdmi_audio {
> > > >    	bool enabled;
> > > > -	struct hdmi_audio_infoframe infoframe;
> > > >    	int rate;
> > > > +	int channels;
> > > >    };
> > > >    struct hdmi_hdcp_ctrl;
> > > > @@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
> > > >    /*
> > > >     * audio:
> > > >     */
> > > > -/* Supported HDMI Audio channels and rates */
> > > > -#define	MSM_HDMI_AUDIO_CHANNEL_2	0
> > > > -#define	MSM_HDMI_AUDIO_CHANNEL_4	1
> > > > -#define	MSM_HDMI_AUDIO_CHANNEL_6	2
> > > > -#define	MSM_HDMI_AUDIO_CHANNEL_8	3
> > > > -
> > > >    #define	HDMI_SAMPLE_RATE_32KHZ		0
> > > >    #define	HDMI_SAMPLE_RATE_44_1KHZ	1
> > > >    #define	HDMI_SAMPLE_RATE_48KHZ		2
> > > > @@ -221,12 +215,8 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
> > > >    #define	HDMI_SAMPLE_RATE_176_4KHZ	5
> > > >    #define	HDMI_SAMPLE_RATE_192KHZ		6
> > > > -int msm_hdmi_audio_update(struct hdmi *hdmi);
> > > > -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> > > > -	uint32_t num_of_channels, uint32_t channel_allocation,
> > > > -	uint32_t level_shift, bool down_mix);
> > > > -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
> > > > -
> > > > +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
> > > > +int msm_hdmi_audio_disable(struct hdmi *hdmi);
> > > >    /*
> > > >     * hdmi bridge:
> > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > > > index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..924654bfb48cf17feadea1c0661ee6ee4e1b4589 100644
> > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > > > @@ -7,9 +7,6 @@
> > > >    #include <linux/hdmi.h>
> > > >    #include "hdmi.h"
> > > > -/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
> > > > -static int nchannels[] = { 2, 4, 6, 8 };
> > > > -
> > > >    /* Supported HDMI Audio sample rates */
> > > >    #define MSM_HDMI_SAMPLE_RATE_32KHZ		0
> > > >    #define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1
> > > > @@ -71,19 +68,20 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
> > > >    	return NULL;
> > > >    }
> > > > -int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > +static int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > >    {
> > > >    	struct hdmi_audio *audio = &hdmi->audio;
> > > > -	struct hdmi_audio_infoframe *info = &audio->infoframe;
> > > >    	const struct hdmi_msm_audio_arcs *arcs = NULL;
> > > >    	bool enabled = audio->enabled;
> > > >    	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
> > > > -	uint32_t infofrm_ctrl, audio_config;
> > > > +	uint32_t audio_config;
> > > > +
> > > > +	if (!hdmi->connector->display_info.is_hdmi)
> > > > +		return -EINVAL;
> > > > +
> > > > +	DBG("audio: enabled=%d, channels=%d, rate=%d",
> > > > +	    audio->enabled, audio->channels, audio->rate);
> > > > -	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
> > > > -		"level_shift_value=%d, downmix_inhibit=%d, rate=%d",
> > > > -		audio->enabled, info->channels,  info->channel_allocation,
> > > > -		info->level_shift_value, info->downmix_inhibit, audio->rate);
> > > >    	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
> > > >    	if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
> > > > @@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > >    	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
> > > >    	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
> > > >    	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
> > > > -	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > > >    	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
> > > >    	/* Clear N/CTS selection bits */
> > > > @@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > >    	if (enabled) {
> > > >    		uint32_t n, cts, multiplier;
> > > >    		enum hdmi_acr_cts select;
> > > > -		uint8_t buf[14];
> > > >    		n   = arcs->lut[audio->rate].n;
> > > >    		cts = arcs->lut[audio->rate].cts;
> > > > @@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > >    				HDMI_ACR_1_N(n));
> > > >    		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
> > > > -				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
> > > > +				COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
> > > >    				HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
> > > >    		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
> > > >    		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
> > > > -		/* configure infoframe: */
> > > > -		hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
> > > > -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
> > > > -				(buf[3] <<  0) | (buf[4] <<  8) |
> > > > -				(buf[5] << 16) | (buf[6] << 24));
> > > > -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
> > > > -				(buf[7] <<  0) | (buf[8] << 8));
> > > > -
> > > >    		hdmi_write(hdmi, REG_HDMI_GC, 0);
> > > >    		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
> > > > @@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > >    		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
> > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > > > -
> > > >    		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
> > > >    		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
> > > >    		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
> > > > @@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > >    		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
> > > >    		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
> > > >    		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
> > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > > >    		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
> > > >    	}
> > > >    	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
> > > >    	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
> > > >    	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
> > > > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
> > > >    	hdmi_write(hdmi, REG_HDMI_AUD_INT,
> > > >    			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
> > > > @@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > >    	return 0;
> > > >    }
> > > > -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> > > > -	uint32_t num_of_channels, uint32_t channel_allocation,
> > > > -	uint32_t level_shift, bool down_mix)
> > > > +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
> > > >    {
> > > > -	struct hdmi_audio *audio;
> > > > -
> > > >    	if (!hdmi)
> > > >    		return -ENXIO;
> > > > -	audio = &hdmi->audio;
> > > > -
> > > > -	if (num_of_channels >= ARRAY_SIZE(nchannels))
> > > > +	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
> > > >    		return -EINVAL;
> > > > -	audio->enabled = enabled;
> > > > -	audio->infoframe.channels = nchannels[num_of_channels];
> > > > -	audio->infoframe.channel_allocation = channel_allocation;
> > > > -	audio->infoframe.level_shift_value = level_shift;
> > > > -	audio->infoframe.downmix_inhibit = down_mix;
> > > > +	hdmi->audio.rate = rate;
> > > > +	hdmi->audio.channels = channels;
> > > > +	hdmi->audio.enabled = true;
> > > >    	return msm_hdmi_audio_update(hdmi);
> > > >    }
> > > > -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
> > > > +int msm_hdmi_audio_disable(struct hdmi *hdmi)
> > > >    {
> > > > -	struct hdmi_audio *audio;
> > > > -
> > > >    	if (!hdmi)
> > > > -		return;
> > > > -
> > > > -	audio = &hdmi->audio;
> > > > +		return -ENXIO;
> > > > -	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
> > > > -		return;
> > > > +	hdmi->audio.rate = 0;
> > > > +	hdmi->audio.channels = 2;
> > > > +	hdmi->audio.enabled = false;
> > > > -	audio->rate = rate;
> > > > -	msm_hdmi_audio_update(hdmi);
> > > > +	return msm_hdmi_audio_update(hdmi);
> > > >    }
> > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > index d5ab1f74c0e6f47dc59872c016104e9a84d85e9e..168b4104e705e8217f5d7ca5f902d7557c55ae24 100644
> > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > @@ -7,6 +7,8 @@
> > > >    #include <linux/delay.h>
> > > >    #include <drm/drm_bridge_connector.h>
> > > >    #include <drm/drm_edid.h>
> > > > +#include <drm/display/drm_hdmi_helper.h>
> > > > +#include <drm/display/drm_hdmi_state_helper.h>
> > > >    #include "msm_kms.h"
> > > >    #include "hdmi.h"
> > > > @@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge)
> > > >    #define AVI_IFRAME_LINE_NUMBER 1
> > > > -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> > > > +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
> > > > +					 const u8 *buffer, size_t len)
> > > >    {
> > > > -	struct drm_crtc *crtc = hdmi->encoder->crtc;
> > > > -	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> > > > -	union hdmi_infoframe frame;
> > > > -	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
> > > > +	u32 buf[4] = {};
> > > >    	u32 val;
> > > > -	int len;
> > > > +	int i;
> > > > -	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
> > > > -						 hdmi->connector, mode);
> > > > -
> > > > -	len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
> > > > -	if (len < 0) {
> > > > +	if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
> > > >    		DRM_DEV_ERROR(&hdmi->pdev->dev,
> > > >    			"failed to configure avi infoframe\n");
> > > > -		return;
> > > > +		return -EINVAL;
> > > >    	}
> > > >    	/*
> > > > @@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> > > >    	 * written to the LSB byte of AVI_INFO0 and the version is written to
> > > >    	 * the third byte from the LSB of AVI_INFO3
> > > >    	 */
> > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
> > > > +	memcpy(buf, &buffer[3], len - 3);
> > > > +
> > > > +	buf[3] |= buffer[1] << 24;
> > > > +
> > > > +	for (i = 0; i < ARRAY_SIZE(buf); i++)
> > > > +		hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
> > > > +
> > > > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > +	val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > > > +		HDMI_INFOFRAME_CTRL0_AVI_CONT;
> > > > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > +
> > > > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > +	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > > > +	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> > > > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
> > > > +					   const u8 *buffer, size_t len)
> > > > +{
> > > > +	u32 val;
> > > > +
> > > > +	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
> > > > +		DRM_DEV_ERROR(&hdmi->pdev->dev,
> > > > +			"failed to configure audio infoframe\n");
> > > > +		return -EINVAL;
> > > > +	}
> > > > +
> > > > +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
> > > >    		   buffer[3] |
> > > >    		   buffer[4] << 8 |
> > > >    		   buffer[5] << 16 |
> > > >    		   buffer[6] << 24);
> > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
> > > > +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
> > > >    		   buffer[7] |
> > > >    		   buffer[8] << 8 |
> > > >    		   buffer[9] << 16 |
> > > >    		   buffer[10] << 24);
> > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
> > > > -		   buffer[11] |
> > > > -		   buffer[12] << 8 |
> > > > -		   buffer[13] << 16 |
> > > > -		   buffer[14] << 24);
> > > > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > +	val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> > > > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> > > > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> > > > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > > > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
> > > > +					   enum hdmi_infoframe_type type)
> > > > +{
> > > > +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > > > +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > > > +	u32 val;
> > > > +
> > > > +	switch (type) {
> > > > +	case HDMI_INFOFRAME_TYPE_AVI:
> > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > > > +		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > > > +			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
> > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
> > > > -		   buffer[15] |
> > > > -		   buffer[16] << 8 |
> > > > -		   buffer[1] << 24);
> > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > +		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
> > > > -		   HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > > > -		   HDMI_INFOFRAME_CTRL0_AVI_CONT);
> > > > +		break;
> > > > -	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > -	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > > > -	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> > > > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > > > +		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> > > > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> > > > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> > > > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
> > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > +
> > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > +		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
> > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > +
> > > > +		break;
> > > > +
> > > > +	default:
> > > > +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
> > > > +					   enum hdmi_infoframe_type type,
> > > > +					   const u8 *buffer, size_t len)
> > > > +{
> > > > +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > > > +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > > > +
> > > > +	msm_hdmi_bridge_clear_infoframe(bridge, type);
> > > > +
> > > > +	switch (type) {
> > > > +	case HDMI_INFOFRAME_TYPE_AVI:
> > > > +		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
> > > > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > > > +		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
> > > > +	default:
> > > > +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> > > > +		return 0;
> > > > +	}
> > > >    }
> > > >    static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > > @@ -146,16 +223,16 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> > > >    	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > > >    	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > > > +	hdmi->pixclock = conn_state->hdmi.tmds_char_rate;
> > > > +
> > > >    	if (!hdmi->power_on) {
> > > >    		msm_hdmi_phy_resource_enable(phy);
> > > >    		msm_hdmi_power_on(bridge);
> > > >    		hdmi->power_on = true;
> > > > -		if (hdmi->hdmi_mode) {
> > > > -			msm_hdmi_config_avi_infoframe(hdmi);
> > > > -			msm_hdmi_audio_update(hdmi);
> > > > -		}
> > > >    	}
> > > > +	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
> > > > +
> > > >    	msm_hdmi_phy_powerup(phy, hdmi->pixclock);
> > > >    	msm_hdmi_set_mode(hdmi, true);
> > > > @@ -184,8 +261,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> > > >    	if (hdmi->power_on) {
> > > >    		power_off(bridge);
> > > >    		hdmi->power_on = false;
> > > > -		if (hdmi->hdmi_mode)
> > > > -			msm_hdmi_audio_update(hdmi);
> > > >    		msm_hdmi_phy_resource_disable(phy);
> > > >    	}
> > > >    }
> > > > @@ -196,8 +271,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > >    	int hstart, hend, vstart, vend;
> > > >    	uint32_t frame_ctrl;
> > > > -	hdmi->pixclock = mode->clock * 1000;
> > > > -
> > > >    	hstart = mode->htotal - mode->hsync_start;
> > > >    	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
> > > > @@ -241,9 +314,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > >    		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
> > > >    	DBG("frame_ctrl=%08x", frame_ctrl);
> > > >    	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
> > > > -
> > > > -	if (hdmi->hdmi_mode)
> > > > -		msm_hdmi_audio_update(hdmi);
> > > >    }
> 
> Overall, I would like to know how the sequence was broken up:
> 
> HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND/CONT/UPDATE was moved from
> msm_hdmi_audio_update() to msm_hdmi_config_audio_infoframe() which is
> involed by drm_atomic_helper_connector_hdmi_update_infoframes() /
> drm_atomic_helper_connector_hdmi_clear_audio_infoframe().
> 
> But,HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND bit of REG_HDMI_AUDIO_PKT_CTRL1
> remained in msm_hdmi_audio_update().

This is correct, this bit controls sending of audio data, not the Audio
InfoFrame.

The strategy is very simple: Audio InfoFames are controlled centrally
via the DRM HDMI framework. Correct InfoFrame data is programmed at the
atomic_pre_enable() time (if it was set before) or during
msm_hdmi_bridge_audio_prepare() when the new stream is started.

All audio data frame management is deferred to
msm_hdmi_bridge_audio_prepare().

> If this is correct, are we not missing msm_hdmi_audio_update() in some
> places like pre_enable() / post_disable()?

drm_atomic_helper_connector_hdmi_update_infoframes() takes care of
writing all InfoFrames, including the Audio one.

> 
> Was this done because those calls were anyway bailing out audio->enabled was
> not set by then?
> 
> This seems to be another change which could have been done by itself to drop
> those calls first and then make this change to make it more clear.
> 
> OR atleast please explain these things better in the commit text.

If the above text is fine to you, I'll add it to the commit message.


-- 
With best wishes
Dmitry

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

* Re: [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable
  2025-02-07 20:11           ` Abhinav Kumar
@ 2025-02-07 22:07             ` Dmitry Baryshkov
  0 siblings, 0 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-02-07 22:07 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel

On Fri, Feb 07, 2025 at 12:11:55PM -0800, Abhinav Kumar wrote:
> 
> 
> On 2/6/2025 5:19 PM, Dmitry Baryshkov wrote:
> > On Thu, Feb 06, 2025 at 12:41:30PM -0800, Abhinav Kumar wrote:
> > > 
> > > 
> > > On 2/3/2025 4:59 PM, Dmitry Baryshkov wrote:
> > > > On Mon, Feb 03, 2025 at 11:34:00AM -0800, Abhinav Kumar wrote:
> > > > > 
> > > > > 
> > > > > On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> > > > > > The mode_set callback is deprecated, it doesn't get the
> > > > > > drm_bridge_state, just mode-related argumetns. Also Abhinav pointed out
> > > > > > that HDMI timings should be programmed after setting up HDMI PHY and
> > > > > > PLL. Rework the code to program HDMI timings at the end of
> > > > > > atomic_pre_enable().
> > > > > > 
> > > > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > ---
> > > > > >     drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 23 +++++++++++++++--------
> > > > > >     1 file changed, 15 insertions(+), 8 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > > > index d839c71091dcdc3b020fcbba8d698d58ee7fc749..d5ab1f74c0e6f47dc59872c016104e9a84d85e9e 100644
> > > > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > > > @@ -126,15 +126,26 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> > > > > >     	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > > >     }
> > > > > > +static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > > > > +					       const struct drm_display_mode *mode);
> > > > > >     static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> > > > > >     					      struct drm_bridge_state *old_bridge_state)
> > > > > >     {
> > > > > > +	struct drm_atomic_state *state = old_bridge_state->base.state;
> > > > > >     	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > > > > >     	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > > > > >     	struct hdmi_phy *phy = hdmi->phy;
> > > > > > +	struct drm_encoder *encoder = bridge->encoder;
> > > > > > +	struct drm_connector *connector;
> > > > > > +	struct drm_connector_state *conn_state;
> > > > > > +	struct drm_crtc_state *crtc_state;
> > > > > >     	DBG("power up");
> > > > > > +	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
> > > > > > +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > > > > > +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > > > > > +
> > > > > >     	if (!hdmi->power_on) {
> > > > > >     		msm_hdmi_phy_resource_enable(phy);
> > > > > >     		msm_hdmi_power_on(bridge);
> > > > > > @@ -151,6 +162,8 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> > > > > >     	if (hdmi->hdcp_ctrl)
> > > > > >     		msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
> > > > > > +
> > > > > > +	msm_hdmi_bridge_atomic_set_timings(hdmi, &crtc_state->adjusted_mode);
> > > > > >     }
> > > > > 
> > > > > This addresses my comment about setting up the HDMI timing registers before
> > > > > setting up the timing engine registers.
> > > > > 
> > > > > But prior to this change, mode_set was doing the same thing as
> > > > > msm_hdmi_bridge_atomic_set_timings() which means
> > > > > msm_hdmi_bridge_atomic_set_timings() should be called at the beginning of
> > > > > pre_enable()?
> > > > > 
> > > > > The controller is enabled in msm_hdmi_set_mode(). So this should be done
> > > > > before that.
> > > > 
> > > > In [1] you provided the following order:
> > > > 
> > > > 1) setup HDMI PHY and PLL
> > > > 2) setup HDMI video path correctly (HDMI timing registers)
> > > > 3) setup timing generator to match the HDMI video in (2)
> > > > 4) Enable timing engine
> > > > 
> > > > This means htat msm_hdmi_bridge_atomic_set_timings() should come at the
> > > > end of msm_hdmi_bridge_atomic_pre_enable(), not in the beginning /
> > > > middle of it.
> > > > 
> > > > [1] https://lore.kernel.org/dri-devel/8dd4a43e-d83c-1f36-21ff-61e13ff751e7@quicinc.com/
> > > > 
> > > 
> > > Sequence given is correct and is exactly what is given in the docs. What is
> > > somewhat not clear in the docs is the location of the enable of the HDMI
> > > controller. This is not there in the above 4 steps. I am referring to the
> > > enable bit being programmed in msm_hdmi_set_mode(). Ideally till we enable
> > > the timing engine, it should be okay but what I wanted to do was to keep the
> > > msm_hdmi_set_mode() as the last call in this function that way we program
> > > everything and then enable the controller.
> > > 
> > > This can be done in either way, move it to the beginning of the function or
> > > move it right before msm_hdmi_set_mode(). I had suggested beginning because
> > > thats how it was when things were still in mode_set.
> > 
> > Well.. following your description it might be better to put it after PHY
> > init. What do you think?
> > 
> 
> Are you referring to after msm_hdmi_phy_powerup()? Yes, thats fine too.

After doing several tests, this doesn't result in a stable enough
behaviour. I'll follow your recommendataion and call
msm_hdmi_bridge_atomic_set_timings() in the beginning of
msm_hdmi_bridge_atomic_pre_enable().

-- 
With best wishes
Dmitry

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

* Re: [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework
  2025-02-07 22:03         ` Dmitry Baryshkov
@ 2025-02-07 22:27           ` Abhinav Kumar
  2025-02-07 23:43             ` Dmitry Baryshkov
  0 siblings, 1 reply; 22+ messages in thread
From: Abhinav Kumar @ 2025-02-07 22:27 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel



On 2/7/2025 2:03 PM, Dmitry Baryshkov wrote:
> On Fri, Feb 07, 2025 at 01:34:35PM -0800, Abhinav Kumar wrote:
>>
>>
>> On 2/3/2025 5:30 PM, Dmitry Baryshkov wrote:
>>> On Mon, Feb 03, 2025 at 04:25:59PM -0800, Abhinav Kumar wrote:
>>>>
>>>>
>>>> On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
>>>>> Setup the HDMI connector on the MSM HDMI outputs. Make use of
>>>>> atomic_check hook and of the provided Infoframe infrastructure.
>>>>>
>>>>
>>>> By atomic_check are you referring to the
>>>> msm_hdmi_bridge_tmds_char_rate_valid()?
>>>
>>> No, I mean drm_atomic_helper_connector_hdmi_check() being called from
>>> drm_bridge_connector (inthe previous versions it was called from this
>>> driver).
>>>
>>
>> Ack.
>>>>
>>>> Also please confirm if HDMI audio was re-tested with these changes.
>>>
>>> Yes, although not the channels allocation for the multi-channel audio. I
>>> don't have corresponding equipment. If you think that we should start
>>> testing that, I will check if I can get the 6.1 or 8.1 receiver and the
>>> speakers :-)
>>>
>>
>> We should but I am fine with basic audio validation for now.
>>
>>>>
>>>>> Acked-by: Maxime Ripard <mripard@kernel.org>
>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>> ---
>>>>>     drivers/gpu/drm/msm/Kconfig            |   2 +
>>>>>     drivers/gpu/drm/msm/hdmi/hdmi.c        |  45 ++-------
>>>>>     drivers/gpu/drm/msm/hdmi/hdmi.h        |  16 +--
>>>>>     drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  74 ++++----------
>>>>>     drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 180 +++++++++++++++++++++++----------
>>>>>     5 files changed, 162 insertions(+), 155 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
>>>>> index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce9039d6f26f290d0 100644
>>>>> --- a/drivers/gpu/drm/msm/Kconfig
>>>>> +++ b/drivers/gpu/drm/msm/Kconfig
>>>>> @@ -170,6 +170,8 @@ config DRM_MSM_HDMI
>>>>>     	bool "Enable HDMI support in MSM DRM driver"
>>>>>     	depends on DRM_MSM
>>>>>     	default y
>>>>> +	select DRM_DISPLAY_HDMI_HELPER
>>>>> +	select DRM_DISPLAY_HDMI_STATE_HELPER
>>>>>     	help
>>>>>     	  Compile in support for the HDMI output MSM DRM driver. It can
>>>>>     	  be a primary or a secondary display on device. Note that this is used
>>>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
>>>>> index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe9b69c0da594bd 100644
>>>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
>>>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
>>>>> @@ -12,6 +12,7 @@
>>>>>     #include <drm/drm_bridge_connector.h>
>>>>>     #include <drm/drm_of.h>
>>>>> +#include <drm/display/drm_hdmi_state_helper.h>
>>>>>     #include <sound/hdmi-codec.h>
>>>>>     #include "hdmi.h"
>>>>> @@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
>>>>>     	hdmi->dev = dev;
>>>>>     	hdmi->encoder = encoder;
>>>>> -	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
>>>>> -
>>>>>     	ret = msm_hdmi_bridge_init(hdmi);
>>>>>     	if (ret) {
>>>>>     		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
>>>>> @@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
>>>>>     				    struct hdmi_codec_params *params)
>>>>>     {
>>>>>     	struct hdmi *hdmi = dev_get_drvdata(dev);
>>>>> -	unsigned int chan;
>>>>> -	unsigned int channel_allocation = 0;
>>>>>     	unsigned int rate;
>>>>> -	unsigned int level_shift  = 0; /* 0dB */
>>>>> -	bool down_mix = false;
>>>>> +	int ret;
>>>>>     	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
>>>>>     		 params->sample_width, params->cea.channels);
>>>>> -	switch (params->cea.channels) {
>>>>> -	case 2:
>>>>> -		/* FR and FL speakers */
>>>>> -		channel_allocation  = 0;
>>>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_2;
>>>>> -		break;
>>>>> -	case 4:
>>>>> -		/* FC, LFE, FR and FL speakers */
>>>>> -		channel_allocation  = 0x3;
>>>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_4;
>>>>> -		break;
>>>>> -	case 6:
>>>>> -		/* RR, RL, FC, LFE, FR and FL speakers */
>>>>> -		channel_allocation  = 0x0B;
>>>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_6;
>>>>> -		break;
>>>>> -	case 8:
>>>>> -		/* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
>>>>> -		channel_allocation  = 0x1F;
>>>>> -		chan = MSM_HDMI_AUDIO_CHANNEL_8;
>>>>> -		break;
>>>>> -	default:
>>>>> -		return -EINVAL;
>>>>> -	}
>>>>
>>>> This mapping table was doing two things:
>>>>
>>>> 1) drop the conversion of channels to an index to nchannels[] and use the
>>>> channels directly. This part is fine but could have been a separate change
>>>> by itself to show the redundancy.
>>>>
>>>> 2) drop the mapping table of channels to channel_allocation.
>>>> I am not fully sure of this. Was this done because
>>>> hdmi_codec_channel_alloc[] table in hdmi-codec does this for us?
>>>> hdmi_codec_get_ch_alloc_table_idx() uses channels and the flags to come up
>>>> with the idx into this table. But it seems like current MSM HDMI code did
>>>> not consider the flags. So for example, it seems like for 6 channels, we
>>>> could return any of the below based on the flags but MSM HDMI always used
>>>> 0x0B so will the values match?
>>>
>>> Do they have to match? The correct value is being calculated by the HDMI
>>> code in ASoC and then being written into the Audio InfoFrame. If the MSM
>>> HDMI code wasn't taking ELD data into account, then it's a bug. But... I
>>> don't think it's worth spending too much time on fixing it separately.
>>>
>>
>> Its a change in values which are passed to the audio infoframe but I dont
>> know if it will change the behavior of what has been working so far (I hope
>> not).
>>
>> I agree, that msm hdmi driver not considering the flags in the mask is a bug
>> so for that reason, we should use the channels and channel allocation
>> supplied to us by hdmi_codec.
>>
>> If it does result in an issue (due to it incorrectly working today), we will
>> atleast know where to look at.
>>
>> Some more questions below.
> 
> Ack
> 
>>
>>> In the end, that is exactly the purpose of the frameworks - to make code
>>> error prone and to remove the need to reimplement same things over and
>>> over again, making differnt kinds of mistakes. For example, MSM HDMI
>>> code also doesn't implement plugged_cb support. It doesn't provide ELD
>>> to the HDMI codec code, etc. All of that is being fixed by using the
>>> framework. It's not worth implementing those functions in the MSM HDMI
>>> code first only to drop them in the next commit.
>>>
>>>>
>>>> 202 	{ .ca_id = 0x0b, .n_ch = 6,
>>>> 203 	  .mask = FL | FR | LFE | FC | RL | RR},
>>>> 204 	/* surround40 */
>>>> 205 	{ .ca_id = 0x08, .n_ch = 6,
>>>> 206 	  .mask = FL | FR | RL | RR },
>>>> 207 	/* surround41 */
>>>> 208 	{ .ca_id = 0x09, .n_ch = 6,
>>>> 209 	  .mask = FL | FR | LFE | RL | RR },
>>>> 210 	/* surround50 */
>>>> 211 	{ .ca_id = 0x0a, .n_ch = 6,
>>>> 212 	  .mask = FL | FR | FC | RL | RR },
>>>> 213 	/* 6.1 */
>>>>
>>>>
>>>>> -
>>>>>     	switch (params->sample_rate) {
>>>>>     	case 32000:
>>>>>     		rate = HDMI_SAMPLE_RATE_32KHZ;
>>>>> @@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
>>>>>     		return -EINVAL;
>>>>>     	}
>>>>> -	msm_hdmi_audio_set_sample_rate(hdmi, rate);
>>>>> -	msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
>>>>> -			      level_shift, down_mix);
>>>>> +	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
>>>>> +								      &params->cea);
>>>>> +	if (ret)
>>>>> +		return ret;
>>>>> +
>>>>> +	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
>>>>>     	return 0;
>>>>>     }
>>>>> @@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
>>>>>     {
>>>>>     	struct hdmi *hdmi = dev_get_drvdata(dev);
>>>>> -	msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
>>>>> +	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
>>>>> +	msm_hdmi_audio_disable(hdmi);
>>>>>     }
>>>>>     static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
>>>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
>>>>> index a62d2aedfbb7239d37c826c4f96762f100a2be4a..53b52351d0eddf4a5c87a5290016bb53ed4d29f7 100644
>>>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
>>>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
>>>>> @@ -24,8 +24,8 @@ struct hdmi_platform_config;
>>>>>     struct hdmi_audio {
>>>>>     	bool enabled;
>>>>> -	struct hdmi_audio_infoframe infoframe;
>>>>>     	int rate;
>>>>> +	int channels;
>>>>>     };
>>>>>     struct hdmi_hdcp_ctrl;
>>>>> @@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
>>>>>     /*
>>>>>      * audio:
>>>>>      */
>>>>> -/* Supported HDMI Audio channels and rates */
>>>>> -#define	MSM_HDMI_AUDIO_CHANNEL_2	0
>>>>> -#define	MSM_HDMI_AUDIO_CHANNEL_4	1
>>>>> -#define	MSM_HDMI_AUDIO_CHANNEL_6	2
>>>>> -#define	MSM_HDMI_AUDIO_CHANNEL_8	3
>>>>> -
>>>>>     #define	HDMI_SAMPLE_RATE_32KHZ		0
>>>>>     #define	HDMI_SAMPLE_RATE_44_1KHZ	1
>>>>>     #define	HDMI_SAMPLE_RATE_48KHZ		2
>>>>> @@ -221,12 +215,8 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
>>>>>     #define	HDMI_SAMPLE_RATE_176_4KHZ	5
>>>>>     #define	HDMI_SAMPLE_RATE_192KHZ		6
>>>>> -int msm_hdmi_audio_update(struct hdmi *hdmi);
>>>>> -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
>>>>> -	uint32_t num_of_channels, uint32_t channel_allocation,
>>>>> -	uint32_t level_shift, bool down_mix);
>>>>> -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
>>>>> -
>>>>> +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
>>>>> +int msm_hdmi_audio_disable(struct hdmi *hdmi);
>>>>>     /*
>>>>>      * hdmi bridge:
>>>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
>>>>> index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..924654bfb48cf17feadea1c0661ee6ee4e1b4589 100644
>>>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
>>>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
>>>>> @@ -7,9 +7,6 @@
>>>>>     #include <linux/hdmi.h>
>>>>>     #include "hdmi.h"
>>>>> -/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
>>>>> -static int nchannels[] = { 2, 4, 6, 8 };
>>>>> -
>>>>>     /* Supported HDMI Audio sample rates */
>>>>>     #define MSM_HDMI_SAMPLE_RATE_32KHZ		0
>>>>>     #define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1
>>>>> @@ -71,19 +68,20 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
>>>>>     	return NULL;
>>>>>     }
>>>>> -int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>> +static int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>>     {
>>>>>     	struct hdmi_audio *audio = &hdmi->audio;
>>>>> -	struct hdmi_audio_infoframe *info = &audio->infoframe;
>>>>>     	const struct hdmi_msm_audio_arcs *arcs = NULL;
>>>>>     	bool enabled = audio->enabled;
>>>>>     	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
>>>>> -	uint32_t infofrm_ctrl, audio_config;
>>>>> +	uint32_t audio_config;
>>>>> +
>>>>> +	if (!hdmi->connector->display_info.is_hdmi)
>>>>> +		return -EINVAL;
>>>>> +
>>>>> +	DBG("audio: enabled=%d, channels=%d, rate=%d",
>>>>> +	    audio->enabled, audio->channels, audio->rate);
>>>>> -	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
>>>>> -		"level_shift_value=%d, downmix_inhibit=%d, rate=%d",
>>>>> -		audio->enabled, info->channels,  info->channel_allocation,
>>>>> -		info->level_shift_value, info->downmix_inhibit, audio->rate);
>>>>>     	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
>>>>>     	if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
>>>>> @@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>>     	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
>>>>>     	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
>>>>>     	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
>>>>> -	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
>>>>>     	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
>>>>>     	/* Clear N/CTS selection bits */
>>>>> @@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>>     	if (enabled) {
>>>>>     		uint32_t n, cts, multiplier;
>>>>>     		enum hdmi_acr_cts select;
>>>>> -		uint8_t buf[14];
>>>>>     		n   = arcs->lut[audio->rate].n;
>>>>>     		cts = arcs->lut[audio->rate].cts;
>>>>> @@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>>     				HDMI_ACR_1_N(n));
>>>>>     		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
>>>>> -				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
>>>>> +				COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
>>>>>     				HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
>>>>>     		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
>>>>>     		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
>>>>> -		/* configure infoframe: */
>>>>> -		hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
>>>>> -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
>>>>> -				(buf[3] <<  0) | (buf[4] <<  8) |
>>>>> -				(buf[5] << 16) | (buf[6] << 24));
>>>>> -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
>>>>> -				(buf[7] <<  0) | (buf[8] << 8));
>>>>> -
>>>>>     		hdmi_write(hdmi, REG_HDMI_GC, 0);
>>>>>     		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
>>>>> @@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>>     		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
>>>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
>>>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
>>>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
>>>>> -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
>>>>> -
>>>>>     		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
>>>>>     		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
>>>>>     		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
>>>>> @@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>>     		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
>>>>>     		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
>>>>>     		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
>>>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
>>>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
>>>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
>>>>> -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
>>>>>     		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
>>>>>     	}
>>>>>     	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
>>>>>     	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
>>>>>     	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
>>>>> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
>>>>>     	hdmi_write(hdmi, REG_HDMI_AUD_INT,
>>>>>     			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
>>>>> @@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
>>>>>     	return 0;
>>>>>     }
>>>>> -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
>>>>> -	uint32_t num_of_channels, uint32_t channel_allocation,
>>>>> -	uint32_t level_shift, bool down_mix)
>>>>> +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
>>>>>     {
>>>>> -	struct hdmi_audio *audio;
>>>>> -
>>>>>     	if (!hdmi)
>>>>>     		return -ENXIO;
>>>>> -	audio = &hdmi->audio;
>>>>> -
>>>>> -	if (num_of_channels >= ARRAY_SIZE(nchannels))
>>>>> +	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
>>>>>     		return -EINVAL;
>>>>> -	audio->enabled = enabled;
>>>>> -	audio->infoframe.channels = nchannels[num_of_channels];
>>>>> -	audio->infoframe.channel_allocation = channel_allocation;
>>>>> -	audio->infoframe.level_shift_value = level_shift;
>>>>> -	audio->infoframe.downmix_inhibit = down_mix;
>>>>> +	hdmi->audio.rate = rate;
>>>>> +	hdmi->audio.channels = channels;
>>>>> +	hdmi->audio.enabled = true;
>>>>>     	return msm_hdmi_audio_update(hdmi);
>>>>>     }
>>>>> -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
>>>>> +int msm_hdmi_audio_disable(struct hdmi *hdmi)
>>>>>     {
>>>>> -	struct hdmi_audio *audio;
>>>>> -
>>>>>     	if (!hdmi)
>>>>> -		return;
>>>>> -
>>>>> -	audio = &hdmi->audio;
>>>>> +		return -ENXIO;
>>>>> -	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
>>>>> -		return;
>>>>> +	hdmi->audio.rate = 0;
>>>>> +	hdmi->audio.channels = 2;
>>>>> +	hdmi->audio.enabled = false;
>>>>> -	audio->rate = rate;
>>>>> -	msm_hdmi_audio_update(hdmi);
>>>>> +	return msm_hdmi_audio_update(hdmi);
>>>>>     }
>>>>> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>>>> index d5ab1f74c0e6f47dc59872c016104e9a84d85e9e..168b4104e705e8217f5d7ca5f902d7557c55ae24 100644
>>>>> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>>>> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
>>>>> @@ -7,6 +7,8 @@
>>>>>     #include <linux/delay.h>
>>>>>     #include <drm/drm_bridge_connector.h>
>>>>>     #include <drm/drm_edid.h>
>>>>> +#include <drm/display/drm_hdmi_helper.h>
>>>>> +#include <drm/display/drm_hdmi_state_helper.h>
>>>>>     #include "msm_kms.h"
>>>>>     #include "hdmi.h"
>>>>> @@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge)
>>>>>     #define AVI_IFRAME_LINE_NUMBER 1
>>>>> -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>>>>> +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
>>>>> +					 const u8 *buffer, size_t len)
>>>>>     {
>>>>> -	struct drm_crtc *crtc = hdmi->encoder->crtc;
>>>>> -	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
>>>>> -	union hdmi_infoframe frame;
>>>>> -	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
>>>>> +	u32 buf[4] = {};
>>>>>     	u32 val;
>>>>> -	int len;
>>>>> +	int i;
>>>>> -	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
>>>>> -						 hdmi->connector, mode);
>>>>> -
>>>>> -	len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
>>>>> -	if (len < 0) {
>>>>> +	if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
>>>>>     		DRM_DEV_ERROR(&hdmi->pdev->dev,
>>>>>     			"failed to configure avi infoframe\n");
>>>>> -		return;
>>>>> +		return -EINVAL;
>>>>>     	}
>>>>>     	/*
>>>>> @@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
>>>>>     	 * written to the LSB byte of AVI_INFO0 and the version is written to
>>>>>     	 * the third byte from the LSB of AVI_INFO3
>>>>>     	 */
>>>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
>>>>> +	memcpy(buf, &buffer[3], len - 3);
>>>>> +
>>>>> +	buf[3] |= buffer[1] << 24;
>>>>> +
>>>>> +	for (i = 0; i < ARRAY_SIZE(buf); i++)
>>>>> +		hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
>>>>> +
>>>>> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>>>> +	val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
>>>>> +		HDMI_INFOFRAME_CTRL0_AVI_CONT;
>>>>> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>>>> +
>>>>> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>>>> +	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
>>>>> +	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
>>>>> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
>>>>> +					   const u8 *buffer, size_t len)
>>>>> +{
>>>>> +	u32 val;
>>>>> +
>>>>> +	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
>>>>> +		DRM_DEV_ERROR(&hdmi->pdev->dev,
>>>>> +			"failed to configure audio infoframe\n");
>>>>> +		return -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
>>>>>     		   buffer[3] |
>>>>>     		   buffer[4] << 8 |
>>>>>     		   buffer[5] << 16 |
>>>>>     		   buffer[6] << 24);
>>>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
>>>>> +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
>>>>>     		   buffer[7] |
>>>>>     		   buffer[8] << 8 |
>>>>>     		   buffer[9] << 16 |
>>>>>     		   buffer[10] << 24);
>>>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
>>>>> -		   buffer[11] |
>>>>> -		   buffer[12] << 8 |
>>>>> -		   buffer[13] << 16 |
>>>>> -		   buffer[14] << 24);
>>>>> +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>>>> +	val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
>>>>> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
>>>>> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
>>>>> +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
>>>>> +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
>>>>> +					   enum hdmi_infoframe_type type)
>>>>> +{
>>>>> +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>>>>> +	struct hdmi *hdmi = hdmi_bridge->hdmi;
>>>>> +	u32 val;
>>>>> +
>>>>> +	switch (type) {
>>>>> +	case HDMI_INFOFRAME_TYPE_AVI:
>>>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
>>>>> +		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
>>>>> +			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
>>>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>>>> -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
>>>>> -		   buffer[15] |
>>>>> -		   buffer[16] << 8 |
>>>>> -		   buffer[1] << 24);
>>>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>>>> +		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
>>>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>>>> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
>>>>> -		   HDMI_INFOFRAME_CTRL0_AVI_SEND |
>>>>> -		   HDMI_INFOFRAME_CTRL0_AVI_CONT);
>>>>> +		break;
>>>>> -	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>>>> -	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
>>>>> -	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
>>>>> -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>>>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>>>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
>>>>> +		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
>>>>> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
>>>>> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
>>>>> +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
>>>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
>>>>> +
>>>>> +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
>>>>> +		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
>>>>> +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
>>>>> +
>>>>> +		break;
>>>>> +
>>>>> +	default:
>>>>> +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
>>>>> +	}
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
>>>>> +					   enum hdmi_infoframe_type type,
>>>>> +					   const u8 *buffer, size_t len)
>>>>> +{
>>>>> +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
>>>>> +	struct hdmi *hdmi = hdmi_bridge->hdmi;
>>>>> +
>>>>> +	msm_hdmi_bridge_clear_infoframe(bridge, type);
>>>>> +
>>>>> +	switch (type) {
>>>>> +	case HDMI_INFOFRAME_TYPE_AVI:
>>>>> +		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
>>>>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>>>>> +		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
>>>>> +	default:
>>>>> +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
>>>>> +		return 0;
>>>>> +	}
>>>>>     }
>>>>>     static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>>>> @@ -146,16 +223,16 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
>>>>>     	conn_state = drm_atomic_get_new_connector_state(state, connector);
>>>>>     	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
>>>>> +	hdmi->pixclock = conn_state->hdmi.tmds_char_rate;
>>>>> +
>>>>>     	if (!hdmi->power_on) {
>>>>>     		msm_hdmi_phy_resource_enable(phy);
>>>>>     		msm_hdmi_power_on(bridge);
>>>>>     		hdmi->power_on = true;
>>>>> -		if (hdmi->hdmi_mode) {
>>>>> -			msm_hdmi_config_avi_infoframe(hdmi);
>>>>> -			msm_hdmi_audio_update(hdmi);
>>>>> -		}
>>>>>     	}
>>>>> +	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
>>>>> +
>>>>>     	msm_hdmi_phy_powerup(phy, hdmi->pixclock);
>>>>>     	msm_hdmi_set_mode(hdmi, true);
>>>>> @@ -184,8 +261,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
>>>>>     	if (hdmi->power_on) {
>>>>>     		power_off(bridge);
>>>>>     		hdmi->power_on = false;
>>>>> -		if (hdmi->hdmi_mode)
>>>>> -			msm_hdmi_audio_update(hdmi);
>>>>>     		msm_hdmi_phy_resource_disable(phy);
>>>>>     	}
>>>>>     }
>>>>> @@ -196,8 +271,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>>>>     	int hstart, hend, vstart, vend;
>>>>>     	uint32_t frame_ctrl;
>>>>> -	hdmi->pixclock = mode->clock * 1000;
>>>>> -
>>>>>     	hstart = mode->htotal - mode->hsync_start;
>>>>>     	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
>>>>> @@ -241,9 +314,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
>>>>>     		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
>>>>>     	DBG("frame_ctrl=%08x", frame_ctrl);
>>>>>     	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
>>>>> -
>>>>> -	if (hdmi->hdmi_mode)
>>>>> -		msm_hdmi_audio_update(hdmi);
>>>>>     }
>>
>> Overall, I would like to know how the sequence was broken up:
>>
>> HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND/CONT/UPDATE was moved from
>> msm_hdmi_audio_update() to msm_hdmi_config_audio_infoframe() which is
>> involed by drm_atomic_helper_connector_hdmi_update_infoframes() /
>> drm_atomic_helper_connector_hdmi_clear_audio_infoframe().
>>
>> But,HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND bit of REG_HDMI_AUDIO_PKT_CTRL1
>> remained in msm_hdmi_audio_update().
> 
> This is correct, this bit controls sending of audio data, not the Audio
> InfoFrame.
> 
> The strategy is very simple: Audio InfoFames are controlled centrally
> via the DRM HDMI framework. Correct InfoFrame data is programmed at the
> atomic_pre_enable() time (if it was set before) or during
> msm_hdmi_bridge_audio_prepare() when the new stream is started.
> 
> All audio data frame management is deferred to
> msm_hdmi_bridge_audio_prepare().
> 

Thats in the last patch of the series not this one. But I understand the 
split.

>> If this is correct, are we not missing msm_hdmi_audio_update() in some
>> places like pre_enable() / post_disable()?
> 
> drm_atomic_helper_connector_hdmi_update_infoframes() takes care of
> writing all InfoFrames, including the Audio one.
> 
>>
>> Was this done because those calls were anyway bailing out audio->enabled was
>> not set by then?
>>
>> This seems to be another change which could have been done by itself to drop
>> those calls first and then make this change to make it more clear.
>>
>> OR atleast please explain these things better in the commit text.
> 
> If the above text is fine to you, I'll add it to the commit message.
> 

This is fine, but the dropping of msm_hdmi_audio_update() from 
msm_hdmi_bridge_atomic_pre_enable() seems unrelated to the split OR 
using the DRM HDMI framework. It seems more because that call by itself 
without audio->enabled which is set in msm_hdmi_audio_info_setup() will 
not do anything.

So this is actually an independent fix and was just combined with this 
change? Thats the part I am trying to be more explicit about.

> 


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

* Re: [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework
  2025-02-07 22:27           ` Abhinav Kumar
@ 2025-02-07 23:43             ` Dmitry Baryshkov
  0 siblings, 0 replies; 22+ messages in thread
From: Dmitry Baryshkov @ 2025-02-07 23:43 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Rob Clark, Sean Paul,
	Marijn Suijten, Simona Vetter, Simona Vetter, dri-devel,
	linux-arm-msm, freedreno, linux-kernel

On Fri, Feb 07, 2025 at 02:27:41PM -0800, Abhinav Kumar wrote:
> 
> 
> On 2/7/2025 2:03 PM, Dmitry Baryshkov wrote:
> > On Fri, Feb 07, 2025 at 01:34:35PM -0800, Abhinav Kumar wrote:
> > > 
> > > 
> > > On 2/3/2025 5:30 PM, Dmitry Baryshkov wrote:
> > > > On Mon, Feb 03, 2025 at 04:25:59PM -0800, Abhinav Kumar wrote:
> > > > > 
> > > > > 
> > > > > On 1/24/2025 1:47 PM, Dmitry Baryshkov wrote:
> > > > > > Setup the HDMI connector on the MSM HDMI outputs. Make use of
> > > > > > atomic_check hook and of the provided Infoframe infrastructure.
> > > > > > 
> > > > > 
> > > > > By atomic_check are you referring to the
> > > > > msm_hdmi_bridge_tmds_char_rate_valid()?
> > > > 
> > > > No, I mean drm_atomic_helper_connector_hdmi_check() being called from
> > > > drm_bridge_connector (inthe previous versions it was called from this
> > > > driver).
> > > > 
> > > 
> > > Ack.
> > > > > 
> > > > > Also please confirm if HDMI audio was re-tested with these changes.
> > > > 
> > > > Yes, although not the channels allocation for the multi-channel audio. I
> > > > don't have corresponding equipment. If you think that we should start
> > > > testing that, I will check if I can get the 6.1 or 8.1 receiver and the
> > > > speakers :-)
> > > > 
> > > 
> > > We should but I am fine with basic audio validation for now.
> > > 
> > > > > 
> > > > > > Acked-by: Maxime Ripard <mripard@kernel.org>
> > > > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > ---
> > > > > >     drivers/gpu/drm/msm/Kconfig            |   2 +
> > > > > >     drivers/gpu/drm/msm/hdmi/hdmi.c        |  45 ++-------
> > > > > >     drivers/gpu/drm/msm/hdmi/hdmi.h        |  16 +--
> > > > > >     drivers/gpu/drm/msm/hdmi/hdmi_audio.c  |  74 ++++----------
> > > > > >     drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 180 +++++++++++++++++++++++----------
> > > > > >     5 files changed, 162 insertions(+), 155 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
> > > > > > index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce9039d6f26f290d0 100644
> > > > > > --- a/drivers/gpu/drm/msm/Kconfig
> > > > > > +++ b/drivers/gpu/drm/msm/Kconfig
> > > > > > @@ -170,6 +170,8 @@ config DRM_MSM_HDMI
> > > > > >     	bool "Enable HDMI support in MSM DRM driver"
> > > > > >     	depends on DRM_MSM
> > > > > >     	default y
> > > > > > +	select DRM_DISPLAY_HDMI_HELPER
> > > > > > +	select DRM_DISPLAY_HDMI_STATE_HELPER
> > > > > >     	help
> > > > > >     	  Compile in support for the HDMI output MSM DRM driver. It can
> > > > > >     	  be a primary or a secondary display on device. Note that this is used
> > > > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > > > > > index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe9b69c0da594bd 100644
> > > > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> > > > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > > > > > @@ -12,6 +12,7 @@
> > > > > >     #include <drm/drm_bridge_connector.h>
> > > > > >     #include <drm/drm_of.h>
> > > > > > +#include <drm/display/drm_hdmi_state_helper.h>
> > > > > >     #include <sound/hdmi-codec.h>
> > > > > >     #include "hdmi.h"
> > > > > > @@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
> > > > > >     	hdmi->dev = dev;
> > > > > >     	hdmi->encoder = encoder;
> > > > > > -	hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
> > > > > > -
> > > > > >     	ret = msm_hdmi_bridge_init(hdmi);
> > > > > >     	if (ret) {
> > > > > >     		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
> > > > > > @@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
> > > > > >     				    struct hdmi_codec_params *params)
> > > > > >     {
> > > > > >     	struct hdmi *hdmi = dev_get_drvdata(dev);
> > > > > > -	unsigned int chan;
> > > > > > -	unsigned int channel_allocation = 0;
> > > > > >     	unsigned int rate;
> > > > > > -	unsigned int level_shift  = 0; /* 0dB */
> > > > > > -	bool down_mix = false;
> > > > > > +	int ret;
> > > > > >     	DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
> > > > > >     		 params->sample_width, params->cea.channels);
> > > > > > -	switch (params->cea.channels) {
> > > > > > -	case 2:
> > > > > > -		/* FR and FL speakers */
> > > > > > -		channel_allocation  = 0;
> > > > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_2;
> > > > > > -		break;
> > > > > > -	case 4:
> > > > > > -		/* FC, LFE, FR and FL speakers */
> > > > > > -		channel_allocation  = 0x3;
> > > > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_4;
> > > > > > -		break;
> > > > > > -	case 6:
> > > > > > -		/* RR, RL, FC, LFE, FR and FL speakers */
> > > > > > -		channel_allocation  = 0x0B;
> > > > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_6;
> > > > > > -		break;
> > > > > > -	case 8:
> > > > > > -		/* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
> > > > > > -		channel_allocation  = 0x1F;
> > > > > > -		chan = MSM_HDMI_AUDIO_CHANNEL_8;
> > > > > > -		break;
> > > > > > -	default:
> > > > > > -		return -EINVAL;
> > > > > > -	}
> > > > > 
> > > > > This mapping table was doing two things:
> > > > > 
> > > > > 1) drop the conversion of channels to an index to nchannels[] and use the
> > > > > channels directly. This part is fine but could have been a separate change
> > > > > by itself to show the redundancy.
> > > > > 
> > > > > 2) drop the mapping table of channels to channel_allocation.
> > > > > I am not fully sure of this. Was this done because
> > > > > hdmi_codec_channel_alloc[] table in hdmi-codec does this for us?
> > > > > hdmi_codec_get_ch_alloc_table_idx() uses channels and the flags to come up
> > > > > with the idx into this table. But it seems like current MSM HDMI code did
> > > > > not consider the flags. So for example, it seems like for 6 channels, we
> > > > > could return any of the below based on the flags but MSM HDMI always used
> > > > > 0x0B so will the values match?
> > > > 
> > > > Do they have to match? The correct value is being calculated by the HDMI
> > > > code in ASoC and then being written into the Audio InfoFrame. If the MSM
> > > > HDMI code wasn't taking ELD data into account, then it's a bug. But... I
> > > > don't think it's worth spending too much time on fixing it separately.
> > > > 
> > > 
> > > Its a change in values which are passed to the audio infoframe but I dont
> > > know if it will change the behavior of what has been working so far (I hope
> > > not).
> > > 
> > > I agree, that msm hdmi driver not considering the flags in the mask is a bug
> > > so for that reason, we should use the channels and channel allocation
> > > supplied to us by hdmi_codec.
> > > 
> > > If it does result in an issue (due to it incorrectly working today), we will
> > > atleast know where to look at.
> > > 
> > > Some more questions below.
> > 
> > Ack
> > 
> > > 
> > > > In the end, that is exactly the purpose of the frameworks - to make code
> > > > error prone and to remove the need to reimplement same things over and
> > > > over again, making differnt kinds of mistakes. For example, MSM HDMI
> > > > code also doesn't implement plugged_cb support. It doesn't provide ELD
> > > > to the HDMI codec code, etc. All of that is being fixed by using the
> > > > framework. It's not worth implementing those functions in the MSM HDMI
> > > > code first only to drop them in the next commit.
> > > > 
> > > > > 
> > > > > 202 	{ .ca_id = 0x0b, .n_ch = 6,
> > > > > 203 	  .mask = FL | FR | LFE | FC | RL | RR},
> > > > > 204 	/* surround40 */
> > > > > 205 	{ .ca_id = 0x08, .n_ch = 6,
> > > > > 206 	  .mask = FL | FR | RL | RR },
> > > > > 207 	/* surround41 */
> > > > > 208 	{ .ca_id = 0x09, .n_ch = 6,
> > > > > 209 	  .mask = FL | FR | LFE | RL | RR },
> > > > > 210 	/* surround50 */
> > > > > 211 	{ .ca_id = 0x0a, .n_ch = 6,
> > > > > 212 	  .mask = FL | FR | FC | RL | RR },
> > > > > 213 	/* 6.1 */
> > > > > 
> > > > > 
> > > > > > -
> > > > > >     	switch (params->sample_rate) {
> > > > > >     	case 32000:
> > > > > >     		rate = HDMI_SAMPLE_RATE_32KHZ;
> > > > > > @@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev, void *data,
> > > > > >     		return -EINVAL;
> > > > > >     	}
> > > > > > -	msm_hdmi_audio_set_sample_rate(hdmi, rate);
> > > > > > -	msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
> > > > > > -			      level_shift, down_mix);
> > > > > > +	ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->connector,
> > > > > > +								      &params->cea);
> > > > > > +	if (ret)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels);
> > > > > >     	return 0;
> > > > > >     }
> > > > > > @@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev, void *data)
> > > > > >     {
> > > > > >     	struct hdmi *hdmi = dev_get_drvdata(dev);
> > > > > > -	msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
> > > > > > +	drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector);
> > > > > > +	msm_hdmi_audio_disable(hdmi);
> > > > > >     }
> > > > > >     static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
> > > > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> > > > > > index a62d2aedfbb7239d37c826c4f96762f100a2be4a..53b52351d0eddf4a5c87a5290016bb53ed4d29f7 100644
> > > > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> > > > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> > > > > > @@ -24,8 +24,8 @@ struct hdmi_platform_config;
> > > > > >     struct hdmi_audio {
> > > > > >     	bool enabled;
> > > > > > -	struct hdmi_audio_infoframe infoframe;
> > > > > >     	int rate;
> > > > > > +	int channels;
> > > > > >     };
> > > > > >     struct hdmi_hdcp_ctrl;
> > > > > > @@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
> > > > > >     /*
> > > > > >      * audio:
> > > > > >      */
> > > > > > -/* Supported HDMI Audio channels and rates */
> > > > > > -#define	MSM_HDMI_AUDIO_CHANNEL_2	0
> > > > > > -#define	MSM_HDMI_AUDIO_CHANNEL_4	1
> > > > > > -#define	MSM_HDMI_AUDIO_CHANNEL_6	2
> > > > > > -#define	MSM_HDMI_AUDIO_CHANNEL_8	3
> > > > > > -
> > > > > >     #define	HDMI_SAMPLE_RATE_32KHZ		0
> > > > > >     #define	HDMI_SAMPLE_RATE_44_1KHZ	1
> > > > > >     #define	HDMI_SAMPLE_RATE_48KHZ		2
> > > > > > @@ -221,12 +215,8 @@ static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev)
> > > > > >     #define	HDMI_SAMPLE_RATE_176_4KHZ	5
> > > > > >     #define	HDMI_SAMPLE_RATE_192KHZ		6
> > > > > > -int msm_hdmi_audio_update(struct hdmi *hdmi);
> > > > > > -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> > > > > > -	uint32_t num_of_channels, uint32_t channel_allocation,
> > > > > > -	uint32_t level_shift, bool down_mix);
> > > > > > -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
> > > > > > -
> > > > > > +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels);
> > > > > > +int msm_hdmi_audio_disable(struct hdmi *hdmi);
> > > > > >     /*
> > > > > >      * hdmi bridge:
> > > > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > > > > > index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..924654bfb48cf17feadea1c0661ee6ee4e1b4589 100644
> > > > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > > > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
> > > > > > @@ -7,9 +7,6 @@
> > > > > >     #include <linux/hdmi.h>
> > > > > >     #include "hdmi.h"
> > > > > > -/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
> > > > > > -static int nchannels[] = { 2, 4, 6, 8 };
> > > > > > -
> > > > > >     /* Supported HDMI Audio sample rates */
> > > > > >     #define MSM_HDMI_SAMPLE_RATE_32KHZ		0
> > > > > >     #define MSM_HDMI_SAMPLE_RATE_44_1KHZ		1
> > > > > > @@ -71,19 +68,20 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
> > > > > >     	return NULL;
> > > > > >     }
> > > > > > -int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > > +static int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > >     {
> > > > > >     	struct hdmi_audio *audio = &hdmi->audio;
> > > > > > -	struct hdmi_audio_infoframe *info = &audio->infoframe;
> > > > > >     	const struct hdmi_msm_audio_arcs *arcs = NULL;
> > > > > >     	bool enabled = audio->enabled;
> > > > > >     	uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
> > > > > > -	uint32_t infofrm_ctrl, audio_config;
> > > > > > +	uint32_t audio_config;
> > > > > > +
> > > > > > +	if (!hdmi->connector->display_info.is_hdmi)
> > > > > > +		return -EINVAL;
> > > > > > +
> > > > > > +	DBG("audio: enabled=%d, channels=%d, rate=%d",
> > > > > > +	    audio->enabled, audio->channels, audio->rate);
> > > > > > -	DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
> > > > > > -		"level_shift_value=%d, downmix_inhibit=%d, rate=%d",
> > > > > > -		audio->enabled, info->channels,  info->channel_allocation,
> > > > > > -		info->level_shift_value, info->downmix_inhibit, audio->rate);
> > > > > >     	DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
> > > > > >     	if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
> > > > > > @@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > >     	acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
> > > > > >     	vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
> > > > > >     	aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
> > > > > > -	infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > > > > >     	audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
> > > > > >     	/* Clear N/CTS selection bits */
> > > > > > @@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > >     	if (enabled) {
> > > > > >     		uint32_t n, cts, multiplier;
> > > > > >     		enum hdmi_acr_cts select;
> > > > > > -		uint8_t buf[14];
> > > > > >     		n   = arcs->lut[audio->rate].n;
> > > > > >     		cts = arcs->lut[audio->rate].cts;
> > > > > > @@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > >     				HDMI_ACR_1_N(n));
> > > > > >     		hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
> > > > > > -				COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
> > > > > > +				COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
> > > > > >     				HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
> > > > > >     		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
> > > > > >     		acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
> > > > > > -		/* configure infoframe: */
> > > > > > -		hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
> > > > > > -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
> > > > > > -				(buf[3] <<  0) | (buf[4] <<  8) |
> > > > > > -				(buf[5] << 16) | (buf[6] << 24));
> > > > > > -		hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
> > > > > > -				(buf[7] <<  0) | (buf[8] << 8));
> > > > > > -
> > > > > >     		hdmi_write(hdmi, REG_HDMI_GC, 0);
> > > > > >     		vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
> > > > > > @@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > >     		aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
> > > > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> > > > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> > > > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> > > > > > -		infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > > > > > -
> > > > > >     		audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
> > > > > >     		audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
> > > > > >     		audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
> > > > > > @@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > >     		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
> > > > > >     		vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
> > > > > >     		aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
> > > > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
> > > > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
> > > > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
> > > > > > -		infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > > > > >     		audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
> > > > > >     	}
> > > > > >     	hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
> > > > > >     	hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
> > > > > >     	hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
> > > > > > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
> > > > > >     	hdmi_write(hdmi, REG_HDMI_AUD_INT,
> > > > > >     			COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
> > > > > > @@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi)
> > > > > >     	return 0;
> > > > > >     }
> > > > > > -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
> > > > > > -	uint32_t num_of_channels, uint32_t channel_allocation,
> > > > > > -	uint32_t level_shift, bool down_mix)
> > > > > > +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels)
> > > > > >     {
> > > > > > -	struct hdmi_audio *audio;
> > > > > > -
> > > > > >     	if (!hdmi)
> > > > > >     		return -ENXIO;
> > > > > > -	audio = &hdmi->audio;
> > > > > > -
> > > > > > -	if (num_of_channels >= ARRAY_SIZE(nchannels))
> > > > > > +	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
> > > > > >     		return -EINVAL;
> > > > > > -	audio->enabled = enabled;
> > > > > > -	audio->infoframe.channels = nchannels[num_of_channels];
> > > > > > -	audio->infoframe.channel_allocation = channel_allocation;
> > > > > > -	audio->infoframe.level_shift_value = level_shift;
> > > > > > -	audio->infoframe.downmix_inhibit = down_mix;
> > > > > > +	hdmi->audio.rate = rate;
> > > > > > +	hdmi->audio.channels = channels;
> > > > > > +	hdmi->audio.enabled = true;
> > > > > >     	return msm_hdmi_audio_update(hdmi);
> > > > > >     }
> > > > > > -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
> > > > > > +int msm_hdmi_audio_disable(struct hdmi *hdmi)
> > > > > >     {
> > > > > > -	struct hdmi_audio *audio;
> > > > > > -
> > > > > >     	if (!hdmi)
> > > > > > -		return;
> > > > > > -
> > > > > > -	audio = &hdmi->audio;
> > > > > > +		return -ENXIO;
> > > > > > -	if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
> > > > > > -		return;
> > > > > > +	hdmi->audio.rate = 0;
> > > > > > +	hdmi->audio.channels = 2;
> > > > > > +	hdmi->audio.enabled = false;
> > > > > > -	audio->rate = rate;
> > > > > > -	msm_hdmi_audio_update(hdmi);
> > > > > > +	return msm_hdmi_audio_update(hdmi);
> > > > > >     }
> > > > > > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > > > index d5ab1f74c0e6f47dc59872c016104e9a84d85e9e..168b4104e705e8217f5d7ca5f902d7557c55ae24 100644
> > > > > > --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > > > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > > > > > @@ -7,6 +7,8 @@
> > > > > >     #include <linux/delay.h>
> > > > > >     #include <drm/drm_bridge_connector.h>
> > > > > >     #include <drm/drm_edid.h>
> > > > > > +#include <drm/display/drm_hdmi_helper.h>
> > > > > > +#include <drm/display/drm_hdmi_state_helper.h>
> > > > > >     #include "msm_kms.h"
> > > > > >     #include "hdmi.h"
> > > > > > @@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge)
> > > > > >     #define AVI_IFRAME_LINE_NUMBER 1
> > > > > > -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> > > > > > +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
> > > > > > +					 const u8 *buffer, size_t len)
> > > > > >     {
> > > > > > -	struct drm_crtc *crtc = hdmi->encoder->crtc;
> > > > > > -	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> > > > > > -	union hdmi_infoframe frame;
> > > > > > -	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
> > > > > > +	u32 buf[4] = {};
> > > > > >     	u32 val;
> > > > > > -	int len;
> > > > > > +	int i;
> > > > > > -	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
> > > > > > -						 hdmi->connector, mode);
> > > > > > -
> > > > > > -	len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
> > > > > > -	if (len < 0) {
> > > > > > +	if (len != HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) {
> > > > > >     		DRM_DEV_ERROR(&hdmi->pdev->dev,
> > > > > >     			"failed to configure avi infoframe\n");
> > > > > > -		return;
> > > > > > +		return -EINVAL;
> > > > > >     	}
> > > > > >     	/*
> > > > > > @@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
> > > > > >     	 * written to the LSB byte of AVI_INFO0 and the version is written to
> > > > > >     	 * the third byte from the LSB of AVI_INFO3
> > > > > >     	 */
> > > > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
> > > > > > +	memcpy(buf, &buffer[3], len - 3);
> > > > > > +
> > > > > > +	buf[3] |= buffer[1] << 24;
> > > > > > +
> > > > > > +	for (i = 0; i < ARRAY_SIZE(buf); i++)
> > > > > > +		hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]);
> > > > > > +
> > > > > > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > > > +	val |= HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > > > > > +		HDMI_INFOFRAME_CTRL0_AVI_CONT;
> > > > > > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > > > +
> > > > > > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > > > +	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > > > > > +	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> > > > > > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > > > +
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
> > > > > > +					   const u8 *buffer, size_t len)
> > > > > > +{
> > > > > > +	u32 val;
> > > > > > +
> > > > > > +	if (len != HDMI_INFOFRAME_SIZE(AUDIO)) {
> > > > > > +		DRM_DEV_ERROR(&hdmi->pdev->dev,
> > > > > > +			"failed to configure audio infoframe\n");
> > > > > > +		return -EINVAL;
> > > > > > +	}
> > > > > > +
> > > > > > +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
> > > > > >     		   buffer[3] |
> > > > > >     		   buffer[4] << 8 |
> > > > > >     		   buffer[5] << 16 |
> > > > > >     		   buffer[6] << 24);
> > > > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
> > > > > > +	hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
> > > > > >     		   buffer[7] |
> > > > > >     		   buffer[8] << 8 |
> > > > > >     		   buffer[9] << 16 |
> > > > > >     		   buffer[10] << 24);
> > > > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
> > > > > > -		   buffer[11] |
> > > > > > -		   buffer[12] << 8 |
> > > > > > -		   buffer[13] << 16 |
> > > > > > -		   buffer[14] << 24);
> > > > > > +	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > > > +	val |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> > > > > > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> > > > > > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> > > > > > +		HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
> > > > > > +	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > > > +
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
> > > > > > +					   enum hdmi_infoframe_type type)
> > > > > > +{
> > > > > > +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > > > > > +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > > > > > +	u32 val;
> > > > > > +
> > > > > > +	switch (type) {
> > > > > > +	case HDMI_INFOFRAME_TYPE_AVI:
> > > > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > > > > > +		val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > > > > > +			 HDMI_INFOFRAME_CTRL0_AVI_CONT);
> > > > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > > > -	hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
> > > > > > -		   buffer[15] |
> > > > > > -		   buffer[16] << 8 |
> > > > > > -		   buffer[1] << 24);
> > > > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > > > +		val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > > > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > > > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
> > > > > > -		   HDMI_INFOFRAME_CTRL0_AVI_SEND |
> > > > > > -		   HDMI_INFOFRAME_CTRL0_AVI_CONT);
> > > > > > +		break;
> > > > > > -	val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > > > -	val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
> > > > > > -	val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
> > > > > > -	hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > > > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > > > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
> > > > > > +		val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND |
> > > > > > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT |
> > > > > > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE |
> > > > > > +			 HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE);
> > > > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val);
> > > > > > +
> > > > > > +		val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
> > > > > > +		val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK;
> > > > > > +		hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
> > > > > > +
> > > > > > +		break;
> > > > > > +
> > > > > > +	default:
> > > > > > +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> > > > > > +	}
> > > > > > +
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
> > > > > > +					   enum hdmi_infoframe_type type,
> > > > > > +					   const u8 *buffer, size_t len)
> > > > > > +{
> > > > > > +	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
> > > > > > +	struct hdmi *hdmi = hdmi_bridge->hdmi;
> > > > > > +
> > > > > > +	msm_hdmi_bridge_clear_infoframe(bridge, type);
> > > > > > +
> > > > > > +	switch (type) {
> > > > > > +	case HDMI_INFOFRAME_TYPE_AVI:
> > > > > > +		return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
> > > > > > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > > > > > +		return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
> > > > > > +	default:
> > > > > > +		drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
> > > > > > +		return 0;
> > > > > > +	}
> > > > > >     }
> > > > > >     static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > > > > @@ -146,16 +223,16 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> > > > > >     	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > > > > >     	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > > > > > +	hdmi->pixclock = conn_state->hdmi.tmds_char_rate;
> > > > > > +
> > > > > >     	if (!hdmi->power_on) {
> > > > > >     		msm_hdmi_phy_resource_enable(phy);
> > > > > >     		msm_hdmi_power_on(bridge);
> > > > > >     		hdmi->power_on = true;
> > > > > > -		if (hdmi->hdmi_mode) {
> > > > > > -			msm_hdmi_config_avi_infoframe(hdmi);
> > > > > > -			msm_hdmi_audio_update(hdmi);
> > > > > > -		}
> > > > > >     	}
> > > > > > +	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
> > > > > > +
> > > > > >     	msm_hdmi_phy_powerup(phy, hdmi->pixclock);
> > > > > >     	msm_hdmi_set_mode(hdmi, true);
> > > > > > @@ -184,8 +261,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct drm_bridge *bridge,
> > > > > >     	if (hdmi->power_on) {
> > > > > >     		power_off(bridge);
> > > > > >     		hdmi->power_on = false;
> > > > > > -		if (hdmi->hdmi_mode)
> > > > > > -			msm_hdmi_audio_update(hdmi);
> > > > > >     		msm_hdmi_phy_resource_disable(phy);
> > > > > >     	}
> > > > > >     }
> > > > > > @@ -196,8 +271,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > > > >     	int hstart, hend, vstart, vend;
> > > > > >     	uint32_t frame_ctrl;
> > > > > > -	hdmi->pixclock = mode->clock * 1000;
> > > > > > -
> > > > > >     	hstart = mode->htotal - mode->hsync_start;
> > > > > >     	hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
> > > > > > @@ -241,9 +314,6 @@ static void msm_hdmi_bridge_atomic_set_timings(struct hdmi *hdmi,
> > > > > >     		frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
> > > > > >     	DBG("frame_ctrl=%08x", frame_ctrl);
> > > > > >     	hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
> > > > > > -
> > > > > > -	if (hdmi->hdmi_mode)
> > > > > > -		msm_hdmi_audio_update(hdmi);
> > > > > >     }
> > > 
> > > Overall, I would like to know how the sequence was broken up:
> > > 
> > > HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND/CONT/UPDATE was moved from
> > > msm_hdmi_audio_update() to msm_hdmi_config_audio_infoframe() which is
> > > involed by drm_atomic_helper_connector_hdmi_update_infoframes() /
> > > drm_atomic_helper_connector_hdmi_clear_audio_infoframe().
> > > 
> > > But,HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND bit of REG_HDMI_AUDIO_PKT_CTRL1
> > > remained in msm_hdmi_audio_update().
> > 
> > This is correct, this bit controls sending of audio data, not the Audio
> > InfoFrame.
> > 
> > The strategy is very simple: Audio InfoFames are controlled centrally
> > via the DRM HDMI framework. Correct InfoFrame data is programmed at the
> > atomic_pre_enable() time (if it was set before) or during
> > msm_hdmi_bridge_audio_prepare() when the new stream is started.
> > 
> > All audio data frame management is deferred to
> > msm_hdmi_bridge_audio_prepare().
> > 
> 
> Thats in the last patch of the series not this one. But I understand the
> split.
> 
> > > If this is correct, are we not missing msm_hdmi_audio_update() in some
> > > places like pre_enable() / post_disable()?
> > 
> > drm_atomic_helper_connector_hdmi_update_infoframes() takes care of
> > writing all InfoFrames, including the Audio one.
> > 
> > > 
> > > Was this done because those calls were anyway bailing out audio->enabled was
> > > not set by then?
> > > 
> > > This seems to be another change which could have been done by itself to drop
> > > those calls first and then make this change to make it more clear.
> > > 
> > > OR atleast please explain these things better in the commit text.
> > 
> > If the above text is fine to you, I'll add it to the commit message.
> > 
> 
> This is fine, but the dropping of msm_hdmi_audio_update() from
> msm_hdmi_bridge_atomic_pre_enable() seems unrelated to the split OR using
> the DRM HDMI framework. It seems more because that call by itself without
> audio->enabled which is set in msm_hdmi_audio_info_setup() will not do
> anything.
> 
> So this is actually an independent fix and was just combined with this
> change? Thats the part I am trying to be more explicit about.

Ah, I see. I will bring it back.

> 
> > 
> 

-- 
With best wishes
Dmitry

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

end of thread, other threads:[~2025-02-07 23:43 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-24 21:47 [PATCH v6 0/7] drm/msm: make use of the HDMI connector infrastructure Dmitry Baryshkov
2025-01-24 21:47 ` [PATCH v6 1/7] drm/msm/hdmi: switch to atomic bridge callbacks Dmitry Baryshkov
2025-01-24 21:47 ` [PATCH v6 2/7] drm/msm/hdmi: program HDMI timings during atomic_pre_enable Dmitry Baryshkov
2025-01-26 16:41   ` Maxime Ripard
2025-02-03 19:34   ` Abhinav Kumar
2025-02-04  0:59     ` Dmitry Baryshkov
2025-02-06 20:41       ` Abhinav Kumar
2025-02-07  1:19         ` Dmitry Baryshkov
2025-02-07 20:11           ` Abhinav Kumar
2025-02-07 22:07             ` Dmitry Baryshkov
2025-01-24 21:47 ` [PATCH v6 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework Dmitry Baryshkov
2025-02-04  0:25   ` Abhinav Kumar
2025-02-04  1:30     ` Dmitry Baryshkov
2025-02-07 21:34       ` Abhinav Kumar
2025-02-07 22:03         ` Dmitry Baryshkov
2025-02-07 22:27           ` Abhinav Kumar
2025-02-07 23:43             ` Dmitry Baryshkov
2025-01-24 21:47 ` [PATCH v6 4/7] drm/msm/hdmi: get rid of hdmi_mode Dmitry Baryshkov
2025-01-24 21:47 ` [PATCH v6 5/7] drm/msm/hdmi: update HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE definition Dmitry Baryshkov
2025-01-24 21:47 ` [PATCH v6 6/7] drm/msm/hdmi: also send the SPD and HDMI Vendor Specific InfoFrames Dmitry Baryshkov
2025-01-24 21:47 ` [PATCH v6 7/7] drm/msm/hdmi: use DRM HDMI Audio framework Dmitry Baryshkov
2025-01-27 10:10   ` Maxime Ripard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox