linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60
@ 2018-11-30 13:42 Neil Armstrong
  2018-11-30 13:42 ` [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support Neil Armstrong
                   ` (7 more replies)
  0 siblings, 8 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:42 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	Heiko Stübner, maxime.ripard
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel

This patchset aims to add support for the following HDMI2.0 4k60 modes:
- 594Mhz TMDS frequency needing TMDS Scramling and 1/40 rate for RGB/YUV4:4:4
- 297MHz TMDS frequency with YUV4:2:0 encoding

The first mode uses the SCDC helpers introduced by intel to :
- discover where the monitor support SCDC
- setup the SCDC parameters
This is implemented in the dw-hdmi bridge driver by handling scrambling
support during the bridge setup and by exporting an helper for the PHY
setup to setup the SCDC configuration for the 1/40 TMDS rate.
This code will only be active if the encoder support a TMDS rate > 340MHz.

This patch could eventually break support on different SoC when connected
on a 4k60 monitor with SCDC :
- i.MX correctly discards pixel clocks > 216MHz
- R-CAR discards discards pixel clocks > 297MHz since [1]
- Rockchip discards invalid pixel clocks not in the rockchip_mpll_cfg table
- sun8i correctly discards pixel clocks > 297MHz on a83t
- sun8i discards discards pixel clocks > 594Mhz on h6, which is already broken

First patch should fix support for Allwinner H6.

The second mode is implemented by added the missing 4:2:0 bypass handling
in the dw-hdmi bridge driver and adding a "mtmdsclock" separating the
pixel clock from the tmds clock in the mode setup phase.
We also enable support for these modes in the connector only if the platform
glue code explicits the support.

Only the meson DRM dw_hdmi glue allows ycbcr420 modes, so no breakage
is expected here.

The remaining patches adds support for :
- 1/40 TMDS rate aka DIV40 in the dw-hdmi meson PHY setup
- 4:2:0 output and clock setup

The dw-hdmi support re-uses the support done by Rockchip engineers on the
Linux 4.4 BSP kernel.

These modes has been validated using a MuxLab HDMI Signal Analyser in
addition to different UHD TVs supporting full 4k60 or the 4:2:0 variant.

Changes since RFC v1 at [2]:
- Fix all comments from Laurent :
- Add define for HDMI 1.4 max tmds clock and SCDC supported version
- Call dw_hdmi_set_high_tmds_clock_ratio() in dw_hdmi_phy_enable_powerdown()
to unbreak Allwinner H6
- Pass in_t(u8, bytes, SCDC_MIN_SOURCE_VERSION) as SCDC version
- Finally add comments for SCDC and Scrambling process

[1] https://patchwork.freedesktop.org/patch/263616/

Neil Armstrong (7):
  drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support
  drm/meson: add HDMI div40 TMDS mode
  drm/meson: add support for HDMI2.0 2160p modes
  drm/bridge: dw-hdmi: add support for YUV420 output
  drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  drm/meson: Add YUV420 output support
  drm/meson: Output in YUV444 if sink supports it

Zheng Yang (1):
  drm/bridge: dw-hdmi: support dynamically get input/out color info

 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 182 +++++++++++++++++++---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.h |   1 +
 drivers/gpu/drm/meson/meson_dw_hdmi.c     | 129 ++++++++++++---
 drivers/gpu/drm/meson/meson_vclk.c        |  93 ++++++++---
 drivers/gpu/drm/meson/meson_vclk.h        |   7 +-
 drivers/gpu/drm/meson/meson_venc.c        |   8 +-
 drivers/gpu/drm/meson/meson_venc.h        |  11 ++
 drivers/gpu/drm/meson/meson_venc_cvbs.c   |   3 +-
 include/drm/bridge/dw_hdmi.h              |   7 +
 9 files changed, 375 insertions(+), 66 deletions(-)

-- 
2.19.2


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

* [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
@ 2018-11-30 13:42 ` Neil Armstrong
  2018-12-14 12:12   ` Heiko Stuebner
  2018-12-18 12:25   ` Andrzej Hajda
  2018-11-30 13:42 ` [PATCH RFC v2 2/8] drm/meson: add HDMI div40 TMDS mode Neil Armstrong
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:42 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	Heiko Stübner, maxime.ripard
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel,
	Nickey Yang, Huicong Xu

Add support for SCDC Setup for TMDS Clock > 3.4GHz and enable TMDS
Scrambling when supported or mandatory.

This patch also adds an helper to setup the control bit to support
the high TMDS Bit Period/TMDS Clock-Period Ratio as required with
TMDS Clock > 3.4GHz for HDMI2.0 3840x2160@60/50 modes.

These changes were based on work done by Huicong Xu <xhc@rock-chips.com>
and Nickey Yang <nickey.yang@rock-chips.com> to support HDMI2.0 modes
on the Rockchip 4.4 BSP kernel at [1]

[1] https://github.com/rockchip-linux/kernel/tree/release-4.4

Cc: Nickey Yang <nickey.yang@rock-chips.com>
Cc: Huicong Xu <xhc@rock-chips.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 88 ++++++++++++++++++++++-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.h |  1 +
 include/drm/bridge/dw_hdmi.h              |  1 +
 3 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 64c3cf027518..fcd941d52753 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -28,6 +28,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
+#include <drm/drm_scdc_helper.h>
 #include <drm/bridge/dw_hdmi.h>
 
 #include <uapi/linux/media-bus-format.h>
@@ -43,6 +44,11 @@
 
 #define HDMI_EDID_LEN		512
 
+/* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */
+#define SCDC_MIN_SOURCE_VERSION	0x1
+
+#define HDMI14_MAX_TMDSCLK	340000000
+
 enum hdmi_datamap {
 	RGB444_8B = 0x01,
 	RGB444_10B = 0x03,
@@ -1015,6 +1021,33 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
 
+/*
+ * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
+ * - The Source shall suspend transmission of the TMDS clock and data
+ * - The Source shall write to the TMDS_Bit_Clock_Ratio bit to change it
+ * from a 0 to a 1 or from a 1 to a 0
+ * - The Source shall allow a minimum of 1 ms and a maximum of 100 ms from
+ * the time the TMDS_Bit_Clock_Ratio bit is written until resuming
+ * transmission of TMDS clock and data
+ *
+ * To respect the 100ms maximum delay, the dw_hdmi_set_high_tmds_clock_ratio()
+ * helper should called right before enabling the TMDS Clock and Data in
+ * the PHY configuration callback.
+ */
+void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
+{
+	unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock;
+
+	/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
+	if (hdmi->connector.display_info.hdmi.scdc.supported) {
+		if (mtmdsclock > HDMI14_MAX_TMDSCLK)
+			drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
+		else
+			drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
+	}
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
+
 static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
 {
 	hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
@@ -1216,6 +1249,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 
 	dw_hdmi_phy_power_off(hdmi);
 
+	dw_hdmi_set_high_tmds_clock_ratio(hdmi);
+
 	/* Leave low power consumption mode by asserting SVSRET. */
 	if (phy->has_svsret)
 		dw_hdmi_phy_enable_svsret(hdmi, 1);
@@ -1237,6 +1272,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 		return ret;
 	}
 
+	/* Wait for resuming transmission of TMDS clock and data */
+	if (mpixelclock > HDMI14_MAX_TMDSCLK)
+		msleep(100);
+
 	return dw_hdmi_phy_power_on(hdmi);
 }
 
@@ -1340,11 +1379,12 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
 
 static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 {
+	bool is_hdmi2_sink = hdmi->connector.display_info.hdmi.scdc.supported;
 	struct hdmi_avi_infoframe frame;
 	u8 val;
 
 	/* Initialise info frame from DRM mode */
-	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
+	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2_sink);
 
 	if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
 		frame.colorspace = HDMI_COLORSPACE_YUV444;
@@ -1503,7 +1543,8 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
 static void hdmi_av_composer(struct dw_hdmi *hdmi,
 			     const struct drm_display_mode *mode)
 {
-	u8 inv_val;
+	u8 inv_val, bytes;
+	struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
 	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
 	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
 	unsigned int vdisplay;
@@ -1513,7 +1554,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
 
 	/* Set up HDMI_FC_INVIDCONF */
-	inv_val = (hdmi->hdmi_data.hdcp_enable ?
+	inv_val = (hdmi->hdmi_data.hdcp_enable ||
+		   vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
+		   hdmi_info->scdc.scrambling.low_rates ?
 		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
 		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
 
@@ -1562,6 +1605,45 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 		vsync_len /= 2;
 	}
 
+	/* Scrambling Control */
+	if (hdmi_info->scdc.supported) {
+		if (vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
+		    hdmi_info->scdc.scrambling.low_rates) {
+			/*
+			 * HDMI2.0 Specifies the following procedure:
+			 * After the Source Device has determined that
+			 * SCDC_Present is set (=1), the Source Device should
+			 * write the accurate Version of the Source Device
+			 * to the Source Version field in the SCDCS.
+			 * Source Devices compliant shall set the
+			 * Source Version = 1.
+			 */
+			drm_scdc_readb(&hdmi->i2c->adap, SCDC_SINK_VERSION,
+				       &bytes);
+			drm_scdc_writeb(&hdmi->i2c->adap, SCDC_SOURCE_VERSION,
+				min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
+
+			/* Enabled Scrambling in the Sink */
+			drm_scdc_set_scrambling(&hdmi->i2c->adap, 1);
+
+			/*
+			 * To activate the scrambler feature, you must ensure
+			 * that the quasi-static configuration bit
+			 * fc_invidconf.HDCP_keepout is set at configuration
+			 * time, before the required mc_swrstzreq.tmdsswrst_req
+			 * reset request is issued.
+			 */
+			hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
+				    HDMI_MC_SWRSTZ);
+			hdmi_writeb(hdmi, 1, HDMI_FC_SCRAMBLER_CTRL);
+		} else {
+			hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
+			hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
+				    HDMI_MC_SWRSTZ);
+			drm_scdc_set_scrambling(&hdmi->i2c->adap, 0);
+		}
+	}
+
 	/* Set up horizontal active pixel width */
 	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
 	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
index 9d90eb9c46e5..3f3c616eba97 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
@@ -255,6 +255,7 @@
 #define HDMI_FC_MASK2                           0x10DA
 #define HDMI_FC_POL2                            0x10DB
 #define HDMI_FC_PRCONF                          0x10E0
+#define HDMI_FC_SCRAMBLER_CTRL                  0x10E1
 
 #define HDMI_FC_GMD_STAT                        0x1100
 #define HDMI_FC_GMD_EN                          0x1101
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 9c56412bb2cf..7a02744ce0bc 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -157,6 +157,7 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
 void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
+void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi);
 
 /* PHY configuration */
 void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
-- 
2.19.2


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

* [PATCH RFC v2 2/8] drm/meson: add HDMI div40 TMDS mode
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
  2018-11-30 13:42 ` [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support Neil Armstrong
@ 2018-11-30 13:42 ` Neil Armstrong
  2018-12-18 12:36   ` Andrzej Hajda
  2018-11-30 13:42 ` [PATCH RFC v2 3/8] drm/meson: add support for HDMI2.0 2160p modes Neil Armstrong
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:42 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel

Add support for TMDS Clock > 3.4GHz for HDMI2.0 display modes.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_dw_hdmi.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 807111ebfdd9..b8775102b100 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -365,7 +365,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
 	unsigned int wr_clk =
 		readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
 
-	DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
+	DRM_DEBUG_DRIVER("%d:\"%s\" div%d\n", mode->base.id, mode->name,
+			 mode->clock > 340000 ? 40 : 10);
 
 	/* Enable clocks */
 	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
@@ -385,9 +386,17 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
 	/* Enable normal output to PHY */
 	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
 
-	/* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
-	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
-	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
+	/* TMDS pattern setup (TOFIX Handle the YUV420 case) */
+	if (mode->clock > 340000) {
+		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
+		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
+				  0x03ff03ff);
+	} else {
+		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
+				  0x001f001f);
+		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
+				  0x001f001f);
+	}
 
 	/* Load TMDS pattern */
 	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
@@ -413,6 +422,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
 	/* Disable clock, fifo, fifo_wr */
 	regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
 
+	dw_hdmi_set_high_tmds_clock_ratio(hdmi);
+
 	msleep(100);
 
 	/* Reset PHY 3 times in a row */
