From 9b639eb39bcba67ef2a9318c9f4579bfd0fb890c Mon Sep 17 00:00:00 2001
From: Shengjiu Wang <shengjiu.wang@nxp.com>
Date: Fri, 23 Oct 2020 19:52:10 +0800
Subject: [PATCH] MLK-24916-3: drm: bridge: synopsys: Add HBR support for gp
 audio

Only non_pcm, 32bit, 192kHz, 8channel streams be recognized as
HBR streams.

In order to support this feature, need to enhance the API in
dw-hdmi driver.

The test command is:
$iecset -c 4 audio off
$aplay -Dhw:4 -r 192000 -c 8 -f S32_LE out_put.spd.iec958
$iecset -c 4 audio on

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
---
 .../drm/bridge/synopsys/dw-hdmi-gp-audio.c    |  4 +++
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     | 30 ++++++++++++++++++-
 drivers/gpu/drm/imx/dw_hdmi-imx.c             |  5 ++--
 drivers/gpu/drm/imx/imx8mp-hdmi-pavi.c        | 12 ++++++--
 drivers/gpu/drm/imx/imx8mp-hdmi-pavi.h        |  2 +-
 include/drm/bridge/dw_hdmi.h                  |  5 +++-
 6 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
index 10bf94586d385..b6b77ca7c8794 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-gp-audio.c
@@ -89,6 +89,10 @@ static int audio_hw_params(struct device *dev,  void *data,
 	dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
 	dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
 
+	dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
+				   params->iec.status[0] & IEC958_AES0_NONAUDIO);
+	dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index acd831a25b9b9..10149d9e26172 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -191,6 +191,8 @@ struct dw_hdmi {
 
 	spinlock_t audio_lock;
 	struct mutex audio_mutex;
+	unsigned int sample_non_pcm;
+	unsigned int sample_width;
 	unsigned int sample_rate;
 	unsigned int channels;
 	unsigned int audio_cts;
@@ -709,6 +711,22 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
 	mutex_unlock(&hdmi->audio_mutex);
 }
 
+void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_width = width;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_width);
+
+void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm)
+{
+	mutex_lock(&hdmi->audio_mutex);
+	hdmi->sample_non_pcm = non_pcm;
+	mutex_unlock(&hdmi->audio_mutex);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_non_pcm);
+
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
 {
 	mutex_lock(&hdmi->audio_mutex);
@@ -828,8 +846,18 @@ static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
 
 	hdmi_modb(hdmi,  0x3, 0x3, HDMI_FC_DATAUTO3);
 
+	/* hbr */
+	if (hdmi->sample_rate == 192000 && hdmi->channels == 8 &&
+	    hdmi->sample_width == 32 && hdmi->sample_non_pcm) {
+		hdmi_modb(hdmi, 0x01, 0x01, HDMI_GP_CONF2);
+	}
+
 	if (hdmi->phy.ops->enable_audio)
-		hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data, hdmi->channels);
+		hdmi->phy.ops->enable_audio(hdmi, hdmi->phy.data,
+					    hdmi->channels,
+					    hdmi->sample_width,
+					    hdmi->sample_rate,
+					    hdmi->sample_non_pcm);
 }
 
 static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index 23840c8724741..d8d8aad6407e5 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -318,9 +318,10 @@ static int imx8mp_hdmimix_setup(struct imx_hdmi *hdmi)
 	return clk_bulk_prepare_enable(ARRAY_SIZE(imx8mp_clocks), imx8mp_clocks);
 }
 
-void imx8mp_hdmi_enable_audio(struct dw_hdmi *dw_hdmi, void *data, int channel)
+void imx8mp_hdmi_enable_audio(struct dw_hdmi *dw_hdmi, void *data, int channel,
+			      int width, int rate, int non_pcm)
 {
-	imx8mp_hdmi_pai_enable(channel);
+	imx8mp_hdmi_pai_enable(channel, width, rate, non_pcm);
 }
 
 void imx8mp_hdmi_disable_audio(struct dw_hdmi *dw_hdmi, void *data)
diff --git a/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.c b/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.c
index 9da1407386d06..d93694d803348 100644
--- a/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.c
+++ b/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.c
@@ -42,12 +42,20 @@
 static struct imx8mp_hdmi_pavi *gpavi;
 
 /* PAI APIs  */
-void imx8mp_hdmi_pai_enable(int channel)
+void imx8mp_hdmi_pai_enable(int channel, int width, int rate, int non_pcm)
 {
 	/* PAI set */
 	writel((0x3030000 | ((channel-1) << 8)),
 			gpavi->base + HTX_PAI_CTRL_EXT);
-	writel(0x1c0c675b, gpavi->base + HTX_PAI_FIELD_CTRL);
+
+	/* hbr */
+	if (non_pcm && width == 32 && channel == 8 && rate == 192000)
+		writel(0x004e77df, gpavi->base + HTX_PAI_FIELD_CTRL);
+	else if (width == 32)
+		writel(0x1c8c675b, gpavi->base + HTX_PAI_FIELD_CTRL);
+	else
+		writel(0x1c0c675b, gpavi->base + HTX_PAI_FIELD_CTRL);
+
 	/* PAI start running */
 	writel(HTX_PAI_CTRL_ENABLE, gpavi->base + HTX_PAI_CTRL);
 }
diff --git a/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.h b/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.h
index 2eedd2d489b97..ef90bf46cb970 100644
--- a/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.h
+++ b/drivers/gpu/drm/imx/imx8mp-hdmi-pavi.h
@@ -24,7 +24,7 @@ struct imx8mp_hdmi_pavi {
 	struct reset_control *reset_pvi;
 };
 
-void imx8mp_hdmi_pai_enable(int channel);
+void imx8mp_hdmi_pai_enable(int channel, int width, int rate, int non_pcm);
 void imx8mp_hdmi_pai_disable(void);
 
 void imx8mp_hdmi_pvi_enable(const struct drm_display_mode *mode);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 7c188e887b502..0c90f8d1d6ff6 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -121,7 +121,8 @@ struct dw_hdmi_phy_ops {
 	void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
 			   bool force, bool disabled, bool rxsense);
 	void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
-	void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel);
+	void (*enable_audio)(struct dw_hdmi *hdmi, void *data, int channel,
+			     int width, int rate, int non_pcm);
 	void (*disable_audio)(struct dw_hdmi *hdmi, void *data);
 };
 
@@ -175,6 +176,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
 
 int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
 			   struct device *codec_dev);
+void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm);
+void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width);
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt);
 void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status);
-- 
GitLab