@@ -562,6 +573,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 		mode->vdisplay, mode->vsync_start,
 		mode->vsync_end, mode->vtotal, mode->type, mode->flags);
 
+	/* If sink max TMDS clock < 340MHz, we reject the HDMI2.0 modes */
+	if (mode->clock > 340000 &&
+	    connector->display_info.max_tmds_clock < 340000)
+		return MODE_BAD;
+
 	/* Check against non-VIC supported modes */
 	if (!vic) {
 		status = meson_venc_hdmi_supported_mode(mode);
-- 
2.19.2


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

* [PATCH RFC v2 3/8] drm/meson: add support for HDMI2.0 2160p modes
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
  2018-11-30 13:42 ` [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support Neil Armstrong
  2018-11-30 13:42 ` [PATCH RFC v2 2/8] drm/meson: add HDMI div40 TMDS mode Neil Armstrong
@ 2018-11-30 13:42 ` Neil Armstrong
  2018-12-18 12:37   ` Andrzej Hajda
  2018-11-30 13:42 ` [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output Neil Armstrong
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:42 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel

Now we support the TMDS Clock > 3.4GHz and support the SCDC Control
operation in the DW-HDMI Controller, we can enable support for the
HDMI2.0 3840x2160@60/50 RGB444 display modes.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_venc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 0ba04f6813e6..66d73a932d19 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -848,6 +848,8 @@ struct meson_hdmi_venc_vic_mode {
 	{ 93, &meson_hdmi_encp_mode_2160p24 },
 	{ 94, &meson_hdmi_encp_mode_2160p25 },
 	{ 95, &meson_hdmi_encp_mode_2160p30 },
+	{ 96, &meson_hdmi_encp_mode_2160p25 },
+	{ 97, &meson_hdmi_encp_mode_2160p30 },
 	{ 0, NULL}, /* sentinel */
 };
 
-- 
2.19.2


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

* [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
                   ` (2 preceding siblings ...)
  2018-11-30 13:42 ` [PATCH RFC v2 3/8] drm/meson: add support for HDMI2.0 2160p modes Neil Armstrong
@ 2018-11-30 13:42 ` Neil Armstrong
  2018-12-14 12:13   ` Heiko Stuebner
  2018-12-18 13:41   ` Andrzej Hajda
  2018-11-30 13:42 ` [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info Neil Armstrong
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:42 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	Heiko Stübner, maxime.ripard
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel, Zheng Yang

In order to support the HDMI2.0 YUV420 display modes, this patch
adds support for the YUV420 TMDS Clock divided by 2 and the controller
passthrough mode.

YUV420 Synopsys PHY support will need some specific configuration table
to support theses modes.

This patch is based on work from Zheng Yang <zhengyang@rock-chips.com> in
the Rockchip Linux 4.4 BSP at [1]

[1] https://github.com/rockchip-linux/kernel/tree/release-4.4

Cc: Zheng Yang <zhengyang@rock-chips.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 68 ++++++++++++++++++-----
 1 file changed, 54 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index fcd941d52753..4a9a24e854db 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -99,6 +99,7 @@ struct hdmi_vmode {
 	unsigned int mpixelclock;
 	unsigned int mpixelrepetitioninput;
 	unsigned int mpixelrepetitionoutput;
+	unsigned int mtmdsclock;
 };
 
 struct hdmi_data_info {
@@ -543,7 +544,7 @@ static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
 static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
 {
 	mutex_lock(&hdmi->audio_mutex);
-	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
 				 hdmi->sample_rate);
 	mutex_unlock(&hdmi->audio_mutex);
 }
@@ -552,7 +553,7 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
 {
 	mutex_lock(&hdmi->audio_mutex);
 	hdmi->sample_rate = rate;
-	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
 				 hdmi->sample_rate);
 	mutex_unlock(&hdmi->audio_mutex);
 }
@@ -653,6 +654,20 @@ static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
 	}
 }
 
+static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
+	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
 static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
 {
 	switch (bus_format) {
@@ -882,7 +897,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
 	u8 val, vp_conf;
 
 	if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
-	    hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) {
+	    hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format) ||
+	    hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
 		switch (hdmi_bus_fmt_color_depth(
 					hdmi->hdmi_data.enc_out_bus_format)) {
 		case 8:
@@ -1036,7 +1052,7 @@ EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
  */
 void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
 {
-	unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock;
+	unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
 
 	/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
 	if (hdmi->connector.display_info.hdmi.scdc.supported) {
@@ -1198,6 +1214,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
 	const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
 	const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
 
+	/* TOFIX Will need 420 specific PHY configuration tables */
+
 	/* PLL/MPLL Cfg - always match on final entry */
 	for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
 		if (mpixelclock <= mpll_config->mpixelclock)
@@ -1245,6 +1263,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 	const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
 	const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
 	unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
+	unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
 	int ret;
 
 	dw_hdmi_phy_power_off(hdmi);
@@ -1273,7 +1292,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 	}
 
 	/* Wait for resuming transmission of TMDS clock and data */
-	if (mpixelclock > HDMI14_MAX_TMDSCLK)
+	if (mtmdsclock > HDMI14_MAX_TMDSCLK)
 		msleep(100);
 
 	return dw_hdmi_phy_power_on(hdmi);
@@ -1383,6 +1402,9 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	struct hdmi_avi_infoframe frame;
 	u8 val;
 
+	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
+		is_hdmi2_sink = true;
+
 	/* Initialise info frame from DRM mode */
 	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2_sink);
 
@@ -1390,6 +1412,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 		frame.colorspace = HDMI_COLORSPACE_YUV444;
 	else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
 		frame.colorspace = HDMI_COLORSPACE_YUV422;
+	else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
+		frame.colorspace = HDMI_COLORSPACE_YUV420;
 	else
 		frame.colorspace = HDMI_COLORSPACE_RGB;
 
@@ -1547,15 +1571,18 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
 	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
 	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
-	unsigned int vdisplay;
+	unsigned int vdisplay, hdisplay;
 
-	vmode->mpixelclock = mode->clock * 1000;
+	vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
 
 	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
 
+	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
+		vmode->mtmdsclock /= 2;
+
 	/* Set up HDMI_FC_INVIDCONF */
 	inv_val = (hdmi->hdmi_data.hdcp_enable ||
-		   vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
+		   vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
 		   hdmi_info->scdc.scrambling.low_rates ?
 		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
 		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
@@ -1589,6 +1616,22 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 
 	hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
 
+	hdisplay = mode->hdisplay;
+	hblank = mode->htotal - mode->hdisplay;
+	h_de_hs = mode->hsync_start - mode->hdisplay;
+	hsync_len = mode->hsync_end - mode->hsync_start;
+
+	/*
+	 * When we're setting a YCbCr420 mode, we need
+	 * to adjust the horizontal timing to suit.
+	 */
+	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
+		hdisplay /= 2;
+		hblank /= 2;
+		h_de_hs /= 2;
+		hsync_len /= 2;
+	}
+
 	vdisplay = mode->vdisplay;
 	vblank = mode->vtotal - mode->vdisplay;
 	v_de_vs = mode->vsync_start - mode->vdisplay;
@@ -1607,7 +1650,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 
 	/* Scrambling Control */
 	if (hdmi_info->scdc.supported) {
-		if (vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
+		if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
 		    hdmi_info->scdc.scrambling.low_rates) {
 			/*
 			 * HDMI2.0 Specifies the following procedure:
@@ -1645,15 +1688,14 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	}
 
 	/* Set up horizontal active pixel width */
-	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
-	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+	hdmi_writeb(hdmi, hdisplay >> 8, HDMI_FC_INHACTV1);
+	hdmi_writeb(hdmi, hdisplay, HDMI_FC_INHACTV0);
 
 	/* Set up vertical active lines */
 	hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1);
 	hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0);
 
 	/* Set up horizontal blanking pixel region width */
-	hblank = mode->htotal - mode->hdisplay;
 	hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
 	hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
 
@@ -1661,7 +1703,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
 
 	/* Set up HSYNC active edge delay width (in pixel clks) */
-	h_de_hs = mode->hsync_start - mode->hdisplay;
 	hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
 	hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
 
@@ -1669,7 +1710,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 	hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
 
 	/* Set up HSYNC active pulse width (in pixel clks) */
-	hsync_len = mode->hsync_end - mode->hsync_start;
 	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
 	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
 
-- 
2.19.2


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

* [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
                   ` (3 preceding siblings ...)
  2018-11-30 13:42 ` [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output Neil Armstrong
@ 2018-11-30 13:42 ` Neil Armstrong
  2018-12-14 12:13   ` Heiko Stuebner
  2018-12-19  7:26   ` Andrzej Hajda
  2018-11-30 13:42 ` [PATCH RFC v2 6/8] drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:42 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	Heiko Stübner, maxime.ripard
  Cc: Zheng Yang, dri-devel, linux-amlogic, linux-kernel, Neil Armstrong

From: Zheng Yang <zhengyang@rock-chips.com>

To get input/output bus_format/enc_format dynamically, this patch
introduce following funstion in plat_data:
	- get_input_bus_format
	- get_output_bus_format
	- get_enc_in_encoding
	- get_enc_out_encoding

Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++++++------
 include/drm/bridge/dw_hdmi.h              |  5 ++++
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 4a9a24e854db..bd564ffdf18b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1810,6 +1810,7 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
 static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 {
 	int ret;
+	void *data = hdmi->plat_data->phy_data;
 
 	hdmi_disable_overflow_interrupts(hdmi);
 
@@ -1821,10 +1822,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
 	}
 
-	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
-	    (hdmi->vic == 21) || (hdmi->vic == 22) ||
-	    (hdmi->vic == 2) || (hdmi->vic == 3) ||
-	    (hdmi->vic == 17) || (hdmi->vic == 18))
+	if (hdmi->plat_data->get_enc_out_encoding)
+		hdmi->hdmi_data.enc_out_encoding =
+			hdmi->plat_data->get_enc_out_encoding(data);
+	else if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+		 (hdmi->vic == 21) || (hdmi->vic == 22) ||
+		 (hdmi->vic == 2) || (hdmi->vic == 3) ||
+		 (hdmi->vic == 17) || (hdmi->vic == 18))
 		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601;
 	else
 		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709;
@@ -1833,21 +1837,31 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
 
 	/* TOFIX: Get input format from plat data or fallback to RGB888 */
-	if (hdmi->plat_data->input_bus_format)
+	if (hdmi->plat_data->get_input_bus_format)
+		hdmi->hdmi_data.enc_in_bus_format =
+			hdmi->plat_data->get_input_bus_format(data);
+	else if (hdmi->plat_data->input_bus_format)
 		hdmi->hdmi_data.enc_in_bus_format =
 			hdmi->plat_data->input_bus_format;
 	else
 		hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 
 	/* TOFIX: Get input encoding from plat data or fallback to none */
-	if (hdmi->plat_data->input_bus_encoding)
+	if (hdmi->plat_data->get_enc_in_encoding)
+		hdmi->hdmi_data.enc_in_encoding =
+			hdmi->plat_data->get_enc_in_encoding(data);
+	else if (hdmi->plat_data->input_bus_encoding)
 		hdmi->hdmi_data.enc_in_encoding =
 			hdmi->plat_data->input_bus_encoding;
 	else
 		hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
 
 	/* TOFIX: Default to RGB888 output format */
-	hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	if (hdmi->plat_data->get_output_bus_format)
+		hdmi->hdmi_data.enc_out_bus_format =
+			hdmi->plat_data->get_output_bus_format(data);
+	else
+		hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 
 	hdmi->hdmi_data.pix_repet_factor = 0;
 	hdmi->hdmi_data.hdcp_enable = 0;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 7a02744ce0bc..2e797f782c51 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -142,6 +142,11 @@ struct dw_hdmi_plat_data {
 	int (*configure_phy)(struct dw_hdmi *hdmi,
 			     const struct dw_hdmi_plat_data *pdata,
 			     unsigned long mpixelclock);
+
+	unsigned long (*get_input_bus_format)(void *data);
+	unsigned long (*get_output_bus_format)(void *data);
+	unsigned long (*get_enc_in_encoding)(void *data);
+	unsigned long (*get_enc_out_encoding)(void *data);
 };
 
 struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
-- 
2.19.2


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

* [PATCH RFC v2 6/8] drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
                   ` (4 preceding siblings ...)
  2018-11-30 13:42 ` [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info Neil Armstrong
@ 2018-11-30 13:42 ` Neil Armstrong
  2018-12-14 12:13   ` Heiko Stuebner
  2018-11-30 13:43 ` [PATCH RFC v2 7/8] drm/meson: Add YUV420 output support Neil Armstrong
  2018-11-30 13:43 ` [PATCH RFC v2 8/8] drm/meson: Output in YUV444 if sink supports it Neil Armstrong
  7 siblings, 1 reply; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:42 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	Heiko Stübner, maxime.ripard
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel

Now the DW-HDMI Controller supports the HDMI2.0 modes, enable support
for these modes in the connector if the platform supports them.
We limit these modes to DW-HDMI IP version >= 0x200a which
are designed to support HDMI2.0 display modes.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++++
 include/drm/bridge/dw_hdmi.h              | 1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index bd564ffdf18b..b6987d97f892 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2612,6 +2612,12 @@ __dw_hdmi_probe(struct platform_device *pdev,
 	if (hdmi->phy.ops->setup_hpd)
 		hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
 
+	if (hdmi->version >= 0x200a)
+		hdmi->connector.ycbcr_420_allowed =
+			hdmi->plat_data->ycbcr_420_allowed;
+	else
+		hdmi->connector.ycbcr_420_allowed = false;
+
 	memset(&pdevinfo, 0, sizeof(pdevinfo));
 	pdevinfo.parent = dev;
 	pdevinfo.id = PLATFORM_DEVID_AUTO;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 2e797f782c51..3768265d7a5f 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -128,6 +128,7 @@ struct dw_hdmi_plat_data {
 					   const struct drm_display_mode *mode);
 	unsigned long input_bus_format;
 	unsigned long input_bus_encoding;
+	bool ycbcr_420_allowed;
 
 	/* Vendor PHY support */
 	const struct dw_hdmi_phy_ops *phy_ops;
-- 
2.19.2


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

* [PATCH RFC v2 7/8] drm/meson: Add YUV420 output support
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
                   ` (5 preceding siblings ...)
  2018-11-30 13:42 ` [PATCH RFC v2 6/8] drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
@ 2018-11-30 13:43 ` Neil Armstrong
  2018-11-30 13:43 ` [PATCH RFC v2 8/8] drm/meson: Output in YUV444 if sink supports it Neil Armstrong
  7 siblings, 0 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:43 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel

This patch adds support for the YUV420 output from the Amlogic Meson SoCs
Video Processing Unit to the HDMI Controller.

The YUV420 is obtained by generating a YUV444 pixel stream like
the classic HDMI display modes, but then the Video Encoder output
can be configured to down-sample the YUV444 pixel stream to a YUV420
stream.
In addition if pixel stream down-sampling, the Y Cb Cr components must
also be mapped differently to align with the HDMI2.0 specifications.

This mode needs a different clock generation scheme since the TMDS PHY
clock must match the 10x ration with the YUV420 pixel clock, but
the video encoder must run at 2x the pixel clock.

This patch adds the TMDS PHY clock value in all the video clock setup
in order to better support these specific uses cases and switch
to the Common Clock framework for clocks handling in the future.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_dw_hdmi.c   | 108 ++++++++++++++++++++----
 drivers/gpu/drm/meson/meson_vclk.c      |  93 +++++++++++++++-----
 drivers/gpu/drm/meson/meson_vclk.h      |   7 +-
 drivers/gpu/drm/meson/meson_venc.c      |   6 +-
 drivers/gpu/drm/meson/meson_venc.h      |  11 +++
 drivers/gpu/drm/meson/meson_venc_cvbs.c |   3 +-
 6 files changed, 183 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index b8775102b100..83360f37d9ce 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -141,6 +141,8 @@ struct meson_dw_hdmi {
 	struct regulator *hdmi_supply;
 	u32 irq_stat;
 	struct dw_hdmi *hdmi;
+	unsigned long input_bus_format;
+	unsigned long output_bus_format;
 };
 #define encoder_to_meson_dw_hdmi(x) \
 	container_of(x, struct meson_dw_hdmi, encoder)
@@ -323,25 +325,36 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
 {
 	struct meson_drm *priv = dw_hdmi->priv;
 	int vic = drm_match_cea_mode(mode);
+	unsigned int phy_freq;
 	unsigned int vclk_freq;
 	unsigned int venc_freq;
 	unsigned int hdmi_freq;
 
 	vclk_freq = mode->clock;
 
+	/* For 420, pixel clock is half unlike venc clock */
+	if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
+		vclk_freq /= 2;
+
+	/* TMDS clock is pixel_clock * 10 */
+	phy_freq = vclk_freq * 10;
+
 	if (!vic) {
-		meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
-				 vclk_freq, vclk_freq, false);
+		meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq,
+				 vclk_freq, vclk_freq, vclk_freq, false);
 		return;
 	}
 
+	/* 480i/576i needs global pixel doubling */
 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 		vclk_freq *= 2;
 
 	venc_freq = vclk_freq;
 	hdmi_freq = vclk_freq;
 
-	if (meson_venc_hdmi_venc_repeat(vic))
+	/* VENC double pixels for 1080i, 720p and YUV420 modes */
+	if (meson_venc_hdmi_venc_repeat(vic) ||
+	    dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
 		venc_freq *= 2;
 
 	vclk_freq = max(venc_freq, hdmi_freq);
@@ -349,11 +362,11 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 		venc_freq /= 2;
 
-	DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
-		vclk_freq, venc_freq, hdmi_freq,
+	DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n",
+		phy_freq, vclk_freq, venc_freq, hdmi_freq,
 		priv->venc.hdmi_use_enci);
 
-	meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
+	meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq,
 			 venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
 }
 
@@ -387,7 +400,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
 	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
 
 	/* TMDS pattern setup (TOFIX Handle the YUV420 case) */
-	if (mode->clock > 340000) {
+	if (mode->clock > 340000 &&
+	    dw_hdmi->input_bus_format == MEDIA_BUS_FMT_YUV8_1X24) {
 		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
 		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
 				  0x03ff03ff);
@@ -560,6 +574,8 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 		   const struct drm_display_mode *mode)
 {
 	struct meson_drm *priv = connector->dev->dev_private;
+	bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
+	unsigned int phy_freq;
 	unsigned int vclk_freq;
 	unsigned int venc_freq;
 	unsigned int hdmi_freq;
@@ -573,9 +589,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 		mode->vdisplay, mode->vsync_start,
 		mode->vsync_end, mode->vtotal, mode->type, mode->flags);
 
-	/* If sink max TMDS clock < 340MHz, we reject the HDMI2.0 modes */
+	/* If sink does not support 540MHz, reject the non-420 HDMI2 modes */
 	if (mode->clock > 340000 &&
-	    connector->display_info.max_tmds_clock < 340000)
+	    connector->display_info.max_tmds_clock < 340000 &&
+	    !drm_mode_is_420_only(&connector->display_info, mode) &&
+	    !drm_mode_is_420_also(&connector->display_info, mode))
 		return MODE_BAD;
 
 	/* Check against non-VIC supported modes */
@@ -591,6 +609,15 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 
 	vclk_freq = mode->clock;
 
+	/* For 420, pixel clock is half unlike venc clock */
+	if (drm_mode_is_420_only(&connector->display_info, mode) ||
+	    (!is_hdmi2_sink &&
+	     drm_mode_is_420_also(&connector->display_info, mode)))
+		vclk_freq /= 2;
+
+	/* TMDS clock is pixel_clock * 10 */
+	phy_freq = vclk_freq * 10;
+
 	/* 480i/576i needs global pixel doubling */
 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 		vclk_freq *= 2;
@@ -598,8 +625,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 	venc_freq = vclk_freq;
 	hdmi_freq = vclk_freq;
 
-	/* VENC double pixels for 1080i and 720p modes */
-	if (meson_venc_hdmi_venc_repeat(vic))
+	/* VENC double pixels for 1080i, 720p and YUV420 modes */
+	if (meson_venc_hdmi_venc_repeat(vic) ||
+	    drm_mode_is_420_only(&connector->display_info, mode) ||
+	    (!is_hdmi2_sink &&
+	     drm_mode_is_420_also(&connector->display_info, mode)))
 		venc_freq *= 2;
 
 	vclk_freq = max(venc_freq, hdmi_freq);
@@ -607,10 +637,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
 		venc_freq /= 2;
 
-	dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
-		vclk_freq, venc_freq, hdmi_freq);
+	dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
+		__func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
 
-	return meson_vclk_vic_supported_freq(vclk_freq);
+	return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
 }
 
 /* Encoder */
@@ -628,6 +658,21 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
 					struct drm_crtc_state *crtc_state,
 					struct drm_connector_state *conn_state)
 {
+	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+	struct drm_display_info *info = &conn_state->connector->display_info;
+	struct drm_display_mode *mode = &crtc_state->mode;
+	bool is_hdmi2_sink =
+		conn_state->connector->display_info.hdmi.scdc.supported;
+
+	if (drm_mode_is_420_only(info, mode) ||
+	    (!is_hdmi2_sink && drm_mode_is_420_also(info, mode))) {
+		dw_hdmi->input_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+		dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+	} else {
+		dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
+		dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+	}
+
 	return 0;
 }
 
@@ -665,18 +710,30 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
 	struct meson_drm *priv = dw_hdmi->priv;
 	int vic = drm_match_cea_mode(mode);
+	unsigned int ycrcb_map = MESON_VENC_MAP_CB_Y_CR;
+	bool yuv420_mode = false;
 
 	DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
 			 mode->base.id, mode->name, vic);
 
+	if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) {
+		ycrcb_map = MESON_VENC_MAP_CR_Y_CB;
+		yuv420_mode = true;
+	}
+
 	/* VENC + VENC-DVI Mode setup */
-	meson_venc_hdmi_mode_set(priv, vic, mode);
+	meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode);
 
 	/* VCLK Set clock */
 	dw_hdmi_set_vclk(dw_hdmi, mode);
 
-	/* Setup YUV444 to HDMI-TX, no 10bit diphering */
-	writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+	if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
+		/* Setup YUV420 to HDMI-TX, no 10bit diphering */
+		writel_relaxed(2 | (2 << 2),
+			       priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+	else
+		/* Setup YUV444 to HDMI-TX, no 10bit diphering */
+		writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
 }
 
 static const struct drm_encoder_helper_funcs
@@ -715,6 +772,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = {
 	.fast_io = true,
 };
 
+static unsigned long meson_dw_hdmi_get_in_bus_format(void *data)
+{
+	struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
+
+	return dw_hdmi->input_bus_format;
+}
+
+static unsigned long meson_dw_hdmi_get_out_bus_format(void *data)
+{
+	struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
+
+	return dw_hdmi->output_bus_format;
+}
+
 static bool meson_hdmi_connector_is_available(struct device *dev)
 {
 	struct device_node *ep, *remote;
@@ -891,6 +962,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 	dw_plat_data->phy_data = meson_dw_hdmi;
 	dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
 	dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
+	dw_plat_data->get_input_bus_format = meson_dw_hdmi_get_in_bus_format;
+	dw_plat_data->get_output_bus_format = meson_dw_hdmi_get_out_bus_format;
+	dw_plat_data->ycbcr_420_allowed = true;
 
 	platform_set_drvdata(pdev, meson_dw_hdmi);
 
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index f6ba35a405f8..27c9c5ead234 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -337,12 +337,17 @@ enum {
 /* 2970 /1 /1 /1 /5 /2  => /1 /1 */
 	MESON_VCLK_HDMI_297000,
 /* 5940 /1 /1 /2 /5 /1  => /1 /1 */
-	MESON_VCLK_HDMI_594000
+	MESON_VCLK_HDMI_594000,
+/* 2970 /1 /1 /1 /5 /1  => /1 /2 */
+	MESON_VCLK_HDMI_594000_YUV420,
 };
 
 struct meson_vclk_params {
+	unsigned int pll_freq;
+	unsigned int phy_freq;
+	unsigned int vclk_freq;
+	unsigned int venc_freq;
 	unsigned int pixel_freq;
-	unsigned int pll_base_freq;
 	unsigned int pll_od1;
 	unsigned int pll_od2;
 	unsigned int pll_od3;
@@ -350,8 +355,11 @@ struct meson_vclk_params {
 	unsigned int vclk_div;
 } params[] = {
 	[MESON_VCLK_HDMI_ENCI_54000] = {
+		.pll_freq = 4320000,
+		.phy_freq = 270000,
+		.vclk_freq = 54000,
+		.venc_freq = 54000,
 		.pixel_freq = 54000,
-		.pll_base_freq = 4320000,
 		.pll_od1 = 4,
 		.pll_od2 = 4,
 		.pll_od3 = 1,
@@ -359,8 +367,11 @@ struct meson_vclk_params {
 		.vclk_div = 1,
 	},
 	[MESON_VCLK_HDMI_DDR_54000] = {
-		.pixel_freq = 54000,
-		.pll_base_freq = 4320000,
+		.pll_freq = 4320000,
+		.phy_freq = 270000,
+		.vclk_freq = 54000,
+		.venc_freq = 54000,
+		.pixel_freq = 27000,
 		.pll_od1 = 4,
 		.pll_od2 = 4,
 		.pll_od3 = 1,
@@ -368,8 +379,11 @@ struct meson_vclk_params {
 		.vclk_div = 1,
 	},
 	[MESON_VCLK_HDMI_DDR_148500] = {
-		.pixel_freq = 148500,
-		.pll_base_freq = 2970000,
+		.pll_freq = 2970000,
+		.phy_freq = 742500,
+		.vclk_freq = 148500,
+		.venc_freq = 148500,
+		.pixel_freq = 74250,
 		.pll_od1 = 4,
 		.pll_od2 = 1,
 		.pll_od3 = 1,
@@ -377,8 +391,11 @@ struct meson_vclk_params {
 		.vclk_div = 1,
 	},
 	[MESON_VCLK_HDMI_74250] = {
+		.pll_freq = 2970000,
+		.phy_freq = 742500,
+		.vclk_freq = 74250,
+		.venc_freq = 74250,
 		.pixel_freq = 74250,
-		.pll_base_freq = 2970000,
 		.pll_od1 = 2,
 		.pll_od2 = 2,
 		.pll_od3 = 2,
@@ -386,8 +403,11 @@ struct meson_vclk_params {
 		.vclk_div = 1,
 	},
 	[MESON_VCLK_HDMI_148500] = {
+		.pll_freq = 2970000,
+		.phy_freq = 1485000,
+		.vclk_freq = 148500,
+		.venc_freq = 148500,
 		.pixel_freq = 148500,
-		.pll_base_freq = 2970000,
 		.pll_od1 = 1,
 		.pll_od2 = 2,
 		.pll_od3 = 2,
@@ -395,8 +415,11 @@ struct meson_vclk_params {
 		.vclk_div = 1,
 	},
 	[MESON_VCLK_HDMI_297000] = {
+		.pll_freq = 2970000,
+		.phy_freq = 2970000,
+		.venc_freq = 297000,
+		.vclk_freq = 297000,
 		.pixel_freq = 297000,
-		.pll_base_freq = 2970000,
 		.pll_od1 = 1,
 		.pll_od2 = 1,
 		.pll_od3 = 1,
@@ -404,14 +427,29 @@ struct meson_vclk_params {
 		.vclk_div = 2,
 	},
 	[MESON_VCLK_HDMI_594000] = {
+		.pll_freq = 5940000,
+		.phy_freq = 5940000,
+		.venc_freq = 594000,
+		.vclk_freq = 594000,
 		.pixel_freq = 594000,
-		.pll_base_freq = 5940000,
 		.pll_od1 = 1,
 		.pll_od2 = 1,
 		.pll_od3 = 2,
 		.vid_pll_div = VID_PLL_DIV_5,
 		.vclk_div = 1,
 	},
+	[MESON_VCLK_HDMI_594000_YUV420] = {
+		.pll_freq = 2970000,
+		.phy_freq = 2970000,
+		.venc_freq = 594000,
+		.vclk_freq = 594000,
+		.pixel_freq = 297000,
+		.pll_od1 = 1,
+		.pll_od2 = 1,
+		.pll_od3 = 1,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
 	{ /* sentinel */ },
 };
 
@@ -616,6 +654,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
 	unsigned int od, m, frac, od1, od2, od3;
 
 	if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
+		/* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */
 		od3 = 1;
 		if (od < 4) {
 			od1 = 2;
@@ -638,21 +677,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
 }
 
 enum drm_mode_status
-meson_vclk_vic_supported_freq(unsigned int freq)
+meson_vclk_vic_supported_freq(unsigned int phy_freq,
+			      unsigned int vclk_freq)
 {
 	int i;
 
-	DRM_DEBUG_DRIVER("freq = %d\n", freq);
+	DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
+			 phy_freq, vclk_freq);
 
 	for (i = 0 ; params[i].pixel_freq ; ++i) {
 		DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
 				 i, params[i].pixel_freq,
 				 FREQ_1000_1001(params[i].pixel_freq));
+		DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n",
+				 i, params[i].phy_freq,
+				 FREQ_1000_1001(params[i].phy_freq/10)*10);
 		/* Match strict frequency */
-		if (freq == params[i].pixel_freq)
+		if (phy_freq == params[i].phy_freq &&
+		    vclk_freq == params[i].vclk_freq)
 			return MODE_OK;
 		/* Match 1000/1001 variant */
-		if (freq == FREQ_1000_1001(params[i].pixel_freq))
+		if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) &&
+		    vclk_freq == FREQ_1000_1001(params[i].vclk_freq))
 			return MODE_OK;
 	}
 
@@ -863,8 +909,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
 }
 
 void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
-		      unsigned int vclk_freq, unsigned int venc_freq,
-		      unsigned int dac_freq, bool hdmi_use_enci)
+		      unsigned int phy_freq, unsigned int vclk_freq,
+		      unsigned int venc_freq, unsigned int dac_freq,
+		      bool hdmi_use_enci)
 {
 	bool vic_alternate_clock = false;
 	unsigned int freq;
@@ -883,7 +930,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
 		 * - venc_div = 1
 		 * - encp encoder
 		 */
-		meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
+		meson_vclk_set(priv, phy_freq, 0, 0, 0,
 			       VID_PLL_DIV_5, 2, 1, 1, false, false);
 		return;
 	}
@@ -905,9 +952,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
 	}
 
 	for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
-		if (vclk_freq == params[freq].pixel_freq ||
-		    vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
-			if (vclk_freq != params[freq].pixel_freq)
+		if ((phy_freq == params[freq].phy_freq ||
+		     phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) &&
+		    (vclk_freq == params[freq].vclk_freq ||
+		     vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) {
+			if (vclk_freq != params[freq].vclk_freq)
 				vic_alternate_clock = true;
 			else
 				vic_alternate_clock = false;
@@ -936,7 +985,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
 		return;
 	}
 
-	meson_vclk_set(priv, params[freq].pll_base_freq,
+	meson_vclk_set(priv, params[freq].pll_freq,
 		       params[freq].pll_od1, params[freq].pll_od2,
 		       params[freq].pll_od3, params[freq].vid_pll_div,
 		       params[freq].vclk_div, hdmi_tx_div, venc_div,
diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
index 4bd8752da02a..c4d19ddfcd79 100644
--- a/drivers/gpu/drm/meson/meson_vclk.h
+++ b/drivers/gpu/drm/meson/meson_vclk.h
@@ -33,10 +33,11 @@ enum {
 enum drm_mode_status
 meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
 enum drm_mode_status
-meson_vclk_vic_supported_freq(unsigned int freq);
+meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq);
 
 void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
-		      unsigned int vclk_freq, unsigned int venc_freq,
-		      unsigned int dac_freq, bool hdmi_use_enci);
+		      unsigned int phy_freq, unsigned int vclk_freq,
+		      unsigned int venc_freq, unsigned int dac_freq,
+		      bool hdmi_use_enci);
 
 #endif /* __MESON_VCLK_H */
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 66d73a932d19..04956e3b64b1 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -956,6 +956,8 @@ bool meson_venc_hdmi_venc_repeat(int vic)
 EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat);
 
 void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
+			      unsigned int ycrcb_map,
+			      bool yuv420_mode,
 			      struct drm_display_mode *mode)
 {
 	union meson_hdmi_venc_mode *vmode = NULL;
@@ -1506,8 +1508,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
 	writel_relaxed((use_enci ? 1 : 2) |
 		       (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) |
 		       (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) |
-		       4 << 5 |
-		       (venc_repeat ? 1 << 8 : 0) |
+		       (ycrcb_map << 5) |
+		       (venc_repeat || yuv420_mode ? 1 << 8 : 0) |
 		       (hdmi_repeat ? 1 << 12 : 0),
 		       priv->io_base + _REG(VPU_HDMI_SETTING));
 
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
index 97eaebbfa0c4..5580bf38e381 100644
--- a/drivers/gpu/drm/meson/meson_venc.h
+++ b/drivers/gpu/drm/meson/meson_venc.h
@@ -33,6 +33,15 @@ enum {
 	MESON_VENC_MODE_HDMI,
 };
 
+enum {
+	MESON_VENC_MAP_CR_Y_CB = 0,
+	MESON_VENC_MAP_Y_CB_CR,
+	MESON_VENC_MAP_Y_CR_CB,
+	MESON_VENC_MAP_CB_CR_Y,
+	MESON_VENC_MAP_CB_Y_CR,
+	MESON_VENC_MAP_CR_CB_Y,
+};
+
 struct meson_cvbs_enci_mode {
 	unsigned int mode_tag;
 	unsigned int hso_begin; /* HSO begin position */
@@ -70,6 +79,8 @@ extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
 void meson_venci_cvbs_mode_set(struct meson_drm *priv,
 			       struct meson_cvbs_enci_mode *mode);
 void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
+			      unsigned int ycrcb_map,
+			      bool yuv420_mode,
 			      struct drm_display_mode *mode);
 unsigned int meson_venci_get_field(struct meson_drm *priv);
 
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
index f7945bae3b4a..38a1117b1183 100644
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -207,7 +207,8 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
 			/* Setup 27MHz vclk2 for ENCI and VDAC */
 			meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
 					 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
-					 MESON_VCLK_CVBS, true);
+					 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
+					 true);
 			break;
 		}
 	}
-- 
2.19.2


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

* [PATCH RFC v2 8/8] drm/meson: Output in YUV444 if sink supports it
  2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
                   ` (6 preceding siblings ...)
  2018-11-30 13:43 ` [PATCH RFC v2 7/8] drm/meson: Add YUV420 output support Neil Armstrong
@ 2018-11-30 13:43 ` Neil Armstrong
  7 siblings, 0 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-11-30 13:43 UTC (permalink / raw)
  To: architt, a.hajda, Laurent.pinchart
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-kernel

With the YUV420 handling, we can dynamically setup the HDMI output
pixel format depending on the mode and connector info.
So now, we can output in YUV444, which is the native video pipeline
format, directly to the HDMI Sink if it's supported without
necessarily involving the HDMI Controller CSC.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_dw_hdmi.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 83360f37d9ce..1b7092ab1be8 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -670,7 +670,10 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
 		dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
 	} else {
 		dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
-		dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
+			dw_hdmi->output_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
+		else
+			dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 	}
 
 	return 0;
-- 
2.19.2


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

* Re: [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support
  2018-11-30 13:42 ` [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support Neil Armstrong
@ 2018-12-14 12:12   ` Heiko Stuebner
  2018-12-18 12:25   ` Andrzej Hajda
  1 sibling, 0 replies; 22+ messages in thread
From: Heiko Stuebner @ 2018-12-14 12:12 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	maxime.ripard, dri-devel, linux-amlogic, linux-kernel,
	Nickey Yang, Huicong Xu

Am Freitag, 30. November 2018, 14:42:54 CET schrieb Neil Armstrong:
> Add support for SCDC Setup for TMDS Clock > 3.4GHz and enable TMDS
> Scrambling when supported or mandatory.
> 
> This patch also adds an helper to setup the control bit to support
> the high TMDS Bit Period/TMDS Clock-Period Ratio as required with
> TMDS Clock > 3.4GHz for HDMI2.0 3840x2160@60/50 modes.
> 
> These changes were based on work done by Huicong Xu <xhc@rock-chips.com>
> and Nickey Yang <nickey.yang@rock-chips.com> to support HDMI2.0 modes
> on the Rockchip 4.4 BSP kernel at [1]
> 
> [1] https://github.com/rockchip-linux/kernel/tree/release-4.4
> 
> Cc: Nickey Yang <nickey.yang@rock-chips.com>
> Cc: Huicong Xu <xhc@rock-chips.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

sorry this took a bit longer, but I can confirm that the 4 relevant
patches (1, 4, 5, 6) at least still provide 1080p hdmi output on
rk3288 (with internal hdmiphy) and rk3328 (with external innosilicon
hdmiphy). I don't know how to test newly added features, but at
least the patches don't seem to break existing users, so

on rk3288 and rk3328
Tested-by: Heiko Stuebner <heiko@sntech.de>




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

* Re: [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output
  2018-11-30 13:42 ` [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output Neil Armstrong
@ 2018-12-14 12:13   ` Heiko Stuebner
  2018-12-18 13:41   ` Andrzej Hajda
  1 sibling, 0 replies; 22+ messages in thread
From: Heiko Stuebner @ 2018-12-14 12:13 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	maxime.ripard, dri-devel, linux-amlogic, linux-kernel,
	Zheng Yang

Am Freitag, 30. November 2018, 14:42:57 CET schrieb Neil Armstrong:
> In order to support the HDMI2.0 YUV420 display modes, this patch
> adds support for the YUV420 TMDS Clock divided by 2 and the controller
> passthrough mode.
> 
> YUV420 Synopsys PHY support will need some specific configuration table
> to support theses modes.
> 
> This patch is based on work from Zheng Yang <zhengyang@rock-chips.com> in
> the Rockchip Linux 4.4 BSP at [1]
> 
> [1] https://github.com/rockchip-linux/kernel/tree/release-4.4
> 
> Cc: Zheng Yang <zhengyang@rock-chips.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Please see comments in patch1 for details.

on rk3288 and rk3328
Tested-by: Heiko Stuebner <heiko@sntech.de>




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

* Re: [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info
  2018-11-30 13:42 ` [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info Neil Armstrong
@ 2018-12-14 12:13   ` Heiko Stuebner
  2018-12-19  7:26   ` Andrzej Hajda
  1 sibling, 0 replies; 22+ messages in thread
From: Heiko Stuebner @ 2018-12-14 12:13 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	maxime.ripard, Zheng Yang, dri-devel, linux-amlogic,
	linux-kernel

Am Freitag, 30. November 2018, 14:42:58 CET schrieb Neil Armstrong:
> From: Zheng Yang <zhengyang@rock-chips.com>
> 
> To get input/output bus_format/enc_format dynamically, this patch
> introduce following funstion in plat_data:
> 	- get_input_bus_format
> 	- get_output_bus_format
> 	- get_enc_in_encoding
> 	- get_enc_out_encoding
> 
> Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Please see comments in patch1 for details.

on rk3288 and rk3328
Tested-by: Heiko Stuebner <heiko@sntech.de>




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

* Re: [PATCH RFC v2 6/8] drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2018-11-30 13:42 ` [PATCH RFC v2 6/8] drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
@ 2018-12-14 12:13   ` Heiko Stuebner
  0 siblings, 0 replies; 22+ messages in thread
From: Heiko Stuebner @ 2018-12-14 12:13 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: architt, a.hajda, Laurent.pinchart, Philipp Zabel, Sandy Huang,
	maxime.ripard, dri-devel, linux-amlogic, linux-kernel

Am Freitag, 30. November 2018, 14:42:59 CET schrieb Neil Armstrong:
> Now the DW-HDMI Controller supports the HDMI2.0 modes, enable support
> for these modes in the connector if the platform supports them.
> We limit these modes to DW-HDMI IP version >= 0x200a which
> are designed to support HDMI2.0 display modes.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Please see comments in patch1 for details.

on rk3288 and rk3328
Tested-by: Heiko Stuebner <heiko@sntech.de>




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

* Re: [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support
  2018-11-30 13:42 ` [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support Neil Armstrong
  2018-12-14 12:12   ` Heiko Stuebner
@ 2018-12-18 12:25   ` Andrzej Hajda
  2018-12-18 13:17     ` Neil Armstrong
  1 sibling, 1 reply; 22+ messages in thread
From: Andrzej Hajda @ 2018-12-18 12:25 UTC (permalink / raw)
  To: Neil Armstrong, architt, Laurent.pinchart, Philipp Zabel,
	Sandy Huang, Heiko Stübner, maxime.ripard
  Cc: dri-devel, linux-amlogic, linux-kernel, Nickey Yang, Huicong Xu

Hi Neil,


On 30.11.2018 14:42, Neil Armstrong wrote:
> Add support for SCDC Setup for TMDS Clock > 3.4GHz and enable TMDS
> Scrambling when supported or mandatory.
>
> This patch also adds an helper to setup the control bit to support
> the high TMDS Bit Period/TMDS Clock-Period Ratio as required with
> TMDS Clock > 3.4GHz for HDMI2.0 3840x2160@60/50 modes.
>
> These changes were based on work done by Huicong Xu <xhc@rock-chips.com>
> and Nickey Yang <nickey.yang@rock-chips.com> to support HDMI2.0 modes
> on the Rockchip 4.4 BSP kernel at [1]
>
> [1] https://github.com/rockchip-linux/kernel/tree/release-4.4
>
> Cc: Nickey Yang <nickey.yang@rock-chips.com>
> Cc: Huicong Xu <xhc@rock-chips.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 88 ++++++++++++++++++++++-
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.h |  1 +
>  include/drm/bridge/dw_hdmi.h              |  1 +
>  3 files changed, 87 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 64c3cf027518..fcd941d52753 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -28,6 +28,7 @@
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_encoder_slave.h>
> +#include <drm/drm_scdc_helper.h>
>  #include <drm/bridge/dw_hdmi.h>
>  
>  #include <uapi/linux/media-bus-format.h>
> @@ -43,6 +44,11 @@
>  
>  #define HDMI_EDID_LEN		512
>  
> +/* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */
> +#define SCDC_MIN_SOURCE_VERSION	0x1
> +
> +#define HDMI14_MAX_TMDSCLK	340000000
> +
>  enum hdmi_datamap {
>  	RGB444_8B = 0x01,
>  	RGB444_10B = 0x03,
> @@ -1015,6 +1021,33 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
>  }
>  EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
>  
> +/*
> + * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
> + * - The Source shall suspend transmission of the TMDS clock and data
> + * - The Source shall write to the TMDS_Bit_Clock_Ratio bit to change it
> + * from a 0 to a 1 or from a 1 to a 0
> + * - The Source shall allow a minimum of 1 ms and a maximum of 100 ms from
> + * the time the TMDS_Bit_Clock_Ratio bit is written until resuming
> + * transmission of TMDS clock and data
> + *
> + * To respect the 100ms maximum delay, the dw_hdmi_set_high_tmds_clock_ratio()
> + * helper should called right before enabling the TMDS Clock and Data in
> + * the PHY configuration callback.
> + */
> +void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
> +{
> +	unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock;
> +
> +	/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
> +	if (hdmi->connector.display_info.hdmi.scdc.supported) {
> +		if (mtmdsclock > HDMI14_MAX_TMDSCLK)
> +			drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
> +		else
> +			drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
> +
>  static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
>  {
>  	hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
> @@ -1216,6 +1249,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
>  
>  	dw_hdmi_phy_power_off(hdmi);
>  
> +	dw_hdmi_set_high_tmds_clock_ratio(hdmi);
> +
>  	/* Leave low power consumption mode by asserting SVSRET. */
>  	if (phy->has_svsret)
>  		dw_hdmi_phy_enable_svsret(hdmi, 1);
> @@ -1237,6 +1272,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
>  		return ret;
>  	}
>  
> +	/* Wait for resuming transmission of TMDS clock and data */
> +	if (mpixelclock > HDMI14_MAX_TMDSCLK)
> +		msleep(100);
> +
>  	return dw_hdmi_phy_power_on(hdmi);
>  }
>  
> @@ -1340,11 +1379,12 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
>  
>  static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>  {
> +	bool is_hdmi2_sink = hdmi->connector.display_info.hdmi.scdc.supported;
>  	struct hdmi_avi_infoframe frame;
>  	u8 val;
>  
>  	/* Initialise info frame from DRM mode */
> -	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
> +	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2_sink);
>  
>  	if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
>  		frame.colorspace = HDMI_COLORSPACE_YUV444;
> @@ -1503,7 +1543,8 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
>  static void hdmi_av_composer(struct dw_hdmi *hdmi,
>  			     const struct drm_display_mode *mode)
>  {
> -	u8 inv_val;
> +	u8 inv_val, bytes;
> +	struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
>  	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
>  	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
>  	unsigned int vdisplay;
> @@ -1513,7 +1554,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
>  	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
>  
>  	/* Set up HDMI_FC_INVIDCONF */
> -	inv_val = (hdmi->hdmi_data.hdcp_enable ?
> +	inv_val = (hdmi->hdmi_data.hdcp_enable ||
> +		   vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
> +		   hdmi_info->scdc.scrambling.low_rates ?
>  		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
>  		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
>  
> @@ -1562,6 +1605,45 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
>  		vsync_len /= 2;
>  	}
>  
> +	/* Scrambling Control */
> +	if (hdmi_info->scdc.supported) {
> +		if (vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
> +		    hdmi_info->scdc.scrambling.low_rates) {
> +			/*
> +			 * HDMI2.0 Specifies the following procedure:
> +			 * After the Source Device has determined that
> +			 * SCDC_Present is set (=1), the Source Device should
> +			 * write the accurate Version of the Source Device
> +			 * to the Source Version field in the SCDCS.
> +			 * Source Devices compliant shall set the
> +			 * Source Version = 1.
> +			 */
> +			drm_scdc_readb(&hdmi->i2c->adap, SCDC_SINK_VERSION,
> +				       &bytes);
> +			drm_scdc_writeb(&hdmi->i2c->adap, SCDC_SOURCE_VERSION,
> +				min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
> +
> +			/* Enabled Scrambling in the Sink */
> +			drm_scdc_set_scrambling(&hdmi->i2c->adap, 1);
> +
> +			/*
> +			 * To activate the scrambler feature, you must ensure
> +			 * that the quasi-static configuration bit
> +			 * fc_invidconf.HDCP_keepout is set at configuration
> +			 * time, before the required mc_swrstzreq.tmdsswrst_req
> +			 * reset request is issued.
> +			 */
> +			hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,


Are you sure you need casting to u8?


> +				    HDMI_MC_SWRSTZ);
> +			hdmi_writeb(hdmi, 1, HDMI_FC_SCRAMBLER_CTRL);
> +		} else {
> +			hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
> +			hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
> +				    HDMI_MC_SWRSTZ);
> +			drm_scdc_set_scrambling(&hdmi->i2c->adap, 0);
> +		}
> +	}
> +
>  	/* Set up horizontal active pixel width */
>  	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
>  	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> index 9d90eb9c46e5..3f3c616eba97 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> @@ -255,6 +255,7 @@
>  #define HDMI_FC_MASK2                           0x10DA
>  #define HDMI_FC_POL2                            0x10DB
>  #define HDMI_FC_PRCONF                          0x10E0
> +#define HDMI_FC_SCRAMBLER_CTRL                  0x10E1
>  
>  #define HDMI_FC_GMD_STAT                        0x1100
>  #define HDMI_FC_GMD_EN                          0x1101
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index 9c56412bb2cf..7a02744ce0bc 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -157,6 +157,7 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
>  void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
>  void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
>  void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
> +void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi);
>  
>  /* PHY configuration */
>  void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);

Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>

 --
Regards
Andrzej




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

* Re: [PATCH RFC v2 2/8] drm/meson: add HDMI div40 TMDS mode
  2018-11-30 13:42 ` [PATCH RFC v2 2/8] drm/meson: add HDMI div40 TMDS mode Neil Armstrong
@ 2018-12-18 12:36   ` Andrzej Hajda
  2018-12-18 13:19     ` Neil Armstrong
  0 siblings, 1 reply; 22+ messages in thread
From: Andrzej Hajda @ 2018-12-18 12:36 UTC (permalink / raw)
  To: Neil Armstrong, architt, Laurent.pinchart
  Cc: dri-devel, linux-amlogic, linux-kernel

On 30.11.2018 14:42, Neil Armstrong wrote:
> Add support for TMDS Clock > 3.4GHz for HDMI2.0 display modes.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/meson/meson_dw_hdmi.c | 24 ++++++++++++++++++++----
>  1 file changed, 20 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> index 807111ebfdd9..b8775102b100 100644
> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> @@ -365,7 +365,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
>  	unsigned int wr_clk =
>  		readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
>  
> -	DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
> +	DRM_DEBUG_DRIVER("%d:\"%s\" div%d\n", mode->base.id, mode->name,
> +			 mode->clock > 340000 ? 40 : 10);
>  
>  	/* Enable clocks */
>  	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
> @@ -385,9 +386,17 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
>  	/* Enable normal output to PHY */
>  	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
>  
> -	/* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
> -	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
> -	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
> +	/* TMDS pattern setup (TOFIX Handle the YUV420 case) */
> +	if (mode->clock > 340000) {
> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
> +				  0x03ff03ff);
> +	} else {
> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
> +				  0x001f001f);
> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
> +				  0x001f001f);
> +	}
>  
>  	/* Load TMDS pattern */
>  	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
> @@ -413,6 +422,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
>  	/* Disable clock, fifo, fifo_wr */
>  	regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
>  
> +	dw_hdmi_set_high_tmds_clock_ratio(hdmi);
> +
>  	msleep(100);
>  
>  	/* Reset PHY 3 times in a row */
> @@ -562,6 +573,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
>  		mode->vdisplay, mode->vsync_start,
>  		mode->vsync_end, mode->vtotal, mode->type, mode->flags);
>  
> +	/* If sink max TMDS clock < 340MHz, we reject the HDMI2.0 modes */
> +	if (mode->clock > 340000 &&
> +	    connector->display_info.max_tmds_clock < 340000)
> +		return MODE_BAD;
> +


Why not just:

if (mode->clock > connector->display_info.max_tmds_clock)
	return MODE_BAD;


Regards

Andrzej


>  	/* Check against non-VIC supported modes */
>  	if (!vic) {
>  		status = meson_venc_hdmi_supported_mode(mode);



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

* Re: [PATCH RFC v2 3/8] drm/meson: add support for HDMI2.0 2160p modes
  2018-11-30 13:42 ` [PATCH RFC v2 3/8] drm/meson: add support for HDMI2.0 2160p modes Neil Armstrong
@ 2018-12-18 12:37   ` Andrzej Hajda
  0 siblings, 0 replies; 22+ messages in thread
From: Andrzej Hajda @ 2018-12-18 12:37 UTC (permalink / raw)
  To: Neil Armstrong, architt, Laurent.pinchart
  Cc: dri-devel, linux-amlogic, linux-kernel

On 30.11.2018 14:42, Neil Armstrong wrote:
> Now we support the TMDS Clock > 3.4GHz and support the SCDC Control
> operation in the DW-HDMI Controller, we can enable support for the
> HDMI2.0 3840x2160@60/50 RGB444 display modes.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/meson/meson_venc.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
> index 0ba04f6813e6..66d73a932d19 100644
> --- a/drivers/gpu/drm/meson/meson_venc.c
> +++ b/drivers/gpu/drm/meson/meson_venc.c
> @@ -848,6 +848,8 @@ struct meson_hdmi_venc_vic_mode {
>  	{ 93, &meson_hdmi_encp_mode_2160p24 },
>  	{ 94, &meson_hdmi_encp_mode_2160p25 },
>  	{ 95, &meson_hdmi_encp_mode_2160p30 },
> +	{ 96, &meson_hdmi_encp_mode_2160p25 },
> +	{ 97, &meson_hdmi_encp_mode_2160p30 },
>  	{ 0, NULL}, /* sentinel */
>  };
>  

Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>

 --
Regards
Andrzej


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

* Re: [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support
  2018-12-18 12:25   ` Andrzej Hajda
@ 2018-12-18 13:17     ` Neil Armstrong
  0 siblings, 0 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-12-18 13:17 UTC (permalink / raw)
  To: Andrzej Hajda, architt, Laurent.pinchart, Philipp Zabel,
	Sandy Huang, Heiko Stübner, maxime.ripard
  Cc: dri-devel, linux-amlogic, linux-kernel, Nickey Yang, Huicong Xu

On 18/12/2018 13:25, Andrzej Hajda wrote:
> Hi Neil,
> 
> 
> On 30.11.2018 14:42, Neil Armstrong wrote:
>> Add support for SCDC Setup for TMDS Clock > 3.4GHz and enable TMDS
>> Scrambling when supported or mandatory.
>>
>> This patch also adds an helper to setup the control bit to support
>> the high TMDS Bit Period/TMDS Clock-Period Ratio as required with
>> TMDS Clock > 3.4GHz for HDMI2.0 3840x2160@60/50 modes.
>>
>> These changes were based on work done by Huicong Xu <xhc@rock-chips.com>
>> and Nickey Yang <nickey.yang@rock-chips.com> to support HDMI2.0 modes
>> on the Rockchip 4.4 BSP kernel at [1]
>>
>> [1] https://github.com/rockchip-linux/kernel/tree/release-4.4
>>
>> Cc: Nickey Yang <nickey.yang@rock-chips.com>
>> Cc: Huicong Xu <xhc@rock-chips.com>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 88 ++++++++++++++++++++++-
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.h |  1 +
>>  include/drm/bridge/dw_hdmi.h              |  1 +
>>  3 files changed, 87 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> index 64c3cf027518..fcd941d52753 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -28,6 +28,7 @@
>>  #include <drm/drm_crtc_helper.h>
>>  #include <drm/drm_edid.h>
>>  #include <drm/drm_encoder_slave.h>
>> +#include <drm/drm_scdc_helper.h>
>>  #include <drm/bridge/dw_hdmi.h>
>>  
>>  #include <uapi/linux/media-bus-format.h>
>> @@ -43,6 +44,11 @@
>>  
>>  #define HDMI_EDID_LEN		512
>>  
>> +/* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */
>> +#define SCDC_MIN_SOURCE_VERSION	0x1
>> +
>> +#define HDMI14_MAX_TMDSCLK	340000000
>> +
>>  enum hdmi_datamap {
>>  	RGB444_8B = 0x01,
>>  	RGB444_10B = 0x03,
>> @@ -1015,6 +1021,33 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
>>  }
>>  EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
>>  
>> +/*
>> + * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
>> + * - The Source shall suspend transmission of the TMDS clock and data
>> + * - The Source shall write to the TMDS_Bit_Clock_Ratio bit to change it
>> + * from a 0 to a 1 or from a 1 to a 0
>> + * - The Source shall allow a minimum of 1 ms and a maximum of 100 ms from
>> + * the time the TMDS_Bit_Clock_Ratio bit is written until resuming
>> + * transmission of TMDS clock and data
>> + *
>> + * To respect the 100ms maximum delay, the dw_hdmi_set_high_tmds_clock_ratio()
>> + * helper should called right before enabling the TMDS Clock and Data in
>> + * the PHY configuration callback.
>> + */
>> +void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
>> +{
>> +	unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock;
>> +
>> +	/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
>> +	if (hdmi->connector.display_info.hdmi.scdc.supported) {
>> +		if (mtmdsclock > HDMI14_MAX_TMDSCLK)
>> +			drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
>> +		else
>> +			drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
>> +	}
>> +}
>> +EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
>> +
>>  static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
>>  {
>>  	hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
>> @@ -1216,6 +1249,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
>>  
>>  	dw_hdmi_phy_power_off(hdmi);
>>  
>> +	dw_hdmi_set_high_tmds_clock_ratio(hdmi);
>> +
>>  	/* Leave low power consumption mode by asserting SVSRET. */
>>  	if (phy->has_svsret)
>>  		dw_hdmi_phy_enable_svsret(hdmi, 1);
>> @@ -1237,6 +1272,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
>>  		return ret;
>>  	}
>>  
>> +	/* Wait for resuming transmission of TMDS clock and data */
>> +	if (mpixelclock > HDMI14_MAX_TMDSCLK)
>> +		msleep(100);
>> +
>>  	return dw_hdmi_phy_power_on(hdmi);
>>  }
>>  
>> @@ -1340,11 +1379,12 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
>>  
>>  static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>>  {
>> +	bool is_hdmi2_sink = hdmi->connector.display_info.hdmi.scdc.supported;
>>  	struct hdmi_avi_infoframe frame;
>>  	u8 val;
>>  
>>  	/* Initialise info frame from DRM mode */
>> -	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
>> +	drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2_sink);
>>  
>>  	if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
>>  		frame.colorspace = HDMI_COLORSPACE_YUV444;
>> @@ -1503,7 +1543,8 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
>>  static void hdmi_av_composer(struct dw_hdmi *hdmi,
>>  			     const struct drm_display_mode *mode)
>>  {
>> -	u8 inv_val;
>> +	u8 inv_val, bytes;
>> +	struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
>>  	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
>>  	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
>>  	unsigned int vdisplay;
>> @@ -1513,7 +1554,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
>>  	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
>>  
>>  	/* Set up HDMI_FC_INVIDCONF */
>> -	inv_val = (hdmi->hdmi_data.hdcp_enable ?
>> +	inv_val = (hdmi->hdmi_data.hdcp_enable ||
>> +		   vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
>> +		   hdmi_info->scdc.scrambling.low_rates ?
>>  		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
>>  		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
>>  
>> @@ -1562,6 +1605,45 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
>>  		vsync_len /= 2;
>>  	}
>>  
>> +	/* Scrambling Control */
>> +	if (hdmi_info->scdc.supported) {
>> +		if (vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
>> +		    hdmi_info->scdc.scrambling.low_rates) {
>> +			/*
>> +			 * HDMI2.0 Specifies the following procedure:
>> +			 * After the Source Device has determined that
>> +			 * SCDC_Present is set (=1), the Source Device should
>> +			 * write the accurate Version of the Source Device
>> +			 * to the Source Version field in the SCDCS.
>> +			 * Source Devices compliant shall set the
>> +			 * Source Version = 1.
>> +			 */
>> +			drm_scdc_readb(&hdmi->i2c->adap, SCDC_SINK_VERSION,
>> +				       &bytes);
>> +			drm_scdc_writeb(&hdmi->i2c->adap, SCDC_SOURCE_VERSION,
>> +				min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
>> +
>> +			/* Enabled Scrambling in the Sink */
>> +			drm_scdc_set_scrambling(&hdmi->i2c->adap, 1);
>> +
>> +			/*
>> +			 * To activate the scrambler feature, you must ensure
>> +			 * that the quasi-static configuration bit
>> +			 * fc_invidconf.HDCP_keepout is set at configuration
>> +			 * time, before the required mc_swrstzreq.tmdsswrst_req
>> +			 * reset request is issued.
>> +			 */
>> +			hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
> 
> 
> Are you sure you need casting to u8?

Not sure, it's already casted in dw_hdmi_clear_overflow() :

...
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
...

I'll check if it's really needed.

> 
> 
>> +				    HDMI_MC_SWRSTZ);
>> +			hdmi_writeb(hdmi, 1, HDMI_FC_SCRAMBLER_CTRL);
>> +		} else {
>> +			hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
>> +			hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
>> +				    HDMI_MC_SWRSTZ);
>> +			drm_scdc_set_scrambling(&hdmi->i2c->adap, 0);
>> +		}
>> +	}
>> +
>>  	/* Set up horizontal active pixel width */
>>  	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
>>  	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
>> index 9d90eb9c46e5..3f3c616eba97 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
>> @@ -255,6 +255,7 @@
>>  #define HDMI_FC_MASK2                           0x10DA
>>  #define HDMI_FC_POL2                            0x10DB
>>  #define HDMI_FC_PRCONF                          0x10E0
>> +#define HDMI_FC_SCRAMBLER_CTRL                  0x10E1
>>  
>>  #define HDMI_FC_GMD_STAT                        0x1100
>>  #define HDMI_FC_GMD_EN                          0x1101
>> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
>> index 9c56412bb2cf..7a02744ce0bc 100644
>> --- a/include/drm/bridge/dw_hdmi.h
>> +++ b/include/drm/bridge/dw_hdmi.h
>> @@ -157,6 +157,7 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
>>  void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
>>  void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
>>  void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
>> +void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi);
>>  
>>  /* PHY configuration */
>>  void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
> 
> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>

Thanks,
Neil

> 
>  --
> Regards
> Andrzej
> 
> 
> 


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

* Re: [PATCH RFC v2 2/8] drm/meson: add HDMI div40 TMDS mode
  2018-12-18 12:36   ` Andrzej Hajda
@ 2018-12-18 13:19     ` Neil Armstrong
  0 siblings, 0 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-12-18 13:19 UTC (permalink / raw)
  To: Andrzej Hajda, architt, Laurent.pinchart
  Cc: dri-devel, linux-amlogic, linux-kernel

On 18/12/2018 13:36, Andrzej Hajda wrote:
> On 30.11.2018 14:42, Neil Armstrong wrote:
>> Add support for TMDS Clock > 3.4GHz for HDMI2.0 display modes.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/meson/meson_dw_hdmi.c | 24 ++++++++++++++++++++----
>>  1 file changed, 20 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
>> index 807111ebfdd9..b8775102b100 100644
>> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
>> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
>> @@ -365,7 +365,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
>>  	unsigned int wr_clk =
>>  		readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
>>  
>> -	DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
>> +	DRM_DEBUG_DRIVER("%d:\"%s\" div%d\n", mode->base.id, mode->name,
>> +			 mode->clock > 340000 ? 40 : 10);
>>  
>>  	/* Enable clocks */
>>  	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
>> @@ -385,9 +386,17 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
>>  	/* Enable normal output to PHY */
>>  	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
>>  
>> -	/* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
>> -	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
>> -	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
>> +	/* TMDS pattern setup (TOFIX Handle the YUV420 case) */
>> +	if (mode->clock > 340000) {
>> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
>> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
>> +				  0x03ff03ff);
>> +	} else {
>> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
>> +				  0x001f001f);
>> +		dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
>> +				  0x001f001f);
>> +	}
>>  
>>  	/* Load TMDS pattern */
>>  	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
>> @@ -413,6 +422,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
>>  	/* Disable clock, fifo, fifo_wr */
>>  	regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
>>  
>> +	dw_hdmi_set_high_tmds_clock_ratio(hdmi);
>> +
>>  	msleep(100);
>>  
>>  	/* Reset PHY 3 times in a row */
>> @@ -562,6 +573,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
>>  		mode->vdisplay, mode->vsync_start,
>>  		mode->vsync_end, mode->vtotal, mode->type, mode->flags);
>>  
>> +	/* If sink max TMDS clock < 340MHz, we reject the HDMI2.0 modes */
>> +	if (mode->clock > 340000 &&
>> +	    connector->display_info.max_tmds_clock < 340000)
>> +		return MODE_BAD;
>> +
> 
> 
> Why not just:
> 
> if (mode->clock > connector->display_info.max_tmds_clock)
> 	return MODE_BAD;

Hmm, let me check, it may be better indeed.

Neil

> 
> 
> Regards
> 
> Andrzej
> 
> 
>>  	/* Check against non-VIC supported modes */
>>  	if (!vic) {
>>  		status = meson_venc_hdmi_supported_mode(mode);
> 
> 


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

* Re: [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output
  2018-11-30 13:42 ` [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output Neil Armstrong
  2018-12-14 12:13   ` Heiko Stuebner
@ 2018-12-18 13:41   ` Andrzej Hajda
  1 sibling, 0 replies; 22+ messages in thread
From: Andrzej Hajda @ 2018-12-18 13:41 UTC (permalink / raw)
  To: Neil Armstrong, architt, Laurent.pinchart, Philipp Zabel,
	Sandy Huang, Heiko Stübner, maxime.ripard
  Cc: dri-devel, linux-amlogic, linux-kernel, Zheng Yang

On 30.11.2018 14:42, Neil Armstrong wrote:
> In order to support the HDMI2.0 YUV420 display modes, this patch
> adds support for the YUV420 TMDS Clock divided by 2 and the controller
> passthrough mode.
>
> YUV420 Synopsys PHY support will need some specific configuration table
> to support theses modes.
>
> This patch is based on work from Zheng Yang <zhengyang@rock-chips.com> in
> the Rockchip Linux 4.4 BSP at [1]
>
> [1] https://github.com/rockchip-linux/kernel/tree/release-4.4
>
> Cc: Zheng Yang <zhengyang@rock-chips.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>


Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>

 --
Regards
Andrzej



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

* Re: [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info
  2018-11-30 13:42 ` [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info Neil Armstrong
  2018-12-14 12:13   ` Heiko Stuebner
@ 2018-12-19  7:26   ` Andrzej Hajda
  2018-12-19  7:50     ` Laurent Pinchart
  1 sibling, 1 reply; 22+ messages in thread
From: Andrzej Hajda @ 2018-12-19  7:26 UTC (permalink / raw)
  To: Neil Armstrong, architt, Laurent.pinchart, Philipp Zabel,
	Sandy Huang, Heiko Stübner, maxime.ripard
  Cc: Zheng Yang, dri-devel, linux-amlogic, linux-kernel

On 30.11.2018 14:42, Neil Armstrong wrote:
> From: Zheng Yang <zhengyang@rock-chips.com>
>
> To get input/output bus_format/enc_format dynamically, this patch
> introduce following funstion in plat_data:
> 	- get_input_bus_format
> 	- get_output_bus_format
> 	- get_enc_in_encoding
> 	- get_enc_out_encoding


It seems fishy. On one side description says about dynamic resolution of
formats and encodings.

On the other side these functions as only argument takes platform_data
which should be rather static.

Where is this "dynamic" thing? The only usage of these callbacks I have
found in next patches is also not dynamic, the functions just return
some static value.

Moreover function takes void* argument, which is again something
suspicious, why cannot you pass know structure?

And finally encoding usually should depend on display mode, it should
not depend only static data.


What kind of problems do you want to solve here?


Regards

Andrzej



>
> Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++++++------
>  include/drm/bridge/dw_hdmi.h              |  5 ++++
>  2 files changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 4a9a24e854db..bd564ffdf18b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -1810,6 +1810,7 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
>  static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>  {
>  	int ret;
> +	void *data = hdmi->plat_data->phy_data;
>  
>  	hdmi_disable_overflow_interrupts(hdmi);
>  
> @@ -1821,10 +1822,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>  		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
>  	}
>  
> -	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
> -	    (hdmi->vic == 21) || (hdmi->vic == 22) ||
> -	    (hdmi->vic == 2) || (hdmi->vic == 3) ||
> -	    (hdmi->vic == 17) || (hdmi->vic == 18))
> +	if (hdmi->plat_data->get_enc_out_encoding)
> +		hdmi->hdmi_data.enc_out_encoding =
> +			hdmi->plat_data->get_enc_out_encoding(data);
> +	else if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
> +		 (hdmi->vic == 21) || (hdmi->vic == 22) ||
> +		 (hdmi->vic == 2) || (hdmi->vic == 3) ||
> +		 (hdmi->vic == 17) || (hdmi->vic == 18))
>  		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601;
>  	else
>  		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709;
> @@ -1833,21 +1837,31 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>  	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
>  
>  	/* TOFIX: Get input format from plat data or fallback to RGB888 */
> -	if (hdmi->plat_data->input_bus_format)
> +	if (hdmi->plat_data->get_input_bus_format)
> +		hdmi->hdmi_data.enc_in_bus_format =
> +			hdmi->plat_data->get_input_bus_format(data);
> +	else if (hdmi->plat_data->input_bus_format)
>  		hdmi->hdmi_data.enc_in_bus_format =
>  			hdmi->plat_data->input_bus_format;
>  	else
>  		hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
>  
>  	/* TOFIX: Get input encoding from plat data or fallback to none */
> -	if (hdmi->plat_data->input_bus_encoding)
> +	if (hdmi->plat_data->get_enc_in_encoding)
> +		hdmi->hdmi_data.enc_in_encoding =
> +			hdmi->plat_data->get_enc_in_encoding(data);
> +	else if (hdmi->plat_data->input_bus_encoding)
>  		hdmi->hdmi_data.enc_in_encoding =
>  			hdmi->plat_data->input_bus_encoding;
>  	else
>  		hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
>  
>  	/* TOFIX: Default to RGB888 output format */
> -	hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
> +	if (hdmi->plat_data->get_output_bus_format)
> +		hdmi->hdmi_data.enc_out_bus_format =
> +			hdmi->plat_data->get_output_bus_format(data);
> +	else
> +		hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
>  
>  	hdmi->hdmi_data.pix_repet_factor = 0;
>  	hdmi->hdmi_data.hdcp_enable = 0;
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index 7a02744ce0bc..2e797f782c51 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -142,6 +142,11 @@ struct dw_hdmi_plat_data {
>  	int (*configure_phy)(struct dw_hdmi *hdmi,
>  			     const struct dw_hdmi_plat_data *pdata,
>  			     unsigned long mpixelclock);
> +
> +	unsigned long (*get_input_bus_format)(void *data);
> +	unsigned long (*get_output_bus_format)(void *data);
> +	unsigned long (*get_enc_in_encoding)(void *data);
> +	unsigned long (*get_enc_out_encoding)(void *data);
>  };
>  
>  struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,



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

* Re: [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info
  2018-12-19  7:26   ` Andrzej Hajda
@ 2018-12-19  7:50     ` Laurent Pinchart
  2018-12-20  7:37       ` Neil Armstrong
  0 siblings, 1 reply; 22+ messages in thread
From: Laurent Pinchart @ 2018-12-19  7:50 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Neil Armstrong, architt, Philipp Zabel, Sandy Huang,
	Heiko Stübner, maxime.ripard, Zheng Yang, dri-devel,
	linux-amlogic, linux-kernel

Hello,

On Wednesday, 19 December 2018 09:26:08 EET Andrzej Hajda wrote:
> On 30.11.2018 14:42, Neil Armstrong wrote:
> > From: Zheng Yang <zhengyang@rock-chips.com>
> > 
> > To get input/output bus_format/enc_format dynamically, this patch
> > 
> > introduce following funstion in plat_data:
> > 	- get_input_bus_format
> > 	- get_output_bus_format
> > 	- get_enc_in_encoding
> > 	- get_enc_out_encoding
> 
> It seems fishy. On one side description says about dynamic resolution of
> formats and encodings.
> 
> On the other side these functions as only argument takes platform_data
> which should be rather static.
> 
> Where is this "dynamic" thing? The only usage of these callbacks I have
> found in next patches is also not dynamic, the functions just return
> some static value.
> 
> Moreover function takes void* argument, which is again something
> suspicious, why cannot you pass know structure?
> 
> And finally encoding usually should depend on display mode, it should
> not depend only static data.
> 
> 
> What kind of problems do you want to solve here?

I would add that this doesn't seem to be specific to dw-hdmi in any way. I'd 
prefer an API at the drm_bridge level to handle this.

> > Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
> > Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> > ---
> > 
> >  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++++++------
> >  include/drm/bridge/dw_hdmi.h              |  5 ++++
> >  2 files changed, 26 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
> > 4a9a24e854db..bd564ffdf18b 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -1810,6 +1810,7 @@ static void hdmi_disable_overflow_interrupts(struct
> > dw_hdmi *hdmi)> 
> >  static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode
> >  *mode) {
> >  
> >  	int ret;
> > 
> > +	void *data = hdmi->plat_data->phy_data;
> > 
> >  	hdmi_disable_overflow_interrupts(hdmi);
> > 
> > @@ -1821,10 +1822,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
> > struct drm_display_mode *mode)> 
> >  		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
> >  	
> >  	}
> > 
> > -	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
> > -	    (hdmi->vic == 21) || (hdmi->vic == 22) ||
> > -	    (hdmi->vic == 2) || (hdmi->vic == 3) ||
> > -	    (hdmi->vic == 17) || (hdmi->vic == 18))
> > +	if (hdmi->plat_data->get_enc_out_encoding)
> > +		hdmi->hdmi_data.enc_out_encoding =
> > +			hdmi->plat_data->get_enc_out_encoding(data);
> > +	else if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
> > +		 (hdmi->vic == 21) || (hdmi->vic == 22) ||
> > +		 (hdmi->vic == 2) || (hdmi->vic == 3) ||
> > +		 (hdmi->vic == 17) || (hdmi->vic == 18))
> > 
> >  		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601;
> >  	
> >  	else
> >  	
> >  		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709;
> > 
> > @@ -1833,21 +1837,31 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
> > struct drm_display_mode *mode)> 
> >  	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
> >  	
> >  	/* TOFIX: Get input format from plat data or fallback to RGB888 */
> > 
> > -	if (hdmi->plat_data->input_bus_format)
> > +	if (hdmi->plat_data->get_input_bus_format)
> > +		hdmi->hdmi_data.enc_in_bus_format =
> > +			hdmi->plat_data->get_input_bus_format(data);
> > +	else if (hdmi->plat_data->input_bus_format)
> > 
> >  		hdmi->hdmi_data.enc_in_bus_format =
> >  		
> >  			hdmi->plat_data->input_bus_format;
> >  	
> >  	else
> >  	
> >  		hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
> >  	
> >  	/* TOFIX: Get input encoding from plat data or fallback to none */
> > 
> > -	if (hdmi->plat_data->input_bus_encoding)
> > +	if (hdmi->plat_data->get_enc_in_encoding)
> > +		hdmi->hdmi_data.enc_in_encoding =
> > +			hdmi->plat_data->get_enc_in_encoding(data);
> > +	else if (hdmi->plat_data->input_bus_encoding)
> > 
> >  		hdmi->hdmi_data.enc_in_encoding =
> >  		
> >  			hdmi->plat_data->input_bus_encoding;
> >  	
> >  	else
> >  	
> >  		hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
> >  	
> >  	/* TOFIX: Default to RGB888 output format */
> > 
> > -	hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
> > +	if (hdmi->plat_data->get_output_bus_format)
> > +		hdmi->hdmi_data.enc_out_bus_format =
> > +			hdmi->plat_data->get_output_bus_format(data);
> > +	else
> > +		hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
> > 
> >  	hdmi->hdmi_data.pix_repet_factor = 0;
> >  	hdmi->hdmi_data.hdcp_enable = 0;
> > 
> > diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> > index 7a02744ce0bc..2e797f782c51 100644
> > --- a/include/drm/bridge/dw_hdmi.h
> > +++ b/include/drm/bridge/dw_hdmi.h
> > @@ -142,6 +142,11 @@ struct dw_hdmi_plat_data {
> > 
> >  	int (*configure_phy)(struct dw_hdmi *hdmi,
> >  	
> >  			     const struct dw_hdmi_plat_data *pdata,
> >  			     unsigned long mpixelclock);
> > 
> > +
> > +	unsigned long (*get_input_bus_format)(void *data);
> > +	unsigned long (*get_output_bus_format)(void *data);
> > +	unsigned long (*get_enc_in_encoding)(void *data);
> > +	unsigned long (*get_enc_out_encoding)(void *data);
> > 
> >  };
> >  
> >  struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,


-- 
Regards,

Laurent Pinchart




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

* Re: [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info
  2018-12-19  7:50     ` Laurent Pinchart
@ 2018-12-20  7:37       ` Neil Armstrong
  0 siblings, 0 replies; 22+ messages in thread
From: Neil Armstrong @ 2018-12-20  7:37 UTC (permalink / raw)
  To: Laurent Pinchart, Andrzej Hajda
  Cc: architt, Philipp Zabel, Sandy Huang, Heiko Stübner,
	maxime.ripard, Zheng Yang, dri-devel, linux-amlogic,
	linux-kernel

Hi Andrzej, Laurent,

Thanks for your review.

On 19/12/2018 08:50, Laurent Pinchart wrote:
> Hello,
> 
> On Wednesday, 19 December 2018 09:26:08 EET Andrzej Hajda wrote:
>> On 30.11.2018 14:42, Neil Armstrong wrote:
>>> From: Zheng Yang <zhengyang@rock-chips.com>
>>>
>>> To get input/output bus_format/enc_format dynamically, this patch
>>>
>>> introduce following funstion in plat_data:
>>> 	- get_input_bus_format
>>> 	- get_output_bus_format
>>> 	- get_enc_in_encoding
>>> 	- get_enc_out_encoding
>>
>> It seems fishy. On one side description says about dynamic resolution of
>> formats and encodings.
>>
>> On the other side these functions as only argument takes platform_data
>> which should be rather static.

They are callbacks to the "glue" code, similar the PHY and HPD callbacks,
they will return different encodings and formats depending on the current mode
being atomically set.

>>
>> Where is this "dynamic" thing? The only usage of these callbacks I have
>> found in next patches is also not dynamic, the functions just return
>> some static value.

in patch 7 & 8 we return the current glue dw_hdmi->input_bus_format
and dw_hdmi->output_bus_format set during the encoder atomic_check()

>>
>> Moreover function takes void* argument, which is again something
>> suspicious, why cannot you pass know structure?

Yes, we should also pass dw_hdmi along the dw_plat_data->phy_data we
already pass.

>>
>> And finally encoding usually should depend on display mode, it should
>> not depend only static data.

It does not, there are fallbacks already in place, where you can override
with static data (the bus encoding and format can be fixed) or dynamic
to solve the yuv420 format.
Amlogic pipeline can *only* output in YUV (444, 422 or 420) so I pushed
support for statically describing the input format and encoding using
V4L2 definitions.

>>
>>
>> What kind of problems do you want to solve here?

We try to solve 2 things :
- The YUV420 HDMI2.0 mode, but the DW-HDMI CSC cannot convert to/from YUV420, so
it's in passthrought only. So the encoder must output in yuv420 and the controller
must know the input format and the output format, and this dynamically.
- Today the DW-HDMI forces RGB 8bit output, but we may prefer YUV444 or YU422 depending
on the sink and eventually output in 10, 12 or 16bit mode. This logic should
not be in the controller bridge code.

To solve these uses case, we put the logic in the encoder to determine what is
the DW-HDMI input format+encoding and the needed output format+encoding.

Today, the encoding callbacks are not used in this patchset, but they follow the
same scheme.

> 
> I would add that this doesn't seem to be specific to dw-hdmi in any way. I'd 
> prefer an API at the drm_bridge level to handle this.

Can you point me what you have in mind ? I'll be happy to implement it.

These callbacks are only an extension of the hdmi->plat_data->input_bus_format
and hdmi->plat_data->input_bus_encoding I introduced a few times ago.

I'd really like to solve this correctly, but still solve it at some point !
The YUV420 support is handy to easily support 4k60 for cheap and older TVs
without the hassle of SCDC and TMDS scrambling.

Neil

> 
>>> Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>> ---
>>>
>>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++++++------
>>>  include/drm/bridge/dw_hdmi.h              |  5 ++++
>>>  2 files changed, 26 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
>>> 4a9a24e854db..bd564ffdf18b 100644
>>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>> @@ -1810,6 +1810,7 @@ static void hdmi_disable_overflow_interrupts(struct
>>> dw_hdmi *hdmi)> 
>>>  static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode
>>>  *mode) {
>>>  
>>>  	int ret;
>>>
>>> +	void *data = hdmi->plat_data->phy_data;
>>>
>>>  	hdmi_disable_overflow_interrupts(hdmi);
>>>
>>> @@ -1821,10 +1822,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
>>> struct drm_display_mode *mode)> 
>>>  		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
>>>  	
>>>  	}
>>>
>>> -	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
>>> -	    (hdmi->vic == 21) || (hdmi->vic == 22) ||
>>> -	    (hdmi->vic == 2) || (hdmi->vic == 3) ||
>>> -	    (hdmi->vic == 17) || (hdmi->vic == 18))
>>> +	if (hdmi->plat_data->get_enc_out_encoding)
>>> +		hdmi->hdmi_data.enc_out_encoding =
>>> +			hdmi->plat_data->get_enc_out_encoding(data);
>>> +	else if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
>>> +		 (hdmi->vic == 21) || (hdmi->vic == 22) ||
>>> +		 (hdmi->vic == 2) || (hdmi->vic == 3) ||
>>> +		 (hdmi->vic == 17) || (hdmi->vic == 18))
>>>
>>>  		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601;
>>>  	
>>>  	else
>>>  	
>>>  		hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709;
>>>
>>> @@ -1833,21 +1837,31 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
>>> struct drm_display_mode *mode)> 
>>>  	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
>>>  	
>>>  	/* TOFIX: Get input format from plat data or fallback to RGB888 */
>>>
>>> -	if (hdmi->plat_data->input_bus_format)
>>> +	if (hdmi->plat_data->get_input_bus_format)
>>> +		hdmi->hdmi_data.enc_in_bus_format =
>>> +			hdmi->plat_data->get_input_bus_format(data);
>>> +	else if (hdmi->plat_data->input_bus_format)
>>>
>>>  		hdmi->hdmi_data.enc_in_bus_format =
>>>  		
>>>  			hdmi->plat_data->input_bus_format;
>>>  	
>>>  	else
>>>  	
>>>  		hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
>>>  	
>>>  	/* TOFIX: Get input encoding from plat data or fallback to none */
>>>
>>> -	if (hdmi->plat_data->input_bus_encoding)
>>> +	if (hdmi->plat_data->get_enc_in_encoding)
>>> +		hdmi->hdmi_data.enc_in_encoding =
>>> +			hdmi->plat_data->get_enc_in_encoding(data);
>>> +	else if (hdmi->plat_data->input_bus_encoding)
>>>
>>>  		hdmi->hdmi_data.enc_in_encoding =
>>>  		
>>>  			hdmi->plat_data->input_bus_encoding;
>>>  	
>>>  	else
>>>  	
>>>  		hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
>>>  	
>>>  	/* TOFIX: Default to RGB888 output format */
>>>
>>> -	hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
>>> +	if (hdmi->plat_data->get_output_bus_format)
>>> +		hdmi->hdmi_data.enc_out_bus_format =
>>> +			hdmi->plat_data->get_output_bus_format(data);
>>> +	else
>>> +		hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
>>>
>>>  	hdmi->hdmi_data.pix_repet_factor = 0;
>>>  	hdmi->hdmi_data.hdcp_enable = 0;
>>>
>>> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
>>> index 7a02744ce0bc..2e797f782c51 100644
>>> --- a/include/drm/bridge/dw_hdmi.h
>>> +++ b/include/drm/bridge/dw_hdmi.h
>>> @@ -142,6 +142,11 @@ struct dw_hdmi_plat_data {
>>>
>>>  	int (*configure_phy)(struct dw_hdmi *hdmi,
>>>  	
>>>  			     const struct dw_hdmi_plat_data *pdata,
>>>  			     unsigned long mpixelclock);
>>>
>>> +
>>> +	unsigned long (*get_input_bus_format)(void *data);
>>> +	unsigned long (*get_output_bus_format)(void *data);
>>> +	unsigned long (*get_enc_in_encoding)(void *data);
>>> +	unsigned long (*get_enc_out_encoding)(void *data);
>>>
>>>  };
>>>  
>>>  struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
> 
> 


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

end of thread, other threads:[~2018-12-20  7:37 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-30 13:42 [PATCH RFC v2 0/8] drm/meson: Add support for HDMI2.0 4k60 Neil Armstrong
2018-11-30 13:42 ` [PATCH RFC v2 1/8] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support Neil Armstrong
2018-12-14 12:12   ` Heiko Stuebner
2018-12-18 12:25   ` Andrzej Hajda
2018-12-18 13:17     ` Neil Armstrong
2018-11-30 13:42 ` [PATCH RFC v2 2/8] drm/meson: add HDMI div40 TMDS mode Neil Armstrong
2018-12-18 12:36   ` Andrzej Hajda
2018-12-18 13:19     ` Neil Armstrong
2018-11-30 13:42 ` [PATCH RFC v2 3/8] drm/meson: add support for HDMI2.0 2160p modes Neil Armstrong
2018-12-18 12:37   ` Andrzej Hajda
2018-11-30 13:42 ` [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output Neil Armstrong
2018-12-14 12:13   ` Heiko Stuebner
2018-12-18 13:41   ` Andrzej Hajda
2018-11-30 13:42 ` [PATCH RFC v2 5/8] drm/bridge: dw-hdmi: support dynamically get input/out color info Neil Armstrong
2018-12-14 12:13   ` Heiko Stuebner
2018-12-19  7:26   ` Andrzej Hajda
2018-12-19  7:50     ` Laurent Pinchart
2018-12-20  7:37       ` Neil Armstrong
2018-11-30 13:42 ` [PATCH RFC v2 6/8] drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
2018-12-14 12:13   ` Heiko Stuebner
2018-11-30 13:43 ` [PATCH RFC v2 7/8] drm/meson: Add YUV420 output support Neil Armstrong
2018-11-30 13:43 ` [PATCH RFC v2 8/8] drm/meson: Output in YUV444 if sink supports it Neil Armstrong

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