linux-amlogic.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support
@ 2020-02-06 19:18 Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color Neil Armstrong
                   ` (10 more replies)
  0 siblings, 11 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

This patchset is based on Boris's v10 "drm: Add support for bus-format negotiation" at [1]
patchset to implement full bus-format negotiation for DW-HDMI, including YUV420 support and
10/12/16bit YUV444, YUV422 and RGB. The Color Space Converter support is already implemented.

And the counterpart implementation in the Amlogic Meson VPU dw-hdmi glue :
- basic bus-format negotiation to select YUV444 bus-format as DW-HDMI input
- YUV420 support when HDMI2.0 YUV420 modeset

This is a follow-up from the previous attempts :
- "drm/meson: Add support for HDMI2.0 YUV420 4k60" at [2]
- "drm/meson: Add support for HDMI2.0 4k60" at [3]

Changes sincd v3 at [6]:
- Added "Plug atomic state hooks to the default implementation" on drm/bridge: dw-hdmi
- Also added these atomic state hooks in meson-dw-hdmi in patch 7
- Rebased on latest drm-misc-next including patches 1-7 of [1]

Changes since RFC v2 at [5]:
- Added fixes from Jonas, who tested and integrated it for Rockchip SoCs
- Added support for 10/12/16bit tmds clock calculation
- Added support for max_bcp connector property
- Adapted to Boris's v4 patchset
- Fixed typos reported by boris

Changes since RFC v1 at [4]:
- Rewrote negociation using the v2 patchset, including full DW-HDMI fmt negociation

[1] https://patchwork.freedesktop.org/patch/msgid/20200128135514.108171-1-boris.brezillon@collabora.com
[2] https://patchwork.freedesktop.org/patch/msgid/20190520133753.23871-1-narmstrong@baylibre.com
[3] https://patchwork.freedesktop.org/patch/msgid/1549022873-40549-1-git-send-email-narmstrong@baylibre.com
[4] https://patchwork.freedesktop.org/patch/msgid/20190820084109.24616-1-narmstrong@baylibre.com
[5] https://patchwork.freedesktop.org/patch/msgid/20190827081425.15011-1-narmstrong@baylibre.com
[6] https://patchwork.freedesktop.org/patch/msgid/20191218154637.17509-1-narmstrong@baylibre.com

Jonas Karlman (2):
  drm/bridge: dw-hdmi: set mtmdsclock for deep color
  drm/bridge: dw-hdmi: add max bpc connector property

Neil Armstrong (9):
  drm/bridge: dw-hdmi: Plug atomic state hooks to the default
    implementation
  drm/bridge: synopsys: dw-hdmi: add bus format negociation
  drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  drm/meson: venc: make drm_display_mode const
  drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs
  drm/meson: dw-hdmi: stop enforcing input_bus_format
  drm/meson: venc: add support for YUV420 setup
  drm/meson: vclk: add support for YUV420 setup
  drm/meson: Add YUV420 output support

 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 302 +++++++++++++++++++++-
 drivers/gpu/drm/meson/meson_dw_hdmi.c     | 200 +++++++++++---
 drivers/gpu/drm/meson/meson_vclk.c        |  93 +++++--
 drivers/gpu/drm/meson/meson_vclk.h        |   7 +-
 drivers/gpu/drm/meson/meson_venc.c        |  10 +-
 drivers/gpu/drm/meson/meson_venc.h        |   4 +-
 drivers/gpu/drm/meson/meson_venc_cvbs.c   |   6 +-
 include/drm/bridge/dw_hdmi.h              |   1 +
 8 files changed, 548 insertions(+), 75 deletions(-)

-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-03-02  9:05   ` Laurent Pinchart
  2020-02-06 19:18 ` [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property Neil Armstrong
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

From: Jonas Karlman <jonas@kwiboo.se>

Configure the correct mtmdsclock for deep colors to prepare support
for 10, 12 & 16bit output.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 67fca439bbfb..9e0927d22db6 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1818,9 +1818,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 
 	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
 
+	if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
+		switch (hdmi_bus_fmt_color_depth(
+				hdmi->hdmi_data.enc_out_bus_format)) {
+		case 16:
+			vmode->mtmdsclock = (u64)vmode->mpixelclock * 2;
+			break;
+		case 12:
+			vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2;
+			break;
+		case 10:
+			vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4;
+			break;
+		}
+	}
+
 	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
 		vmode->mtmdsclock /= 2;
 
+	dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);
+
 	/* Set up HDMI_FC_INVIDCONF */
 	inv_val = (hdmi->hdmi_data.hdcp_enable ||
 		   (dw_hdmi_support_scdc(hdmi) &&
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-17  6:38   ` Jernej Škrabec
  2020-02-06 19:18 ` [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation Neil Armstrong
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

From: Jonas Karlman <jonas@kwiboo.se>

Add the max_bpc property to the dw-hdmi connector to prepare support
for 10, 12 & 16bit output support.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 9e0927d22db6..051001f77dd4 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2406,6 +2406,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
 				    DRM_MODE_CONNECTOR_HDMIA,
 				    hdmi->ddc);
 
+	drm_atomic_helper_connector_reset(connector);
+
+	drm_connector_attach_max_bpc_property(connector, 8, 16);
+
 	if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
 		drm_object_attach_property(&connector->base,
 			connector->dev->mode_config.hdr_output_metadata_property, 0);
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-07 10:57   ` Boris Brezillon
  2020-03-02  9:56   ` Laurent Pinchart
  2020-02-06 19:18 ` [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation Neil Armstrong
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 051001f77dd4..fec4a4bcd1fe 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2494,6 +2494,9 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
 }
 
 static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+	.atomic_reset = drm_atomic_helper_bridge_reset,
 	.attach = dw_hdmi_bridge_attach,
 	.detach = dw_hdmi_bridge_detach,
 	.enable = dw_hdmi_bridge_enable,
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (2 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-07 11:02   ` Boris Brezillon
                     ` (2 more replies)
  2020-02-06 19:18 ` [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
                   ` (6 subsequent siblings)
  10 siblings, 3 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
the possible output and input formats for the current mode and monitor,
and use the negotiated formats in a basic atomic_check callback.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
 1 file changed, 268 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index fec4a4bcd1fe..15048ad694bc 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
 	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)
 		hdmi->hdmi_data.enc_in_bus_format =
 			hdmi->plat_data->input_bus_format;
-	else
+	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
 		hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 
 	/* TOFIX: Get input encoding from plat data or fallback to none */
@@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
 	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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
+		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;
@@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
 	.atomic_check = dw_hdmi_connector_atomic_check,
 };
 
+/*
+ * Possible output formats :
+ * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
+ * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
+ * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
+ * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
+ * - MEDIA_BUS_FMT_YUV16_1X48,
+ * - MEDIA_BUS_FMT_RGB161616_1X48,
+ * - MEDIA_BUS_FMT_UYVY12_1X24,
+ * - MEDIA_BUS_FMT_YUV12_1X36,
+ * - MEDIA_BUS_FMT_RGB121212_1X36,
+ * - MEDIA_BUS_FMT_UYVY10_1X20,
+ * - MEDIA_BUS_FMT_YUV10_1X30,
+ * - MEDIA_BUS_FMT_RGB101010_1X30,
+ * - MEDIA_BUS_FMT_UYVY8_1X16,
+ * - MEDIA_BUS_FMT_YUV8_1X24,
+ * - MEDIA_BUS_FMT_RGB888_1X24,
+ */
+
+/* Can return a maximum of 12 possible output formats for a mode/connector */
+#define MAX_OUTPUT_SEL_FORMATS	12
+
+static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
+					struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state,
+					unsigned int *num_output_fmts)
+{
+	struct drm_connector *conn = conn_state->connector;
+	struct drm_display_info *info = &conn->display_info;
+	struct drm_display_mode *mode = &crtc_state->mode;
+	u8 max_bpc = conn_state->max_requested_bpc;
+	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
+			     (info->color_formats & DRM_COLOR_FORMAT_YCRCB420);
+	u32 *output_fmts;
+	int i = 0;
+
+	*num_output_fmts = 0;
+
+	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
+			      GFP_KERNEL);
+	if (!output_fmts)
+		return NULL;
+
+	/*
+	 * If the current mode enforces 4:2:0, force the output but format
+	 * to 4:2:0 and do not add the YUV422/444/RGB formats
+	 */
+	if (conn->ycbcr_420_allowed &&
+	    (drm_mode_is_420_only(info, mode) ||
+	     (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) {
+
+		/* Order bus formats from 16bit to 8bit if supported */
+		if (max_bpc >= 16 && info->bpc == 16 &&
+		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48))
+			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48;
+
+		if (max_bpc >= 12 && info->bpc >= 12 &&
+		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36))
+			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
+
+		if (max_bpc >= 10 && info->bpc >= 10 &&
+		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30))
+			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+
+		/* Default 8bit fallback */
+		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+
+		*num_output_fmts = i;
+
+		return output_fmts;
+	}
+
+	/*
+	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
+	 * if supported. In any case the default RGB888 format is added
+	 */
+
+	if (max_bpc >= 16 && info->bpc == 16) {
+		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
+			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
+
+		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
+	}
+
+	if (max_bpc >= 12 && info->bpc >= 12) {
+		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
+			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
+
+		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
+			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
+
+		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
+	}
+
+	if (max_bpc >= 10 && info->bpc >= 10) {
+		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
+			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
+
+		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
+			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
+
+		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
+	}
+
+	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
+		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
+
+	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
+		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
+
+	/* Default 8bit RGB fallback */
+	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
+
+	*num_output_fmts = i;
+
+	return output_fmts;
+}
+
+/*
+ * Possible input formats :
+ * - MEDIA_BUS_FMT_RGB888_1X24
+ * - MEDIA_BUS_FMT_YUV8_1X24
+ * - MEDIA_BUS_FMT_UYVY8_1X16
+ * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
+ * - MEDIA_BUS_FMT_RGB101010_1X30
+ * - MEDIA_BUS_FMT_YUV10_1X30
+ * - MEDIA_BUS_FMT_UYVY10_1X20
+ * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
+ * - MEDIA_BUS_FMT_RGB121212_1X36
+ * - MEDIA_BUS_FMT_YUV12_1X36
+ * - MEDIA_BUS_FMT_UYVY12_1X24
+ * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
+ * - MEDIA_BUS_FMT_RGB161616_1X48
+ * - MEDIA_BUS_FMT_YUV16_1X48
+ * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
+ */
+
+/* Can return a maximum of 4 possible input formats for an output format */
+#define MAX_INPUT_SEL_FORMATS	4
+
+static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+					struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state,
+					u32 output_fmt,
+					unsigned int *num_input_fmts)
+{
+	u32 *input_fmts;
+	int i = 0;
+
+	*num_input_fmts = 0;
+
+	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
+			     GFP_KERNEL);
+	if (!input_fmts)
+		return NULL;
+
+	switch (output_fmt) {
+	/* 8bit */
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
+		break;
+	case MEDIA_BUS_FMT_YUV8_1X24:
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+
+	/* 10bit */
+	case MEDIA_BUS_FMT_RGB101010_1X30:
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
+		break;
+	case MEDIA_BUS_FMT_YUV10_1X30:
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
+		break;
+	case MEDIA_BUS_FMT_UYVY10_1X20:
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
+		break;
+
+	/* 12bit */
+	case MEDIA_BUS_FMT_RGB121212_1X36:
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
+		break;
+	case MEDIA_BUS_FMT_YUV12_1X36:
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
+		break;
+	case MEDIA_BUS_FMT_UYVY12_1X24:
+		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
+		break;
+
+	/* 16bit */
+	case MEDIA_BUS_FMT_RGB161616_1X48:
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
+		break;
+	case MEDIA_BUS_FMT_YUV16_1X48:
+		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
+		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
+		break;
+
+	/* 420 */
+	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:
+		input_fmts[i++] = output_fmt;
+		break;
+	}
+
+	*num_input_fmts = i;
+
+	if (*num_input_fmts == 0) {
+		kfree(input_fmts);
+		input_fmts = NULL;
+	}
+
+	return input_fmts;
+}
+
+static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
+				       struct drm_bridge_state *bridge_state,
+				       struct drm_crtc_state *crtc_state,
+				       struct drm_connector_state *conn_state)
+{
+	struct dw_hdmi *hdmi = bridge->driver_private;
+
+	dev_dbg(hdmi->dev, "selected output format %x\n",
+			bridge_state->output_bus_cfg.format);
+
+	hdmi->hdmi_data.enc_out_bus_format =
+			bridge_state->output_bus_cfg.format;
+
+	dev_dbg(hdmi->dev, "selected input format %x\n",
+			bridge_state->input_bus_cfg.format);
+
+	hdmi->hdmi_data.enc_in_bus_format =
+			bridge_state->input_bus_cfg.format;
+
+	return 0;
+}
+
 static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
 {
 	struct dw_hdmi *hdmi = bridge->driver_private;
@@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
 	.atomic_reset = drm_atomic_helper_bridge_reset,
 	.attach = dw_hdmi_bridge_attach,
 	.detach = dw_hdmi_bridge_detach,
+	.atomic_check = dw_hdmi_bridge_atomic_check,
+	.atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
+	.atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
 	.enable = dw_hdmi_bridge_enable,
 	.disable = dw_hdmi_bridge_disable,
 	.mode_set = dw_hdmi_bridge_mode_set,
@@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
 
 	hdmi->bridge.driver_private = hdmi;
 	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
+
 #ifdef CONFIG_OF
 	hdmi->bridge.of_node = pdev->dev.of_node;
 #endif
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (3 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-07 13:38   ` Neil Armstrong
  2020-03-02 10:03   ` Laurent Pinchart
  2020-02-06 19:18 ` [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const Neil Armstrong
                   ` (5 subsequent siblings)
  10 siblings, 2 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, 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>
---
 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 15048ad694bc..4b35ea1427df 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -3231,6 +3231,12 @@ __dw_hdmi_probe(struct platform_device *pdev,
 	hdmi->bridge.of_node = pdev->dev.of_node;
 #endif
 
+	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 9d4d5cc47969..0b34a12c4a1c 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -129,6 +129,7 @@ struct dw_hdmi_plat_data {
 	unsigned long input_bus_format;
 	unsigned long input_bus_encoding;
 	bool use_drm_infoframe;
+	bool ycbcr_420_allowed;
 
 	/* Vendor PHY support */
 	const struct dw_hdmi_phy_ops *phy_ops;
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (4 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-07 13:39   ` Neil Armstrong
  2020-03-02  9:59   ` Laurent Pinchart
  2020-02-06 19:18 ` [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs Neil Armstrong
                   ` (4 subsequent siblings)
  10 siblings, 2 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

Before switching to bridge funcs, make sure drm_display_mode is passed
as const to the venc functions.

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

diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 4efd7864d5bf..a9ab78970bfe 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -946,7 +946,7 @@ 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,
-			      struct drm_display_mode *mode)
+			      const struct drm_display_mode *mode)
 {
 	union meson_hdmi_venc_mode *vmode = NULL;
 	union meson_hdmi_venc_mode vmode_dmt;
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
index 576768bdd08d..1abdcbdf51c0 100644
--- a/drivers/gpu/drm/meson/meson_venc.h
+++ b/drivers/gpu/drm/meson/meson_venc.h
@@ -60,7 +60,7 @@ 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,
-			      struct drm_display_mode *mode);
+			      const struct drm_display_mode *mode);
 unsigned int meson_venci_get_field(struct meson_drm *priv);
 
 void meson_venc_enable_vsync(struct meson_drm *priv);
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (5 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-07 14:57   ` Boris Brezillon
  2020-02-06 19:18 ` [PATCH v4 08/11] drm/meson: dw-hdmi: stop enforcing input_bus_format Neil Armstrong
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

Switch the dw-hdmi driver to drm_bridge_funcs by implementing a new local
bridge, connecting it to the dw-hdmi bridge, then implement the
atomic_get_input_bus_fmts/atomic_get_output_bus_fmts.

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

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 3bb7ffe5fc39..4b3809626f7e 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -16,6 +16,7 @@
 
 #include <drm/bridge/dw_hdmi.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_device.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_probe_helper.h>
@@ -135,6 +136,7 @@ struct meson_dw_hdmi_data {
 
 struct meson_dw_hdmi {
 	struct drm_encoder encoder;
+	struct drm_bridge bridge;
 	struct dw_hdmi_plat_data dw_plat_data;
 	struct meson_drm *priv;
 	struct device *dev;
@@ -151,6 +153,8 @@ struct meson_dw_hdmi {
 };
 #define encoder_to_meson_dw_hdmi(x) \
 	container_of(x, struct meson_dw_hdmi, encoder)
+#define bridge_to_meson_dw_hdmi(x) \
+	container_of(x, struct meson_dw_hdmi, bridge)
 
 static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
 					const char *compat)
@@ -368,7 +372,7 @@ static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
 }
 
 static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
-			     struct drm_display_mode *mode)
+			     const struct drm_display_mode *mode)
 {
 	struct meson_drm *priv = dw_hdmi->priv;
 	int vic = drm_match_cea_mode(mode);
@@ -663,6 +667,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 
 /* Encoder */
 
+static const u32 meson_dw_hdmi_out_bus_fmts[] = {
+	MEDIA_BUS_FMT_YUV8_1X24,
+};
+
 static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
 {
 	drm_encoder_cleanup(encoder);
@@ -672,16 +680,63 @@ static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
 	.destroy        = meson_venc_hdmi_encoder_destroy,
 };
 
-static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+static u32 *
+meson_venc_hdmi_encoder_get_out_bus_fmts(struct drm_bridge *bridge,
+					 struct drm_bridge_state *bridge_state,
+					 struct drm_crtc_state *crtc_state,
+					 struct drm_connector_state *conn_state,
+					 unsigned int *num_output_fmts)
+{
+	u32 *output_fmts;
+
+	*num_output_fmts = ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts);
+	output_fmts = kcalloc(*num_output_fmts, sizeof(*output_fmts),
+			      GFP_KERNEL);
+	if (!output_fmts)
+		return NULL;
+
+	memcpy(output_fmts, meson_dw_hdmi_out_bus_fmts, *num_output_fmts);
+
+	return output_fmts;
+}
+
+static u32 *
+meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge,
+					struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state,
+					u32 output_fmt,
+					unsigned int *num_input_fmts)
+{
+	u32 *input_fmts = NULL;
+
+	if (output_fmt == meson_dw_hdmi_out_bus_fmts[0]) {
+		*num_input_fmts = 1;
+		input_fmts = kcalloc(*num_input_fmts,
+				     sizeof(*input_fmts),
+				     GFP_KERNEL);
+		if (!input_fmts)
+			return NULL;
+
+		input_fmts[0] = output_fmt;
+	} else {
+		*num_input_fmts = 0;
+	}
+
+	return input_fmts;
+}
+
+static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge,
+					struct drm_bridge_state *bridge_state,
 					struct drm_crtc_state *crtc_state,
 					struct drm_connector_state *conn_state)
 {
 	return 0;
 }
 
-static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void meson_venc_hdmi_encoder_disable(struct drm_bridge *bridge)
 {
-	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
 	struct meson_drm *priv = dw_hdmi->priv;
 
 	DRM_DEBUG_DRIVER("\n");
@@ -693,9 +748,9 @@ static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
 	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
 }
 
-static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
+static void meson_venc_hdmi_encoder_enable(struct drm_bridge *bridge)
 {
-	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
 	struct meson_drm *priv = dw_hdmi->priv;
 
 	DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
@@ -706,11 +761,11 @@ static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
 		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
 }
 
-static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
-				   struct drm_display_mode *mode,
-				   struct drm_display_mode *adjusted_mode)
+static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
+				   const struct drm_display_mode *mode,
+				   const struct drm_display_mode *adjusted_mode)
 {
-	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
 	struct meson_drm *priv = dw_hdmi->priv;
 	int vic = drm_match_cea_mode(mode);
 
@@ -726,12 +781,16 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 	writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
 }
 
-static const struct drm_encoder_helper_funcs
-				meson_venc_hdmi_encoder_helper_funcs = {
-	.atomic_check	= meson_venc_hdmi_encoder_atomic_check,
-	.disable	= meson_venc_hdmi_encoder_disable,
-	.enable		= meson_venc_hdmi_encoder_enable,
-	.mode_set	= meson_venc_hdmi_encoder_mode_set,
+static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = {
+	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+	.atomic_get_output_bus_fmts = meson_venc_hdmi_encoder_get_out_bus_fmts,
+	.atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts,
+	.atomic_reset = drm_atomic_helper_bridge_reset,
+	.atomic_check = meson_venc_hdmi_encoder_atomic_check,
+	.enable	= meson_venc_hdmi_encoder_enable,
+	.disable = meson_venc_hdmi_encoder_disable,
+	.mode_set = meson_venc_hdmi_encoder_mode_set,
 };
 
 /* DW HDMI Regmap */
@@ -852,6 +911,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 	struct drm_device *drm = data;
 	struct meson_drm *priv = drm->dev_private;
 	struct dw_hdmi_plat_data *dw_plat_data;
+	struct drm_bridge *next_bridge;
 	struct drm_encoder *encoder;
 	struct resource *res;
 	int irq;
@@ -953,8 +1013,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 
 	/* Encoder */
 
-	drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
-
 	ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
 			       DRM_MODE_ENCODER_TMDS, "meson_hdmi");
 	if (ret) {
@@ -962,6 +1020,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	meson_dw_hdmi->bridge.funcs = &meson_venc_hdmi_encoder_bridge_funcs;
+	drm_bridge_attach(encoder, &meson_dw_hdmi->bridge, NULL);
+
 	encoder->possible_crtcs = BIT(0);
 
 	DRM_DEBUG_DRIVER("encoder initialized\n");
@@ -984,11 +1045,15 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 
 	platform_set_drvdata(pdev, meson_dw_hdmi);
 
-	meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
-					   &meson_dw_hdmi->dw_plat_data);
+	meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev,
+					    &meson_dw_hdmi->dw_plat_data);
 	if (IS_ERR(meson_dw_hdmi->hdmi))
 		return PTR_ERR(meson_dw_hdmi->hdmi);
 
+	next_bridge = of_drm_find_bridge(pdev->dev.of_node);
+	if (next_bridge)
+		drm_bridge_attach(encoder, next_bridge, &meson_dw_hdmi->bridge);
+
 	DRM_DEBUG_DRIVER("HDMI controller initialized\n");
 
 	return 0;
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 08/11] drm/meson: dw-hdmi: stop enforcing input_bus_format
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (6 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 09/11] drm/meson: venc: add support for YUV420 setup Neil Armstrong
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

To allow using formats from negotiation, stop enforcing input_bus_format
in the private dw-plat-data struct.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/meson/meson_dw_hdmi.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 4b3809626f7e..686c47106a18 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -1035,7 +1035,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 	dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
 	dw_plat_data->phy_name = "meson_dw_hdmi_phy";
 	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;
 
 	if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 09/11] drm/meson: venc: add support for YUV420 setup
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (7 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 08/11] drm/meson: dw-hdmi: stop enforcing input_bus_format Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 10/11] drm/meson: vclk: " Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 11/11] drm/meson: Add YUV420 output support Neil Armstrong
  10 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

This patch adds encoding 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.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_dw_hdmi.c | 3 ++-
 drivers/gpu/drm/meson/meson_venc.c    | 8 +++++---
 drivers/gpu/drm/meson/meson_venc.h    | 2 ++
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 686c47106a18..f5d46d082534 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -772,7 +772,8 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
 	DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic);
 
 	/* VENC + VENC-DVI Mode setup */
-	meson_venc_hdmi_mode_set(priv, vic, mode);
+	meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, false,
+				 VPU_HDMI_OUTPUT_CBYCR);
 
 	/* VCLK Set clock */
 	dw_hdmi_set_vclk(dw_hdmi, mode);
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index a9ab78970bfe..f93c725b6f02 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -946,6 +946,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,
 			      const struct drm_display_mode *mode)
 {
 	union meson_hdmi_venc_mode *vmode = NULL;
@@ -1528,14 +1530,14 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
 	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
 		reg |= VPU_HDMI_INV_VSYNC;
 
-	/* Output data format: CbYCr */
-	reg |= VPU_HDMI_OUTPUT_CBYCR;
+	/* Output data format */
+	reg |= ycrcb_map;
 
 	/*
 	 * Write rate to the async FIFO between VENC and HDMI.
 	 * One write every 2 wr_clk.
 	 */
-	if (venc_repeat)
+	if (venc_repeat || yuv420_mode)
 		reg |= VPU_HDMI_WR_RATE(2);
 
 	/*
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
index 1abdcbdf51c0..9138255ffc9e 100644
--- a/drivers/gpu/drm/meson/meson_venc.h
+++ b/drivers/gpu/drm/meson/meson_venc.h
@@ -60,6 +60,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,
 			      const struct drm_display_mode *mode);
 unsigned int meson_venci_get_field(struct meson_drm *priv);
 
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 10/11] drm/meson: vclk: add support for YUV420 setup
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (8 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 09/11] drm/meson: venc: add support for YUV420 setup Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  2020-02-06 19:18 ` [PATCH v4 11/11] drm/meson: Add YUV420 output support Neil Armstrong
  10 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

This patch adds clocking 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.

This mode needs a different clock generation scheme since the TMDS PHY
clock must match the 10x ratio 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   | 24 ++++---
 drivers/gpu/drm/meson/meson_vclk.c      | 93 +++++++++++++++++++------
 drivers/gpu/drm/meson/meson_vclk.h      |  7 +-
 drivers/gpu/drm/meson/meson_venc_cvbs.c |  6 +-
 4 files changed, 95 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index f5d46d082534..94f206bf795d 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -376,15 +376,19 @@ 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;
 
+	/* 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;
 	}
 
@@ -402,11 +406,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);
 }
 
@@ -617,6 +621,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 		   const struct drm_display_mode *mode)
 {
 	struct meson_drm *priv = connector->dev->dev_private;
+	unsigned int phy_freq;
 	unsigned int vclk_freq;
 	unsigned int venc_freq;
 	unsigned int hdmi_freq;
@@ -643,6 +648,9 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 
 	vclk_freq = mode->clock;
 
+	/* 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;
@@ -659,10 +667,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 */
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index f690793ae2d5..fdf26dac9fa8 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -354,12 +354,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;
@@ -367,8 +372,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,
@@ -376,8 +384,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,
@@ -385,8 +396,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,
@@ -394,8 +408,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,
@@ -403,8 +420,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,
@@ -412,8 +432,11 @@ struct meson_vclk_params {
 		.vclk_div = 1,
 	},
 	[MESON_VCLK_HDMI_297000] = {
+		.pll_freq = 5940000,
+		.phy_freq = 2970000,
+		.venc_freq = 297000,
+		.vclk_freq = 297000,
 		.pixel_freq = 297000,
-		.pll_base_freq = 5940000,
 		.pll_od1 = 2,
 		.pll_od2 = 1,
 		.pll_od3 = 1,
@@ -421,14 +444,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 = 5940000,
+		.phy_freq = 2970000,
+		.venc_freq = 594000,
+		.vclk_freq = 594000,
+		.pixel_freq = 297000,
+		.pll_od1 = 2,
+		.pll_od2 = 1,
+		.pll_od3 = 1,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
 	{ /* sentinel */ },
 };
 
@@ -701,6 +739,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;
@@ -723,21 +762,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;
 	}
 
@@ -965,8 +1011,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;
@@ -986,7 +1033,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;
 	}
@@ -1008,9 +1055,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;
@@ -1039,7 +1088,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 b62125540aef..aed0ab2efa71 100644
--- a/drivers/gpu/drm/meson/meson_vclk.h
+++ b/drivers/gpu/drm/meson/meson_vclk.h
@@ -25,10 +25,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_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
index 1bd6b6d15ffb..541f9eb2a135 100644
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -213,8 +213,10 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
 		meson_venci_cvbs_mode_set(priv, meson_mode->enci);
 
 		/* 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_setup(priv, MESON_VCLK_TARGET_CVBS,
+				 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
+				 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
+				 true);
 	}
 }
 
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* [PATCH v4 11/11] drm/meson: Add YUV420 output support
  2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
                   ` (9 preceding siblings ...)
  2020-02-06 19:18 ` [PATCH v4 10/11] drm/meson: vclk: " Neil Armstrong
@ 2020-02-06 19:18 ` Neil Armstrong
  10 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-06 19:18 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

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 enables the bridge bus format negociation, and handles
the YUV420 case if selected by the negociation.

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

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 94f206bf795d..5962afbfc8ab 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -150,6 +150,7 @@ struct meson_dw_hdmi {
 	struct regulator *hdmi_supply;
 	u32 irq_stat;
 	struct dw_hdmi *hdmi;
+	unsigned long output_bus_fmt;
 };
 #define encoder_to_meson_dw_hdmi(x) \
 	container_of(x, struct meson_dw_hdmi, encoder)
@@ -301,6 +302,10 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
 	struct meson_drm *priv = dw_hdmi->priv;
 	unsigned int pixel_clock = mode->clock;
 
+	/* For 420, pixel clock is half unlike venc clock */
+	if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
+		pixel_clock /= 2;
+
 	if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
 	    dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
 		if (pixel_clock >= 371250) {
@@ -383,6 +388,10 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
 
 	vclk_freq = mode->clock;
 
+	/* For 420, pixel clock is half unlike venc clock */
+	if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
+		vclk_freq /= 2;
+
 	/* TMDS clock is pixel_clock * 10 */
 	phy_freq = vclk_freq * 10;
 
@@ -392,13 +401,16 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
 		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->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
 		venc_freq *= 2;
 
 	vclk_freq = max(venc_freq, hdmi_freq);
@@ -445,8 +457,9 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
 	/* Enable normal output to PHY */
 	dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
 
-	/* TMDS pattern setup (TOFIX Handle the YUV420 case) */
-	if (mode->clock > 340000) {
+	/* TMDS pattern setup */
+	if (mode->clock > 340000 &&
+	    dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_YUV8_1X24) {
 		dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
 				  0);
 		dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
@@ -621,6 +634,7 @@ 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;
@@ -630,9 +644,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 
 	DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
 
-	/* If sink max TMDS clock, we reject the mode */
+	/* If sink does not support 540MHz, reject the non-420 HDMI2 modes */
 	if (connector->display_info.max_tmds_clock &&
-	    mode->clock > connector->display_info.max_tmds_clock)
+	    mode->clock > connector->display_info.max_tmds_clock &&
+	    !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 */
@@ -648,6 +664,12 @@ 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;
 
@@ -658,8 +680,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);
@@ -677,6 +702,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 
 static const u32 meson_dw_hdmi_out_bus_fmts[] = {
 	MEDIA_BUS_FMT_YUV8_1X24,
+	MEDIA_BUS_FMT_UYYVYY8_0_5X24,
 };
 
 static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
@@ -717,18 +743,23 @@ meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge,
 					unsigned int *num_input_fmts)
 {
 	u32 *input_fmts = NULL;
+	int i;
 
-	if (output_fmt == meson_dw_hdmi_out_bus_fmts[0]) {
-		*num_input_fmts = 1;
-		input_fmts = kcalloc(*num_input_fmts,
-				     sizeof(*input_fmts),
-				     GFP_KERNEL);
-		if (!input_fmts)
-			return NULL;
+	*num_input_fmts = 0;
 
-		input_fmts[0] = output_fmt;
-	} else {
-		*num_input_fmts = 0;
+	for (i = 0 ; i < ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts) ; ++i) {
+		if (output_fmt == meson_dw_hdmi_out_bus_fmts[i]) {
+			*num_input_fmts = 1;
+			input_fmts = kcalloc(*num_input_fmts,
+					     sizeof(*input_fmts),
+					     GFP_KERNEL);
+			if (!input_fmts)
+				return NULL;
+
+			input_fmts[0] = output_fmt;
+
+			break;
+		}
 	}
 
 	return input_fmts;
@@ -739,6 +770,12 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge,
 					struct drm_crtc_state *crtc_state,
 					struct drm_connector_state *conn_state)
 {
+	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
+
+	dw_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format;
+
+	DRM_DEBUG_DRIVER("output_bus_fmt %lx\n", dw_hdmi->output_bus_fmt);
+
 	return 0;
 }
 
@@ -776,18 +813,29 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
 	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
 	struct meson_drm *priv = dw_hdmi->priv;
 	int vic = drm_match_cea_mode(mode);
+	unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR;
+	bool yuv420_mode = false;
 
 	DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic);
 
+	if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) {
+		ycrcb_map = VPU_HDMI_OUTPUT_CRYCB;
+		yuv420_mode = true;
+	}
+
 	/* VENC + VENC-DVI Mode setup */
-	meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, false,
-				 VPU_HDMI_OUTPUT_CBYCR);
+	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->output_bus_fmt == 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_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = {
@@ -1045,6 +1093,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 	dw_plat_data->phy_name = "meson_dw_hdmi_phy";
 	dw_plat_data->phy_data = meson_dw_hdmi;
 	dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
+	dw_plat_data->ycbcr_420_allowed = true;
 
 	if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
 	    dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
-- 
2.22.0


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
  2020-02-06 19:18 ` [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation Neil Armstrong
@ 2020-02-07 10:57   ` Boris Brezillon
  2020-03-02  9:56   ` Laurent Pinchart
  1 sibling, 0 replies; 41+ messages in thread
From: Boris Brezillon @ 2020-02-07 10:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	Laurent.pinchart, linux-amlogic

On Thu,  6 Feb 2020 20:18:26 +0100
Neil Armstrong <narmstrong@baylibre.com> wrote:

> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 051001f77dd4..fec4a4bcd1fe 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2494,6 +2494,9 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
>  }
>  
>  static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
> +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset = drm_atomic_helper_bridge_reset,
>  	.attach = dw_hdmi_bridge_attach,
>  	.detach = dw_hdmi_bridge_detach,
>  	.enable = dw_hdmi_bridge_enable,


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18 ` [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation Neil Armstrong
@ 2020-02-07 11:02   ` Boris Brezillon
  2020-02-07 13:36     ` Neil Armstrong
  2020-02-29  7:42   ` Jernej Škrabec
  2020-03-02 10:18   ` Laurent Pinchart
  2 siblings, 1 reply; 41+ messages in thread
From: Boris Brezillon @ 2020-02-07 11:02 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	Laurent.pinchart, linux-amlogic

On Thu,  6 Feb 2020 20:18:27 +0100
Neil Armstrong <narmstrong@baylibre.com> wrote:

> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate

								^ hooks?

> the possible output and input formats for the current mode and monitor,
> and use the negotiated formats in a basic atomic_check callback.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---

> +
> +/* Can return a maximum of 4 possible input formats for an output format */
> +#define MAX_INPUT_SEL_FORMATS	4

It seems to only be 3 in practice (based on the code) unless I missed
something.

> +
> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +	int i = 0;
> +
> +	*num_input_fmts = 0;
> +
> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
> +			     GFP_KERNEL);
> +	if (!input_fmts)
> +		return NULL;
> +
> +	switch (output_fmt) {
> +	/* 8bit */
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		break;
> +	case MEDIA_BUS_FMT_YUV8_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +
> +	/* 10bit */
> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		break;
> +	case MEDIA_BUS_FMT_YUV10_1X30:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		break;
> +
> +	/* 12bit */
> +	case MEDIA_BUS_FMT_RGB121212_1X36:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		break;
> +	case MEDIA_BUS_FMT_YUV12_1X36:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY12_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		break;
> +
> +	/* 16bit */
> +	case MEDIA_BUS_FMT_RGB161616_1X48:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +		break;
> +	case MEDIA_BUS_FMT_YUV16_1X48:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +		break;
> +
> +	/* 420 */
> +	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:
> +		input_fmts[i++] = output_fmt;
> +		break;
> +	}
> +
> +	*num_input_fmts = i;
> +
> +	if (*num_input_fmts == 0) {
> +		kfree(input_fmts);
> +		input_fmts = NULL;
> +	}
> +
> +	return input_fmts;
> +}
> +
> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
> +				       struct drm_bridge_state *bridge_state,
> +				       struct drm_crtc_state *crtc_state,
> +				       struct drm_connector_state *conn_state)
> +{
> +	struct dw_hdmi *hdmi = bridge->driver_private;
> +
> +	dev_dbg(hdmi->dev, "selected output format %x\n",
> +			bridge_state->output_bus_cfg.format);

Nit: not aligned on the open parens.

> +
> +	hdmi->hdmi_data.enc_out_bus_format =
> +			bridge_state->output_bus_cfg.format;
> +
> +	dev_dbg(hdmi->dev, "selected input format %x\n",
> +			bridge_state->input_bus_cfg.format);
> +
> +	hdmi->hdmi_data.enc_in_bus_format =
> +			bridge_state->input_bus_cfg.format;
> +
> +	return 0;
> +}
> +
>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>  {
>  	struct dw_hdmi *hdmi = bridge->driver_private;
> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>  	.atomic_reset = drm_atomic_helper_bridge_reset,
>  	.attach = dw_hdmi_bridge_attach,
>  	.detach = dw_hdmi_bridge_detach,
> +	.atomic_check = dw_hdmi_bridge_atomic_check,
> +	.atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
> +	.atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
>  	.enable = dw_hdmi_bridge_enable,
>  	.disable = dw_hdmi_bridge_disable,
>  	.mode_set = dw_hdmi_bridge_mode_set,
> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  
>  	hdmi->bridge.driver_private = hdmi;
>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
> +

Nit: not sure this has to be part of that patch.

Looks good otherwise.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

>  #ifdef CONFIG_OF
>  	hdmi->bridge.of_node = pdev->dev.of_node;
>  #endif


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-07 11:02   ` Boris Brezillon
@ 2020-02-07 13:36     ` Neil Armstrong
  0 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-07 13:36 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	Laurent.pinchart, linux-amlogic

On 07/02/2020 12:02, Boris Brezillon wrote:
> On Thu,  6 Feb 2020 20:18:27 +0100
> Neil Armstrong <narmstrong@baylibre.com> wrote:
> 
>> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
> 
> 								^ hooks?
> 
>> the possible output and input formats for the current mode and monitor,
>> and use the negotiated formats in a basic atomic_check callback.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
> 
>> +
>> +/* Can return a maximum of 4 possible input formats for an output format */
>> +#define MAX_INPUT_SEL_FORMATS	4
> 
> It seems to only be 3 in practice (based on the code) unless I missed
> something.

You're right...

> 
>> +
>> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
>> +					struct drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state *crtc_state,
>> +					struct drm_connector_state *conn_state,
>> +					u32 output_fmt,
>> +					unsigned int *num_input_fmts)
>> +{
>> +	u32 *input_fmts;
>> +	int i = 0;
>> +
>> +	*num_input_fmts = 0;
>> +
>> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
>> +			     GFP_KERNEL);
>> +	if (!input_fmts)
>> +		return NULL;
>> +
>> +	switch (output_fmt) {
>> +	/* 8bit */
>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV8_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +
>> +	/* 10bit */
>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV10_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +
>> +	/* 12bit */
>> +	case MEDIA_BUS_FMT_RGB121212_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV12_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY12_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +
>> +	/* 16bit */
>> +	case MEDIA_BUS_FMT_RGB161616_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV16_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		break;
>> +
>> +	/* 420 */
>> +	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:
>> +		input_fmts[i++] = output_fmt;
>> +		break;
>> +	}
>> +
>> +	*num_input_fmts = i;
>> +
>> +	if (*num_input_fmts == 0) {
>> +		kfree(input_fmts);
>> +		input_fmts = NULL;
>> +	}
>> +
>> +	return input_fmts;
>> +}
>> +
>> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
>> +				       struct drm_bridge_state *bridge_state,
>> +				       struct drm_crtc_state *crtc_state,
>> +				       struct drm_connector_state *conn_state)
>> +{
>> +	struct dw_hdmi *hdmi = bridge->driver_private;
>> +
>> +	dev_dbg(hdmi->dev, "selected output format %x\n",
>> +			bridge_state->output_bus_cfg.format);
> 
> Nit: not aligned on the open parens.
> 
>> +
>> +	hdmi->hdmi_data.enc_out_bus_format =
>> +			bridge_state->output_bus_cfg.format;
>> +
>> +	dev_dbg(hdmi->dev, "selected input format %x\n",
>> +			bridge_state->input_bus_cfg.format);
>> +
>> +	hdmi->hdmi_data.enc_in_bus_format =
>> +			bridge_state->input_bus_cfg.format;
>> +
>> +	return 0;
>> +}
>> +
>>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>>  {
>>  	struct dw_hdmi *hdmi = bridge->driver_private;
>> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>>  	.atomic_reset = drm_atomic_helper_bridge_reset,
>>  	.attach = dw_hdmi_bridge_attach,
>>  	.detach = dw_hdmi_bridge_detach,
>> +	.atomic_check = dw_hdmi_bridge_atomic_check,
>> +	.atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
>> +	.atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
>>  	.enable = dw_hdmi_bridge_enable,
>>  	.disable = dw_hdmi_bridge_disable,
>>  	.mode_set = dw_hdmi_bridge_mode_set,
>> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>  
>>  	hdmi->bridge.driver_private = hdmi;
>>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
>> +
> 
> Nit: not sure this has to be part of that patch.
> 
> Looks good otherwise.
> 
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>


Thanks, will fixup in a v5 or while applying.

Neil

> 
>>  #ifdef CONFIG_OF
>>  	hdmi->bridge.of_node = pdev->dev.of_node;
>>  #endif
> 


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2020-02-06 19:18 ` [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
@ 2020-02-07 13:38   ` Neil Armstrong
  2020-03-02 10:03   ` Laurent Pinchart
  1 sibling, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-07 13:38 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel

On 06/02/2020 20:18, Neil Armstrong wrote:
> 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 15048ad694bc..4b35ea1427df 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -3231,6 +3231,12 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  	hdmi->bridge.of_node = pdev->dev.of_node;
>  #endif
>  
> +	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 9d4d5cc47969..0b34a12c4a1c 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -129,6 +129,7 @@ struct dw_hdmi_plat_data {
>  	unsigned long input_bus_format;
>  	unsigned long input_bus_encoding;
>  	bool use_drm_infoframe;
> +	bool ycbcr_420_allowed;
>  
>  	/* Vendor PHY support */
>  	const struct dw_hdmi_phy_ops *phy_ops;
> 

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

from 020c82bc-15fd-6e23-a093-62abfa9b466d@samsung.com

Neil

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
  2020-02-06 19:18 ` [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const Neil Armstrong
@ 2020-02-07 13:39   ` Neil Armstrong
  2020-03-02  9:59   ` Laurent Pinchart
  1 sibling, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-07 13:39 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel

On 06/02/2020 20:18, Neil Armstrong wrote:
> Before switching to bridge funcs, make sure drm_display_mode is passed
> as const to the venc functions.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/meson/meson_venc.c | 2 +-
>  drivers/gpu/drm/meson/meson_venc.h | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
> index 4efd7864d5bf..a9ab78970bfe 100644
> --- a/drivers/gpu/drm/meson/meson_venc.c
> +++ b/drivers/gpu/drm/meson/meson_venc.c
> @@ -946,7 +946,7 @@ 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,
> -			      struct drm_display_mode *mode)
> +			      const struct drm_display_mode *mode)
>  {
>  	union meson_hdmi_venc_mode *vmode = NULL;
>  	union meson_hdmi_venc_mode vmode_dmt;
> diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
> index 576768bdd08d..1abdcbdf51c0 100644
> --- a/drivers/gpu/drm/meson/meson_venc.h
> +++ b/drivers/gpu/drm/meson/meson_venc.h
> @@ -60,7 +60,7 @@ 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,
> -			      struct drm_display_mode *mode);
> +			      const struct drm_display_mode *mode);
>  unsigned int meson_venci_get_field(struct meson_drm *priv);
>  
>  void meson_venc_enable_vsync(struct meson_drm *priv);
> 


Forgot to add:

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

from 20190821203233.47137f57@collabora.com

Neil

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs
  2020-02-06 19:18 ` [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs Neil Armstrong
@ 2020-02-07 14:57   ` Boris Brezillon
  2020-02-07 15:36     ` Neil Armstrong
  0 siblings, 1 reply; 41+ messages in thread
From: Boris Brezillon @ 2020-02-07 14:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	Laurent.pinchart, linux-amlogic

On Thu,  6 Feb 2020 20:18:30 +0100
Neil Armstrong <narmstrong@baylibre.com> wrote:

> Switch the dw-hdmi driver to drm_bridge_funcs by implementing a new local
> bridge, connecting it to the dw-hdmi bridge, then implement the
> atomic_get_input_bus_fmts/atomic_get_output_bus_fmts.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/meson/meson_dw_hdmi.c | 105 +++++++++++++++++++++-----
>  1 file changed, 85 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> index 3bb7ffe5fc39..4b3809626f7e 100644
> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> @@ -16,6 +16,7 @@
>  
>  #include <drm/bridge/dw_hdmi.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_probe_helper.h>
> @@ -135,6 +136,7 @@ struct meson_dw_hdmi_data {
>  
>  struct meson_dw_hdmi {
>  	struct drm_encoder encoder;
> +	struct drm_bridge bridge;
>  	struct dw_hdmi_plat_data dw_plat_data;
>  	struct meson_drm *priv;
>  	struct device *dev;
> @@ -151,6 +153,8 @@ struct meson_dw_hdmi {
>  };
>  #define encoder_to_meson_dw_hdmi(x) \
>  	container_of(x, struct meson_dw_hdmi, encoder)
> +#define bridge_to_meson_dw_hdmi(x) \
> +	container_of(x, struct meson_dw_hdmi, bridge)
>  
>  static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
>  					const char *compat)
> @@ -368,7 +372,7 @@ static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
>  }
>  
>  static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
> -			     struct drm_display_mode *mode)
> +			     const struct drm_display_mode *mode)
>  {
>  	struct meson_drm *priv = dw_hdmi->priv;
>  	int vic = drm_match_cea_mode(mode);
> @@ -663,6 +667,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
>  
>  /* Encoder */
>  
> +static const u32 meson_dw_hdmi_out_bus_fmts[] = {
> +	MEDIA_BUS_FMT_YUV8_1X24,
> +};
> +
>  static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
>  {
>  	drm_encoder_cleanup(encoder);
> @@ -672,16 +680,63 @@ static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
>  	.destroy        = meson_venc_hdmi_encoder_destroy,
>  };
>  
> -static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
> +static u32 *
> +meson_venc_hdmi_encoder_get_out_bus_fmts(struct drm_bridge *bridge,
> +					 struct drm_bridge_state *bridge_state,
> +					 struct drm_crtc_state *crtc_state,
> +					 struct drm_connector_state *conn_state,
> +					 unsigned int *num_output_fmts)
> +{
> +	u32 *output_fmts;
> +
> +	*num_output_fmts = ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts);
> +	output_fmts = kcalloc(*num_output_fmts, sizeof(*output_fmts),
> +			      GFP_KERNEL);
> +	if (!output_fmts)
> +		return NULL;
> +
> +	memcpy(output_fmts, meson_dw_hdmi_out_bus_fmts, *num_output_fmts);
> +
> +	return output_fmts;
> +}
> +
> +static u32 *
> +meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts = NULL;
> +
> +	if (output_fmt == meson_dw_hdmi_out_bus_fmts[0]) {
> +		*num_input_fmts = 1;
> +		input_fmts = kcalloc(*num_input_fmts,
> +				     sizeof(*input_fmts),
> +				     GFP_KERNEL);
> +		if (!input_fmts)
> +			return NULL;
> +
> +		input_fmts[0] = output_fmt;
> +	} else {
> +		*num_input_fmts = 0;
> +	}
> +
> +	return input_fmts;
> +}
> +
> +static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
>  					struct drm_crtc_state *crtc_state,
>  					struct drm_connector_state *conn_state)
>  {
>  	return 0;
>  }
>  
> -static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
> +static void meson_venc_hdmi_encoder_disable(struct drm_bridge *bridge)
>  {
> -	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> +	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
>  	struct meson_drm *priv = dw_hdmi->priv;
>  
>  	DRM_DEBUG_DRIVER("\n");
> @@ -693,9 +748,9 @@ static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
>  	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
>  }
>  
> -static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
> +static void meson_venc_hdmi_encoder_enable(struct drm_bridge *bridge)
>  {
> -	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> +	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
>  	struct meson_drm *priv = dw_hdmi->priv;
>  
>  	DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
> @@ -706,11 +761,11 @@ static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
>  		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
>  }
>  
> -static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
> -				   struct drm_display_mode *mode,
> -				   struct drm_display_mode *adjusted_mode)
> +static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
> +				   const struct drm_display_mode *mode,
> +				   const struct drm_display_mode *adjusted_mode)
>  {
> -	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> +	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
>  	struct meson_drm *priv = dw_hdmi->priv;
>  	int vic = drm_match_cea_mode(mode);
>  
> @@ -726,12 +781,16 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
>  	writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
>  }
>  
> -static const struct drm_encoder_helper_funcs
> -				meson_venc_hdmi_encoder_helper_funcs = {
> -	.atomic_check	= meson_venc_hdmi_encoder_atomic_check,
> -	.disable	= meson_venc_hdmi_encoder_disable,
> -	.enable		= meson_venc_hdmi_encoder_enable,
> -	.mode_set	= meson_venc_hdmi_encoder_mode_set,
> +static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = {
> +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> +	.atomic_get_output_bus_fmts = meson_venc_hdmi_encoder_get_out_bus_fmts,

Hm, can this bridge element be connected directly to the HDMI connector
without the dw-hdmi bridge in the middle? If that's not the case, then
you probably don't have to implement ->atomic_get_output_bus_fmts()
(only used on the last bridge element).

> +	.atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts,
> +	.atomic_reset = drm_atomic_helper_bridge_reset,
> +	.atomic_check = meson_venc_hdmi_encoder_atomic_check,
> +	.enable	= meson_venc_hdmi_encoder_enable,
> +	.disable = meson_venc_hdmi_encoder_disable,
> +	.mode_set = meson_venc_hdmi_encoder_mode_set,
>  };
>  
>  /* DW HDMI Regmap */
> @@ -852,6 +911,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>  	struct drm_device *drm = data;
>  	struct meson_drm *priv = drm->dev_private;
>  	struct dw_hdmi_plat_data *dw_plat_data;
> +	struct drm_bridge *next_bridge;
>  	struct drm_encoder *encoder;
>  	struct resource *res;
>  	int irq;
> @@ -953,8 +1013,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>  
>  	/* Encoder */
>  
> -	drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
> -
>  	ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
>  			       DRM_MODE_ENCODER_TMDS, "meson_hdmi");
>  	if (ret) {
> @@ -962,6 +1020,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>  		return ret;
>  	}
>  
> +	meson_dw_hdmi->bridge.funcs = &meson_venc_hdmi_encoder_bridge_funcs;
> +	drm_bridge_attach(encoder, &meson_dw_hdmi->bridge, NULL);
> +
>  	encoder->possible_crtcs = BIT(0);
>  
>  	DRM_DEBUG_DRIVER("encoder initialized\n");
> @@ -984,11 +1045,15 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>  
>  	platform_set_drvdata(pdev, meson_dw_hdmi);
>  
> -	meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
> -					   &meson_dw_hdmi->dw_plat_data);
> +	meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev,
> +					    &meson_dw_hdmi->dw_plat_data);
>  	if (IS_ERR(meson_dw_hdmi->hdmi))
>  		return PTR_ERR(meson_dw_hdmi->hdmi);
>  
> +	next_bridge = of_drm_find_bridge(pdev->dev.of_node);
> +	if (next_bridge)
> +		drm_bridge_attach(encoder, next_bridge, &meson_dw_hdmi->bridge);
> +
>  	DRM_DEBUG_DRIVER("HDMI controller initialized\n");
>  
>  	return 0;


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs
  2020-02-07 14:57   ` Boris Brezillon
@ 2020-02-07 15:36     ` Neil Armstrong
  0 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-02-07 15:36 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	Laurent.pinchart, linux-amlogic

On 07/02/2020 15:57, Boris Brezillon wrote:
> On Thu,  6 Feb 2020 20:18:30 +0100
> Neil Armstrong <narmstrong@baylibre.com> wrote:
> 
>> Switch the dw-hdmi driver to drm_bridge_funcs by implementing a new local
>> bridge, connecting it to the dw-hdmi bridge, then implement the
>> atomic_get_input_bus_fmts/atomic_get_output_bus_fmts.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/meson/meson_dw_hdmi.c | 105 +++++++++++++++++++++-----
>>  1 file changed, 85 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
>> index 3bb7ffe5fc39..4b3809626f7e 100644
>> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
>> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
>> @@ -16,6 +16,7 @@
>>  
>>  #include <drm/bridge/dw_hdmi.h>
>>  #include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_bridge.h>
>>  #include <drm/drm_device.h>
>>  #include <drm/drm_edid.h>
>>  #include <drm/drm_probe_helper.h>
>> @@ -135,6 +136,7 @@ struct meson_dw_hdmi_data {
>>  
>>  struct meson_dw_hdmi {
>>  	struct drm_encoder encoder;
>> +	struct drm_bridge bridge;
>>  	struct dw_hdmi_plat_data dw_plat_data;
>>  	struct meson_drm *priv;
>>  	struct device *dev;
>> @@ -151,6 +153,8 @@ struct meson_dw_hdmi {
>>  };
>>  #define encoder_to_meson_dw_hdmi(x) \
>>  	container_of(x, struct meson_dw_hdmi, encoder)
>> +#define bridge_to_meson_dw_hdmi(x) \
>> +	container_of(x, struct meson_dw_hdmi, bridge)
>>  
>>  static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
>>  					const char *compat)
>> @@ -368,7 +372,7 @@ static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
>>  }
>>  
>>  static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
>> -			     struct drm_display_mode *mode)
>> +			     const struct drm_display_mode *mode)
>>  {
>>  	struct meson_drm *priv = dw_hdmi->priv;
>>  	int vic = drm_match_cea_mode(mode);
>> @@ -663,6 +667,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
>>  
>>  /* Encoder */
>>  
>> +static const u32 meson_dw_hdmi_out_bus_fmts[] = {
>> +	MEDIA_BUS_FMT_YUV8_1X24,
>> +};
>> +
>>  static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
>>  {
>>  	drm_encoder_cleanup(encoder);
>> @@ -672,16 +680,63 @@ static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
>>  	.destroy        = meson_venc_hdmi_encoder_destroy,
>>  };
>>  
>> -static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
>> +static u32 *
>> +meson_venc_hdmi_encoder_get_out_bus_fmts(struct drm_bridge *bridge,
>> +					 struct drm_bridge_state *bridge_state,
>> +					 struct drm_crtc_state *crtc_state,
>> +					 struct drm_connector_state *conn_state,
>> +					 unsigned int *num_output_fmts)
>> +{
>> +	u32 *output_fmts;
>> +
>> +	*num_output_fmts = ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts);
>> +	output_fmts = kcalloc(*num_output_fmts, sizeof(*output_fmts),
>> +			      GFP_KERNEL);
>> +	if (!output_fmts)
>> +		return NULL;
>> +
>> +	memcpy(output_fmts, meson_dw_hdmi_out_bus_fmts, *num_output_fmts);
>> +
>> +	return output_fmts;
>> +}
>> +
>> +static u32 *
>> +meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge,
>> +					struct drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state *crtc_state,
>> +					struct drm_connector_state *conn_state,
>> +					u32 output_fmt,
>> +					unsigned int *num_input_fmts)
>> +{
>> +	u32 *input_fmts = NULL;
>> +
>> +	if (output_fmt == meson_dw_hdmi_out_bus_fmts[0]) {
>> +		*num_input_fmts = 1;
>> +		input_fmts = kcalloc(*num_input_fmts,
>> +				     sizeof(*input_fmts),
>> +				     GFP_KERNEL);
>> +		if (!input_fmts)
>> +			return NULL;
>> +
>> +		input_fmts[0] = output_fmt;
>> +	} else {
>> +		*num_input_fmts = 0;
>> +	}
>> +
>> +	return input_fmts;
>> +}
>> +
>> +static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge,
>> +					struct drm_bridge_state *bridge_state,
>>  					struct drm_crtc_state *crtc_state,
>>  					struct drm_connector_state *conn_state)
>>  {
>>  	return 0;
>>  }
>>  
>> -static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
>> +static void meson_venc_hdmi_encoder_disable(struct drm_bridge *bridge)
>>  {
>> -	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
>> +	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
>>  	struct meson_drm *priv = dw_hdmi->priv;
>>  
>>  	DRM_DEBUG_DRIVER("\n");
>> @@ -693,9 +748,9 @@ static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
>>  	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
>>  }
>>  
>> -static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
>> +static void meson_venc_hdmi_encoder_enable(struct drm_bridge *bridge)
>>  {
>> -	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
>> +	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
>>  	struct meson_drm *priv = dw_hdmi->priv;
>>  
>>  	DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
>> @@ -706,11 +761,11 @@ static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
>>  		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
>>  }
>>  
>> -static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
>> -				   struct drm_display_mode *mode,
>> -				   struct drm_display_mode *adjusted_mode)
>> +static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
>> +				   const struct drm_display_mode *mode,
>> +				   const struct drm_display_mode *adjusted_mode)
>>  {
>> -	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
>> +	struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
>>  	struct meson_drm *priv = dw_hdmi->priv;
>>  	int vic = drm_match_cea_mode(mode);
>>  
>> @@ -726,12 +781,16 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
>>  	writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
>>  }
>>  
>> -static const struct drm_encoder_helper_funcs
>> -				meson_venc_hdmi_encoder_helper_funcs = {
>> -	.atomic_check	= meson_venc_hdmi_encoder_atomic_check,
>> -	.disable	= meson_venc_hdmi_encoder_disable,
>> -	.enable		= meson_venc_hdmi_encoder_enable,
>> -	.mode_set	= meson_venc_hdmi_encoder_mode_set,
>> +static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = {
>> +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
>> +	.atomic_get_output_bus_fmts = meson_venc_hdmi_encoder_get_out_bus_fmts,
> 
> Hm, can this bridge element be connected directly to the HDMI connector
> without the dw-hdmi bridge in the middle? If that's not the case, then
> you probably don't have to implement ->atomic_get_output_bus_fmts()
> (only used on the last bridge element).

No, the HDMI bridge is mandatory here.

Ok, makes sense, I'll remove it then.

Neil

> 
>> +	.atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts,
>> +	.atomic_reset = drm_atomic_helper_bridge_reset,
>> +	.atomic_check = meson_venc_hdmi_encoder_atomic_check,
>> +	.enable	= meson_venc_hdmi_encoder_enable,
>> +	.disable = meson_venc_hdmi_encoder_disable,
>> +	.mode_set = meson_venc_hdmi_encoder_mode_set,
>>  };
>>  
>>  /* DW HDMI Regmap */
>> @@ -852,6 +911,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>>  	struct drm_device *drm = data;
>>  	struct meson_drm *priv = drm->dev_private;
>>  	struct dw_hdmi_plat_data *dw_plat_data;
>> +	struct drm_bridge *next_bridge;
>>  	struct drm_encoder *encoder;
>>  	struct resource *res;
>>  	int irq;
>> @@ -953,8 +1013,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>>  
>>  	/* Encoder */
>>  
>> -	drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
>> -
>>  	ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
>>  			       DRM_MODE_ENCODER_TMDS, "meson_hdmi");
>>  	if (ret) {
>> @@ -962,6 +1020,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>>  		return ret;
>>  	}
>>  
>> +	meson_dw_hdmi->bridge.funcs = &meson_venc_hdmi_encoder_bridge_funcs;
>> +	drm_bridge_attach(encoder, &meson_dw_hdmi->bridge, NULL);
>> +
>>  	encoder->possible_crtcs = BIT(0);
>>  
>>  	DRM_DEBUG_DRIVER("encoder initialized\n");
>> @@ -984,11 +1045,15 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>>  
>>  	platform_set_drvdata(pdev, meson_dw_hdmi);
>>  
>> -	meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
>> -					   &meson_dw_hdmi->dw_plat_data);
>> +	meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev,
>> +					    &meson_dw_hdmi->dw_plat_data);
>>  	if (IS_ERR(meson_dw_hdmi->hdmi))
>>  		return PTR_ERR(meson_dw_hdmi->hdmi);
>>  
>> +	next_bridge = of_drm_find_bridge(pdev->dev.of_node);
>> +	if (next_bridge)
>> +		drm_bridge_attach(encoder, next_bridge, &meson_dw_hdmi->bridge);
>> +
>>  	DRM_DEBUG_DRIVER("HDMI controller initialized\n");
>>  
>>  	return 0;
> 


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
  2020-02-06 19:18 ` [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property Neil Armstrong
@ 2020-02-17  6:38   ` Jernej Škrabec
  2020-02-21  8:50     ` Neil Armstrong
  0 siblings, 1 reply; 41+ messages in thread
From: Jernej Škrabec @ 2020-02-17  6:38 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, boris.brezillon, Neil Armstrong
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

Hi!

Dne četrtek, 06. februar 2020 ob 20:18:25 CET je Neil Armstrong napisal(a):
> From: Jonas Karlman <jonas@kwiboo.se>
> 
> Add the max_bpc property to the dw-hdmi connector to prepare support
> for 10, 12 & 16bit output support.
> 
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
> 9e0927d22db6..051001f77dd4 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2406,6 +2406,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge
> *bridge) DRM_MODE_CONNECTOR_HDMIA,
>  				    hdmi->ddc);
> 
> +	drm_atomic_helper_connector_reset(connector);

Why is this reset needed?

Best regards,
Jernej

> +
> +	drm_connector_attach_max_bpc_property(connector, 8, 16);
> +
>  	if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
>  		drm_object_attach_property(&connector->base,
>  			connector->dev-
>mode_config.hdr_output_metadata_property, 0);





_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
  2020-02-17  6:38   ` Jernej Škrabec
@ 2020-02-21  8:50     ` Neil Armstrong
  2020-03-02  9:18       ` Laurent Pinchart
  0 siblings, 1 reply; 41+ messages in thread
From: Neil Armstrong @ 2020-02-21  8:50 UTC (permalink / raw)
  To: Jernej Škrabec, a.hajda, Laurent.pinchart, jonas, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel

Hi Jernej,

On 17/02/2020 07:38, Jernej Škrabec wrote:
> Hi!
> 
> Dne četrtek, 06. februar 2020 ob 20:18:25 CET je Neil Armstrong napisal(a):
>> From: Jonas Karlman <jonas@kwiboo.se>
>>
>> Add the max_bpc property to the dw-hdmi connector to prepare support
>> for 10, 12 & 16bit output support.
>>
>> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
>>  1 file changed, 4 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
>> 9e0927d22db6..051001f77dd4 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -2406,6 +2406,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge
>> *bridge) DRM_MODE_CONNECTOR_HDMIA,
>>  				    hdmi->ddc);
>>
>> +	drm_atomic_helper_connector_reset(connector);
> 
> Why is this reset needed?

I assume it's to allocate a new connector state to attach a the bpc propery.

But indeed, this helper is never used here, but only as callback to the drm_connector_funcs->reset.

But, amdgpu calls :
	/*
	 * Some of the properties below require access to state, like bpc.
	 * Allocate some default initial connector state with our reset helper.
	 */
	if (aconnector->base.funcs->reset)
		aconnector->base.funcs->reset(&aconnector->base);

which is the same.

Neil

> 
> Best regards,
> Jernej
> 
>> +
>> +	drm_connector_attach_max_bpc_property(connector, 8, 16);
>> +
>>  	if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
>>  		drm_object_attach_property(&connector->base,
>>  			connector->dev-
>> mode_config.hdr_output_metadata_property, 0);
> 
> 
> 
> 


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18 ` [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation Neil Armstrong
  2020-02-07 11:02   ` Boris Brezillon
@ 2020-02-29  7:42   ` Jernej Škrabec
  2020-02-29 10:09     ` Jonas Karlman
  2020-03-02  8:04     ` Neil Armstrong
  2020-03-02 10:18   ` Laurent Pinchart
  2 siblings, 2 replies; 41+ messages in thread
From: Jernej Škrabec @ 2020-02-29  7:42 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, jonas, boris.brezillon, Neil Armstrong
  Cc: linux-amlogic, linux-kernel, dri-devel, Neil Armstrong

Hi Neil!

Dne četrtek, 06. februar 2020 ob 20:18:27 CET je Neil Armstrong napisal(a):
> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
> the possible output and input formats for the current mode and monitor,
> and use the negotiated formats in a basic atomic_check callback.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
>  1 file changed, 268 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
> fec4a4bcd1fe..15048ad694bc 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
> struct drm_display_mode *mode)
> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
>  	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)
>  		hdmi->hdmi_data.enc_in_bus_format =
>  			hdmi->plat_data->input_bus_format;
> -	else
> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
>  		hdmi->hdmi_data.enc_in_bus_format = 
MEDIA_BUS_FMT_RGB888_1X24;
> 
>  	/* TOFIX: Get input encoding from plat data or fallback to none */
> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct
> drm_display_mode *mode) 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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
> +		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;
> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs
> dw_hdmi_connector_helper_funcs = .atomic_check =
> dw_hdmi_connector_atomic_check,
>  };
> 
> +/*
> + * Possible output formats :
> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
> + * - MEDIA_BUS_FMT_YUV16_1X48,
> + * - MEDIA_BUS_FMT_RGB161616_1X48,
> + * - MEDIA_BUS_FMT_UYVY12_1X24,
> + * - MEDIA_BUS_FMT_YUV12_1X36,
> + * - MEDIA_BUS_FMT_RGB121212_1X36,
> + * - MEDIA_BUS_FMT_UYVY10_1X20,
> + * - MEDIA_BUS_FMT_YUV10_1X30,
> + * - MEDIA_BUS_FMT_RGB101010_1X30,
> + * - MEDIA_BUS_FMT_UYVY8_1X16,
> + * - MEDIA_BUS_FMT_YUV8_1X24,
> + * - MEDIA_BUS_FMT_RGB888_1X24,
> + */
> +
> +/* Can return a maximum of 12 possible output formats for a mode/connector
> */ +#define MAX_OUTPUT_SEL_FORMATS	12
> +
> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge
> *bridge, +					struct 
drm_bridge_state *bridge_state,
> +					struct drm_crtc_state 
*crtc_state,
> +					struct 
drm_connector_state *conn_state,
> +					unsigned int 
*num_output_fmts)
> +{
> +	struct drm_connector *conn = conn_state->connector;
> +	struct drm_display_info *info = &conn->display_info;
> +	struct drm_display_mode *mode = &crtc_state->mode;
> +	u8 max_bpc = conn_state->max_requested_bpc;
> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
> +			     (info->color_formats & 
DRM_COLOR_FORMAT_YCRCB420);
> +	u32 *output_fmts;
> +	int i = 0;
> +
> +	*num_output_fmts = 0;
> +
> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
> +			      GFP_KERNEL);
> +	if (!output_fmts)
> +		return NULL;
> +
> +	/*
> +	 * If the current mode enforces 4:2:0, force the output but format
> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
> +	 */
> +	if (conn->ycbcr_420_allowed &&
> +	    (drm_mode_is_420_only(info, mode) ||
> +	     ())) {
> +
> +		/* Order bus formats from 16bit to 8bit if supported */
> +		if (max_bpc >= 16 && info->bpc == 16 &&
> +		    (info->hdmi.y420_dc_modes & 
DRM_EDID_YCBCR420_DC_48))
> +			output_fmts[i++] = 
MEDIA_BUS_FMT_UYYVYY16_0_5X48;
> +
> +		if (max_bpc >= 12 && info->bpc >= 12 &&
> +		    (info->hdmi.y420_dc_modes & 
DRM_EDID_YCBCR420_DC_36))
> +			output_fmts[i++] = 
MEDIA_BUS_FMT_UYYVYY12_0_5X36;
> +
> +		if (max_bpc >= 10 && info->bpc >= 10 &&
> +		    (info->hdmi.y420_dc_modes & 
DRM_EDID_YCBCR420_DC_30))
> +			output_fmts[i++] = 
MEDIA_BUS_FMT_UYYVYY10_0_5X30;
> +
> +		/* Default 8bit fallback */
> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
> +
> +		*num_output_fmts = i;
> +
> +		return output_fmts;

Driver shouldn't return just yet for case "is_hdmi2_sink && 
drm_mode_is_420_also(info, mode)", because monitor/TV also supports YCbCr 
4:4:4 in that case. IMO YCbCr 4:4:4 should be even prefered. What do you 
think?

Best regards,
Jernej

> +	}
> +
> +	/*
> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
> +	 * if supported. In any case the default RGB888 format is added
> +	 */
> +
> +	if (max_bpc >= 16 && info->bpc == 16) {
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +
> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +	}
> +
> +	if (max_bpc >= 12 && info->bpc >= 12) {
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +
> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +	}
> +
> +	if (max_bpc >= 10 && info->bpc >= 10) {
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +
> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +	}
> +
> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +
> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +
> +	/* Default 8bit RGB fallback */
> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +
> +	*num_output_fmts = i;
> +
> +	return output_fmts;
> +}
> +
> +/*
> + * Possible input formats :
> + * - MEDIA_BUS_FMT_RGB888_1X24
> + * - MEDIA_BUS_FMT_YUV8_1X24
> + * - MEDIA_BUS_FMT_UYVY8_1X16
> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
> + * - MEDIA_BUS_FMT_RGB101010_1X30
> + * - MEDIA_BUS_FMT_YUV10_1X30
> + * - MEDIA_BUS_FMT_UYVY10_1X20
> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
> + * - MEDIA_BUS_FMT_RGB121212_1X36
> + * - MEDIA_BUS_FMT_YUV12_1X36
> + * - MEDIA_BUS_FMT_UYVY12_1X24
> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
> + * - MEDIA_BUS_FMT_RGB161616_1X48
> + * - MEDIA_BUS_FMT_YUV16_1X48
> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
> + */
> +
> +/* Can return a maximum of 4 possible input formats for an output format */
> +#define MAX_INPUT_SEL_FORMATS	4
> +
> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge
> *bridge, +					struct 
drm_bridge_state *bridge_state,
> +					struct drm_crtc_state 
*crtc_state,
> +					struct 
drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int 
*num_input_fmts)
> +{
> +	u32 *input_fmts;
> +	int i = 0;
> +
> +	*num_input_fmts = 0;
> +
> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
> +			     GFP_KERNEL);
> +	if (!input_fmts)
> +		return NULL;
> +
> +	switch (output_fmt) {
> +	/* 8bit */
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		break;
> +	case MEDIA_BUS_FMT_YUV8_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +
> +	/* 10bit */
> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		break;
> +	case MEDIA_BUS_FMT_YUV10_1X30:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		break;
> +
> +	/* 12bit */
> +	case MEDIA_BUS_FMT_RGB121212_1X36:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		break;
> +	case MEDIA_BUS_FMT_YUV12_1X36:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY12_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		break;
> +
> +	/* 16bit */
> +	case MEDIA_BUS_FMT_RGB161616_1X48:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +		break;
> +	case MEDIA_BUS_FMT_YUV16_1X48:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +		break;
> +
> +	/* 420 */
> +	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:
> +		input_fmts[i++] = output_fmt;
> +		break;
> +	}
> +
> +	*num_input_fmts = i;
> +
> +	if (*num_input_fmts == 0) {
> +		kfree(input_fmts);
> +		input_fmts = NULL;
> +	}
> +
> +	return input_fmts;
> +}
> +
> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
> +				       struct drm_bridge_state 
*bridge_state,
> +				       struct drm_crtc_state 
*crtc_state,
> +				       struct drm_connector_state 
*conn_state)
> +{
> +	struct dw_hdmi *hdmi = bridge->driver_private;
> +
> +	dev_dbg(hdmi->dev, "selected output format %x\n",
> +			bridge_state->output_bus_cfg.format);
> +
> +	hdmi->hdmi_data.enc_out_bus_format =
> +			bridge_state->output_bus_cfg.format;
> +
> +	dev_dbg(hdmi->dev, "selected input format %x\n",
> +			bridge_state->input_bus_cfg.format);
> +
> +	hdmi->hdmi_data.enc_in_bus_format =
> +			bridge_state->input_bus_cfg.format;
> +
> +	return 0;
> +}
> +
>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>  {
>  	struct dw_hdmi *hdmi = bridge->driver_private;
> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs
> dw_hdmi_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset,
>  	.attach = dw_hdmi_bridge_attach,
>  	.detach = dw_hdmi_bridge_detach,
> +	.atomic_check = dw_hdmi_bridge_atomic_check,
> +	.atomic_get_output_bus_fmts = 
dw_hdmi_bridge_atomic_get_output_bus_fmts,
> +	.atomic_get_input_bus_fmts = 
dw_hdmi_bridge_atomic_get_input_bus_fmts,
>  	.enable = dw_hdmi_bridge_enable,
>  	.disable = dw_hdmi_bridge_disable,
>  	.mode_set = dw_hdmi_bridge_mode_set,
> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
> 
>  	hdmi->bridge.driver_private = hdmi;
>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
> +
>  #ifdef CONFIG_OF
>  	hdmi->bridge.of_node = pdev->dev.of_node;
>  #endif





_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-29  7:42   ` Jernej Škrabec
@ 2020-02-29 10:09     ` Jonas Karlman
  2020-02-29 11:07       ` Jernej Škrabec
  2020-03-02  8:08       ` Neil Armstrong
  2020-03-02  8:04     ` Neil Armstrong
  1 sibling, 2 replies; 41+ messages in thread
From: Jonas Karlman @ 2020-02-29 10:09 UTC (permalink / raw)
  To: Jernej Škrabec, a.hajda, Laurent.pinchart, boris.brezillon,
	Neil Armstrong
  Cc: linux-amlogic, linux-kernel, dri-devel

Hi Jernej,

On 2020-02-29 08:42, Jernej Škrabec wrote:
> Hi Neil!
> 
> Dne četrtek, 06. februar 2020 ob 20:18:27 CET je Neil Armstrong napisal(a):
>> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
>> the possible output and input formats for the current mode and monitor,
>> and use the negotiated formats in a basic atomic_check callback.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
>>  1 file changed, 268 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
>> fec4a4bcd1fe..15048ad694bc 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
>> struct drm_display_mode *mode)
>> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
>>  	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)
>>  		hdmi->hdmi_data.enc_in_bus_format =
>>  			hdmi->plat_data->input_bus_format;
>> -	else
>> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
>>  		hdmi->hdmi_data.enc_in_bus_format = 
> MEDIA_BUS_FMT_RGB888_1X24;
>>
>>  	/* TOFIX: Get input encoding from plat data or fallback to none */
>> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct
>> drm_display_mode *mode) 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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
>> +		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;
>> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs
>> dw_hdmi_connector_helper_funcs = .atomic_check =
>> dw_hdmi_connector_atomic_check,
>>  };
>>
>> +/*
>> + * Possible output formats :
>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
>> + * - MEDIA_BUS_FMT_YUV16_1X48,
>> + * - MEDIA_BUS_FMT_RGB161616_1X48,
>> + * - MEDIA_BUS_FMT_UYVY12_1X24,
>> + * - MEDIA_BUS_FMT_YUV12_1X36,
>> + * - MEDIA_BUS_FMT_RGB121212_1X36,
>> + * - MEDIA_BUS_FMT_UYVY10_1X20,
>> + * - MEDIA_BUS_FMT_YUV10_1X30,
>> + * - MEDIA_BUS_FMT_RGB101010_1X30,
>> + * - MEDIA_BUS_FMT_UYVY8_1X16,
>> + * - MEDIA_BUS_FMT_YUV8_1X24,
>> + * - MEDIA_BUS_FMT_RGB888_1X24,
>> + */
>> +
>> +/* Can return a maximum of 12 possible output formats for a mode/connector
>> */ +#define MAX_OUTPUT_SEL_FORMATS	12
>> +
>> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge
>> *bridge, +					struct 
> drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state 
> *crtc_state,
>> +					struct 
> drm_connector_state *conn_state,
>> +					unsigned int 
> *num_output_fmts)
>> +{
>> +	struct drm_connector *conn = conn_state->connector;
>> +	struct drm_display_info *info = &conn->display_info;
>> +	struct drm_display_mode *mode = &crtc_state->mode;
>> +	u8 max_bpc = conn_state->max_requested_bpc;
>> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
>> +			     (info->color_formats & 
> DRM_COLOR_FORMAT_YCRCB420);
>> +	u32 *output_fmts;
>> +	int i = 0;
>> +
>> +	*num_output_fmts = 0;
>> +
>> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
>> +			      GFP_KERNEL);
>> +	if (!output_fmts)
>> +		return NULL;
>> +
>> +	/*
>> +	 * If the current mode enforces 4:2:0, force the output but format
>> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
>> +	 */
>> +	if (conn->ycbcr_420_allowed &&
>> +	    (drm_mode_is_420_only(info, mode) ||
>> +	     ())) {
>> +
>> +		/* Order bus formats from 16bit to 8bit if supported */
>> +		if (max_bpc >= 16 && info->bpc == 16 &&
>> +		    (info->hdmi.y420_dc_modes & 
> DRM_EDID_YCBCR420_DC_48))
>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYYVYY16_0_5X48;
>> +
>> +		if (max_bpc >= 12 && info->bpc >= 12 &&
>> +		    (info->hdmi.y420_dc_modes & 
> DRM_EDID_YCBCR420_DC_36))
>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYYVYY12_0_5X36;
>> +
>> +		if (max_bpc >= 10 && info->bpc >= 10 &&
>> +		    (info->hdmi.y420_dc_modes & 
> DRM_EDID_YCBCR420_DC_30))
>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYYVYY10_0_5X30;
>> +
>> +		/* Default 8bit fallback */
>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
>> +
>> +		*num_output_fmts = i;
>> +
>> +		return output_fmts;
> 
> Driver shouldn't return just yet for case "is_hdmi2_sink && 
> drm_mode_is_420_also(info, mode)", because monitor/TV also supports YCbCr 
> 4:4:4 in that case. IMO YCbCr 4:4:4 should be even prefered. What do you 
> think?

I think we need to have some way for controller driver and userspace to control what
hdmi output format gets selected. I know for a fact that some Samsung TV have issues
with 444 YCbCr modes at 4k 50/60hz but have no problems with 420 modes.
The Samsung TV edid lie and/or the TV is not fully following HDMI specs.

From a personal and mediaplayer userspace perspective I would like to prefer
420/444 YCbCr mode as soon as any yuv drm plane is active and rgb 444 anytime else.

On Rockchip SoCs the display controller cannot output yuv422 to dw-hdmi block,
the optimal output format selection in such case should put yuv422 last.

Maybe dw-hdmi can call a dw-hdmi glue driver callback to get the preferred output format order?

On a side note but related issue, the dw-hdmi format negotiation code should 
probably also filter modes on tmds rate, something like [1].
It is needed to filter out deep color modes that is not supported by the sink or hdmi spec.

[1] https://github.com/Kwiboo/linux-rockchip/commit/fc3df6903384e764ab6ac59879c489cbef55fcbe

Best regards,
Jonas

> 
> Best regards,
> Jernej
> 
>> +	}
>> +
>> +	/*
>> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
>> +	 * if supported. In any case the default RGB888 format is added
>> +	 */
>> +
>> +	if (max_bpc >= 16 && info->bpc == 16) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +	}
>> +
>> +	if (max_bpc >= 12 && info->bpc >= 12) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +	}
>> +
>> +	if (max_bpc >= 10 && info->bpc >= 10) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +	}
>> +
>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +
>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +
>> +	/* Default 8bit RGB fallback */
>> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +
>> +	*num_output_fmts = i;
>> +
>> +	return output_fmts;
>> +}
>> +
>> +/*
>> + * Possible input formats :
>> + * - MEDIA_BUS_FMT_RGB888_1X24
>> + * - MEDIA_BUS_FMT_YUV8_1X24
>> + * - MEDIA_BUS_FMT_UYVY8_1X16
>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
>> + * - MEDIA_BUS_FMT_RGB101010_1X30
>> + * - MEDIA_BUS_FMT_YUV10_1X30
>> + * - MEDIA_BUS_FMT_UYVY10_1X20
>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
>> + * - MEDIA_BUS_FMT_RGB121212_1X36
>> + * - MEDIA_BUS_FMT_YUV12_1X36
>> + * - MEDIA_BUS_FMT_UYVY12_1X24
>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
>> + * - MEDIA_BUS_FMT_RGB161616_1X48
>> + * - MEDIA_BUS_FMT_YUV16_1X48
>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
>> + */
>> +
>> +/* Can return a maximum of 4 possible input formats for an output format */
>> +#define MAX_INPUT_SEL_FORMATS	4
>> +
>> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge
>> *bridge, +					struct 
> drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state 
> *crtc_state,
>> +					struct 
> drm_connector_state *conn_state,
>> +					u32 output_fmt,
>> +					unsigned int 
> *num_input_fmts)
>> +{
>> +	u32 *input_fmts;
>> +	int i = 0;
>> +
>> +	*num_input_fmts = 0;
>> +
>> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
>> +			     GFP_KERNEL);
>> +	if (!input_fmts)
>> +		return NULL;
>> +
>> +	switch (output_fmt) {
>> +	/* 8bit */
>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV8_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +
>> +	/* 10bit */
>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV10_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +
>> +	/* 12bit */
>> +	case MEDIA_BUS_FMT_RGB121212_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV12_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY12_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +
>> +	/* 16bit */
>> +	case MEDIA_BUS_FMT_RGB161616_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV16_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		break;
>> +
>> +	/* 420 */
>> +	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:
>> +		input_fmts[i++] = output_fmt;
>> +		break;
>> +	}
>> +
>> +	*num_input_fmts = i;
>> +
>> +	if (*num_input_fmts == 0) {
>> +		kfree(input_fmts);
>> +		input_fmts = NULL;
>> +	}
>> +
>> +	return input_fmts;
>> +}
>> +
>> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
>> +				       struct drm_bridge_state 
> *bridge_state,
>> +				       struct drm_crtc_state 
> *crtc_state,
>> +				       struct drm_connector_state 
> *conn_state)
>> +{
>> +	struct dw_hdmi *hdmi = bridge->driver_private;
>> +
>> +	dev_dbg(hdmi->dev, "selected output format %x\n",
>> +			bridge_state->output_bus_cfg.format);
>> +
>> +	hdmi->hdmi_data.enc_out_bus_format =
>> +			bridge_state->output_bus_cfg.format;
>> +
>> +	dev_dbg(hdmi->dev, "selected input format %x\n",
>> +			bridge_state->input_bus_cfg.format);
>> +
>> +	hdmi->hdmi_data.enc_in_bus_format =
>> +			bridge_state->input_bus_cfg.format;
>> +
>> +	return 0;
>> +}
>> +
>>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>>  {
>>  	struct dw_hdmi *hdmi = bridge->driver_private;
>> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs
>> dw_hdmi_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset,
>>  	.attach = dw_hdmi_bridge_attach,
>>  	.detach = dw_hdmi_bridge_detach,
>> +	.atomic_check = dw_hdmi_bridge_atomic_check,
>> +	.atomic_get_output_bus_fmts = 
> dw_hdmi_bridge_atomic_get_output_bus_fmts,
>> +	.atomic_get_input_bus_fmts = 
> dw_hdmi_bridge_atomic_get_input_bus_fmts,
>>  	.enable = dw_hdmi_bridge_enable,
>>  	.disable = dw_hdmi_bridge_disable,
>>  	.mode_set = dw_hdmi_bridge_mode_set,
>> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>
>>  	hdmi->bridge.driver_private = hdmi;
>>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
>> +
>>  #ifdef CONFIG_OF
>>  	hdmi->bridge.of_node = pdev->dev.of_node;
>>  #endif
> 
> 
> 
> 

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-29 10:09     ` Jonas Karlman
@ 2020-02-29 11:07       ` Jernej Škrabec
  2020-02-29 12:15         ` Jonas Karlman
  2020-03-02  8:08       ` Neil Armstrong
  1 sibling, 1 reply; 41+ messages in thread
From: Jernej Škrabec @ 2020-02-29 11:07 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, boris.brezillon, Neil Armstrong,
	Jonas Karlman
  Cc: linux-amlogic, linux-kernel, dri-devel

Dne sobota, 29. februar 2020 ob 11:09:14 CET je Jonas Karlman napisal(a):
> Hi Jernej,
> 
> On 2020-02-29 08:42, Jernej Škrabec wrote:
> > Hi Neil!
> > 
> > Dne četrtek, 06. februar 2020 ob 20:18:27 CET je Neil Armstrong 
napisal(a):
> >> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to
> >> negociate
> >> the possible output and input formats for the current mode and monitor,
> >> and use the negotiated formats in a basic atomic_check callback.
> >> 
> >> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> >> ---
> >> 
> >>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
> >>  1 file changed, 268 insertions(+), 4 deletions(-)
> >> 
> >> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
> >> fec4a4bcd1fe..15048ad694bc 100644
> >> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
> >> struct drm_display_mode *mode)
> >> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
> >> 
> >>  	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)
> >>  	
> >>  		hdmi->hdmi_data.enc_in_bus_format =
> >>  		
> >>  			hdmi->plat_data->input_bus_format;
> >> 
> >> -	else
> >> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
> >> 
> >>  		hdmi->hdmi_data.enc_in_bus_format =
> > 
> > MEDIA_BUS_FMT_RGB888_1X24;
> > 
> >>  	/* TOFIX: Get input encoding from plat data or fallback to none */
> >> 
> >> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
> >> struct
> >> drm_display_mode *mode) 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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
> >> +		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;
> >> 
> >> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs
> >> dw_hdmi_connector_helper_funcs = .atomic_check =
> >> dw_hdmi_connector_atomic_check,
> >> 
> >>  };
> >> 
> >> +/*
> >> + * Possible output formats :
> >> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
> >> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
> >> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
> >> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
> >> + * - MEDIA_BUS_FMT_YUV16_1X48,
> >> + * - MEDIA_BUS_FMT_RGB161616_1X48,
> >> + * - MEDIA_BUS_FMT_UYVY12_1X24,
> >> + * - MEDIA_BUS_FMT_YUV12_1X36,
> >> + * - MEDIA_BUS_FMT_RGB121212_1X36,
> >> + * - MEDIA_BUS_FMT_UYVY10_1X20,
> >> + * - MEDIA_BUS_FMT_YUV10_1X30,
> >> + * - MEDIA_BUS_FMT_RGB101010_1X30,
> >> + * - MEDIA_BUS_FMT_UYVY8_1X16,
> >> + * - MEDIA_BUS_FMT_YUV8_1X24,
> >> + * - MEDIA_BUS_FMT_RGB888_1X24,
> >> + */
> >> +
> >> +/* Can return a maximum of 12 possible output formats for a
> >> mode/connector
> >> */ +#define MAX_OUTPUT_SEL_FORMATS	12
> >> +
> >> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge
> >> *bridge, +					struct
> > 
> > drm_bridge_state *bridge_state,
> > 
> >> +					struct drm_crtc_state
> > 
> > *crtc_state,
> > 
> >> +					struct
> > 
> > drm_connector_state *conn_state,
> > 
> >> +					unsigned int
> > 
> > *num_output_fmts)
> > 
> >> +{
> >> +	struct drm_connector *conn = conn_state->connector;
> >> +	struct drm_display_info *info = &conn->display_info;
> >> +	struct drm_display_mode *mode = &crtc_state->mode;
> >> +	u8 max_bpc = conn_state->max_requested_bpc;
> >> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
> >> +			     (info->color_formats &
> > 
> > DRM_COLOR_FORMAT_YCRCB420);
> > 
> >> +	u32 *output_fmts;
> >> +	int i = 0;
> >> +
> >> +	*num_output_fmts = 0;
> >> +
> >> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, 
sizeof(*output_fmts),
> >> +			      GFP_KERNEL);
> >> +	if (!output_fmts)
> >> +		return NULL;
> >> +
> >> +	/*
> >> +	 * If the current mode enforces 4:2:0, force the output but format
> >> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
> >> +	 */
> >> +	if (conn->ycbcr_420_allowed &&
> >> +	    (drm_mode_is_420_only(info, mode) ||
> >> +	     ())) {
> >> +
> >> +		/* Order bus formats from 16bit to 8bit if supported */
> >> +		if (max_bpc >= 16 && info->bpc == 16 &&
> >> +		    (info->hdmi.y420_dc_modes &
> > 
> > DRM_EDID_YCBCR420_DC_48))
> > 
> >> +			output_fmts[i++] =
> > 
> > MEDIA_BUS_FMT_UYYVYY16_0_5X48;
> > 
> >> +
> >> +		if (max_bpc >= 12 && info->bpc >= 12 &&
> >> +		    (info->hdmi.y420_dc_modes &
> > 
> > DRM_EDID_YCBCR420_DC_36))
> > 
> >> +			output_fmts[i++] =
> > 
> > MEDIA_BUS_FMT_UYYVYY12_0_5X36;
> > 
> >> +
> >> +		if (max_bpc >= 10 && info->bpc >= 10 &&
> >> +		    (info->hdmi.y420_dc_modes &
> > 
> > DRM_EDID_YCBCR420_DC_30))
> > 
> >> +			output_fmts[i++] =
> > 
> > MEDIA_BUS_FMT_UYYVYY10_0_5X30;
> > 
> >> +
> >> +		/* Default 8bit fallback */
> >> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
> >> +
> >> +		*num_output_fmts = i;
> >> +
> >> +		return output_fmts;
> > 
> > Driver shouldn't return just yet for case "is_hdmi2_sink &&
> > drm_mode_is_420_also(info, mode)", because monitor/TV also supports YCbCr
> > 4:4:4 in that case. IMO YCbCr 4:4:4 should be even prefered. What do you
> > think?
> 
> I think we need to have some way for controller driver and userspace to
> control what hdmi output format gets selected. I know for a fact that some
> Samsung TV have issues with 444 YCbCr modes at 4k 50/60hz but have no
> problems with 420 modes. The Samsung TV edid lie and/or the TV is not fully
> following HDMI specs

Interesting, maybe just some bandwith issues? I guess we should have a 
blacklist for such cases. I know that at least Allwinner BSP driver for DW 
HDMI has a blacklist, in this case for 2 monitors which claim to support YCbCr 
4:4:4 mode but they not.

> 
> From a personal and mediaplayer userspace perspective I would like to prefer
> 420/444 YCbCr mode as soon as any yuv drm plane is active and rgb 444
> anytime else.

I would argue that YCbCr is always prefered:
- CEA 861 prefers it for all CEA modes
- avoid dealing with quantization range - it's always limited range for < hdmi 
2.0 and selectable on some hdmi 2.0 capable sinks

Anyway, there is no universal solution to avoid color space conversion in all 
cases. For example, due to design of Allwinner Display Engine 2, it can only 
work in RGB format internally, but it can convert final output to YCbCr right 
before it's feeded to DW HDMI. On the other hand, you have meson display 
pipeline which works in YCbCr format internally and relies on DW HDMI CSC unit 
to convert output to RGB. Fortunately, there are also display pipelines which 
can work in any colorspace internally, like Allwinner Display Engine 3. Not 
sure in which category Rockchip display pipeline falls into.

> 
> On Rockchip SoCs the display controller cannot output yuv422 to dw-hdmi
> block, the optimal output format selection in such case should put yuv422
> last.

Note that DW HDMI has decimation support which converts 444 to 422. This is 
part of CSC unit.

Side note: CSC unit is optional feature of DW-HDMI and presence is indicated 
by config register. However, it seems that CSC support is broken in DW HDMI 
controller on 40nm Allwinner SoCs. If it is enabled, TV loses signal. I have 
to investigate if only CSC is broken or decimation also don't work.

> 
> Maybe dw-hdmi can call a dw-hdmi glue driver callback to get the preferred
> output format order?
> 
> On a side note but related issue, the dw-hdmi format negotiation code should
> probably also filter modes on tmds rate, something like [1].
> It is needed to filter out deep color modes that is not supported by the
> sink or hdmi spec.

Ah, you mean on TMDS rates supported by the sink. Could this avoid Samsung 
deep color issues? If so, we don't need blacklist then.

Best regards,
Jernej

> 
> [1]
> https://github.com/Kwiboo/linux-rockchip/commit/fc3df6903384e764ab6ac59879c
> 489cbef55fcbe
> 
> Best regards,
> Jonas
> 
> > Best regards,
> > Jernej
> > 
> >> +	}
> >> +
> >> +	/*
> >> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
> >> +	 * if supported. In any case the default RGB888 format is added
> >> +	 */
> >> +
> >> +	if (max_bpc >= 16 && info->bpc == 16) {
> >> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> >> +
> >> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> >> +	}
> >> +
> >> +	if (max_bpc >= 12 && info->bpc >= 12) {
> >> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> >> +			output_fmts[i++] = 
MEDIA_BUS_FMT_UYVY12_1X24;
> >> +
> >> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >> +
> >> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >> +	}
> >> +
> >> +	if (max_bpc >= 10 && info->bpc >= 10) {
> >> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> >> +			output_fmts[i++] = 
MEDIA_BUS_FMT_UYVY10_1X20;
> >> +
> >> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >> +
> >> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >> +	}
> >> +
> >> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> >> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >> +
> >> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >> +
> >> +	/* Default 8bit RGB fallback */
> >> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >> +
> >> +	*num_output_fmts = i;
> >> +
> >> +	return output_fmts;
> >> +}
> >> +
> >> +/*
> >> + * Possible input formats :
> >> + * - MEDIA_BUS_FMT_RGB888_1X24
> >> + * - MEDIA_BUS_FMT_YUV8_1X24
> >> + * - MEDIA_BUS_FMT_UYVY8_1X16
> >> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
> >> + * - MEDIA_BUS_FMT_RGB101010_1X30
> >> + * - MEDIA_BUS_FMT_YUV10_1X30
> >> + * - MEDIA_BUS_FMT_UYVY10_1X20
> >> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
> >> + * - MEDIA_BUS_FMT_RGB121212_1X36
> >> + * - MEDIA_BUS_FMT_YUV12_1X36
> >> + * - MEDIA_BUS_FMT_UYVY12_1X24
> >> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
> >> + * - MEDIA_BUS_FMT_RGB161616_1X48
> >> + * - MEDIA_BUS_FMT_YUV16_1X48
> >> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
> >> + */
> >> +
> >> +/* Can return a maximum of 4 possible input formats for an output format
> >> */ +#define MAX_INPUT_SEL_FORMATS	4
> >> +
> >> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge
> >> *bridge, +					struct
> > 
> > drm_bridge_state *bridge_state,
> > 
> >> +					struct drm_crtc_state
> > 
> > *crtc_state,
> > 
> >> +					struct
> > 
> > drm_connector_state *conn_state,
> > 
> >> +					u32 output_fmt,
> >> +					unsigned int
> > 
> > *num_input_fmts)
> > 
> >> +{
> >> +	u32 *input_fmts;
> >> +	int i = 0;
> >> +
> >> +	*num_input_fmts = 0;
> >> +
> >> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
> >> +			     GFP_KERNEL);
> >> +	if (!input_fmts)
> >> +		return NULL;
> >> +
> >> +	switch (output_fmt) {
> >> +	/* 8bit */
> >> +	case MEDIA_BUS_FMT_RGB888_1X24:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >> +		break;
> >> +	case MEDIA_BUS_FMT_YUV8_1X24:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >> +		break;
> >> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >> +		break;
> >> +
> >> +	/* 10bit */
> >> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> >> +		break;
> >> +	case MEDIA_BUS_FMT_YUV10_1X30:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >> +		break;
> >> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >> +		break;
> >> +
> >> +	/* 12bit */
> >> +	case MEDIA_BUS_FMT_RGB121212_1X36:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> >> +		break;
> >> +	case MEDIA_BUS_FMT_YUV12_1X36:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >> +		break;
> >> +	case MEDIA_BUS_FMT_UYVY12_1X24:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >> +		break;
> >> +
> >> +	/* 16bit */
> >> +	case MEDIA_BUS_FMT_RGB161616_1X48:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> >> +		break;
> >> +	case MEDIA_BUS_FMT_YUV16_1X48:
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> >> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> >> +		break;
> >> +
> >> +	/* 420 */
> >> +	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:
> >> +		input_fmts[i++] = output_fmt;
> >> +		break;
> >> +	}
> >> +
> >> +	*num_input_fmts = i;
> >> +
> >> +	if (*num_input_fmts == 0) {
> >> +		kfree(input_fmts);
> >> +		input_fmts = NULL;
> >> +	}
> >> +
> >> +	return input_fmts;
> >> +}
> >> +
> >> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
> >> +				       struct drm_bridge_state
> > 
> > *bridge_state,
> > 
> >> +				       struct drm_crtc_state
> > 
> > *crtc_state,
> > 
> >> +				       struct drm_connector_state
> > 
> > *conn_state)
> > 
> >> +{
> >> +	struct dw_hdmi *hdmi = bridge->driver_private;
> >> +
> >> +	dev_dbg(hdmi->dev, "selected output format %x\n",
> >> +			bridge_state->output_bus_cfg.format);
> >> +
> >> +	hdmi->hdmi_data.enc_out_bus_format =
> >> +			bridge_state->output_bus_cfg.format;
> >> +
> >> +	dev_dbg(hdmi->dev, "selected input format %x\n",
> >> +			bridge_state->input_bus_cfg.format);
> >> +
> >> +	hdmi->hdmi_data.enc_in_bus_format =
> >> +			bridge_state->input_bus_cfg.format;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> 
> >>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
> >>  {
> >>  
> >>  	struct dw_hdmi *hdmi = bridge->driver_private;
> >> 
> >> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs
> >> dw_hdmi_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset,
> >> 
> >>  	.attach = dw_hdmi_bridge_attach,
> >>  	.detach = dw_hdmi_bridge_detach,
> >> 
> >> +	.atomic_check = dw_hdmi_bridge_atomic_check,
> >> +	.atomic_get_output_bus_fmts =
> > 
> > dw_hdmi_bridge_atomic_get_output_bus_fmts,
> > 
> >> +	.atomic_get_input_bus_fmts =
> > 
> > dw_hdmi_bridge_atomic_get_input_bus_fmts,
> > 
> >>  	.enable = dw_hdmi_bridge_enable,
> >>  	.disable = dw_hdmi_bridge_disable,
> >>  	.mode_set = dw_hdmi_bridge_mode_set,
> >> 
> >> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
> >> 
> >>  	hdmi->bridge.driver_private = hdmi;
> >>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
> >> 
> >> +
> >> 
> >>  #ifdef CONFIG_OF
> >>  
> >>  	hdmi->bridge.of_node = pdev->dev.of_node;
> >>  
> >>  #endif





_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-29 11:07       ` Jernej Škrabec
@ 2020-02-29 12:15         ` Jonas Karlman
  2020-02-29 14:42           ` Jernej Škrabec
  0 siblings, 1 reply; 41+ messages in thread
From: Jonas Karlman @ 2020-02-29 12:15 UTC (permalink / raw)
  To: Jernej Škrabec, a.hajda, Laurent.pinchart, boris.brezillon,
	Neil Armstrong
  Cc: linux-amlogic, linux-kernel, dri-devel

On 2020-02-29 12:07, Jernej Škrabec wrote:
> Dne sobota, 29. februar 2020 ob 11:09:14 CET je Jonas Karlman napisal(a):
>> Hi Jernej,
>>
>> On 2020-02-29 08:42, Jernej Škrabec wrote:
>>> Hi Neil!
>>>
>>> Dne četrtek, 06. februar 2020 ob 20:18:27 CET je Neil Armstrong 
> napisal(a):
>>>> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to
>>>> negociate
>>>> the possible output and input formats for the current mode and monitor,
>>>> and use the negotiated formats in a basic atomic_check callback.
>>>>
>>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>>> ---
>>>>
>>>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
>>>>  1 file changed, 268 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
>>>> fec4a4bcd1fe..15048ad694bc 100644
>>>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>>> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
>>>> struct drm_display_mode *mode)
>>>> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
>>>>
>>>>  	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)
>>>>  	
>>>>  		hdmi->hdmi_data.enc_in_bus_format =
>>>>  		
>>>>  			hdmi->plat_data->input_bus_format;
>>>>
>>>> -	else
>>>> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
>>>>
>>>>  		hdmi->hdmi_data.enc_in_bus_format =
>>>
>>> MEDIA_BUS_FMT_RGB888_1X24;
>>>
>>>>  	/* TOFIX: Get input encoding from plat data or fallback to none */
>>>>
>>>> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
>>>> struct
>>>> drm_display_mode *mode) 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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
>>>> +		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;
>>>>
>>>> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs
>>>> dw_hdmi_connector_helper_funcs = .atomic_check =
>>>> dw_hdmi_connector_atomic_check,
>>>>
>>>>  };
>>>>
>>>> +/*
>>>> + * Possible output formats :
>>>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
>>>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
>>>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
>>>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
>>>> + * - MEDIA_BUS_FMT_YUV16_1X48,
>>>> + * - MEDIA_BUS_FMT_RGB161616_1X48,
>>>> + * - MEDIA_BUS_FMT_UYVY12_1X24,
>>>> + * - MEDIA_BUS_FMT_YUV12_1X36,
>>>> + * - MEDIA_BUS_FMT_RGB121212_1X36,
>>>> + * - MEDIA_BUS_FMT_UYVY10_1X20,
>>>> + * - MEDIA_BUS_FMT_YUV10_1X30,
>>>> + * - MEDIA_BUS_FMT_RGB101010_1X30,
>>>> + * - MEDIA_BUS_FMT_UYVY8_1X16,
>>>> + * - MEDIA_BUS_FMT_YUV8_1X24,
>>>> + * - MEDIA_BUS_FMT_RGB888_1X24,
>>>> + */
>>>> +
>>>> +/* Can return a maximum of 12 possible output formats for a
>>>> mode/connector
>>>> */ +#define MAX_OUTPUT_SEL_FORMATS	12
>>>> +
>>>> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge
>>>> *bridge, +					struct
>>>
>>> drm_bridge_state *bridge_state,
>>>
>>>> +					struct drm_crtc_state
>>>
>>> *crtc_state,
>>>
>>>> +					struct
>>>
>>> drm_connector_state *conn_state,
>>>
>>>> +					unsigned int
>>>
>>> *num_output_fmts)
>>>
>>>> +{
>>>> +	struct drm_connector *conn = conn_state->connector;
>>>> +	struct drm_display_info *info = &conn->display_info;
>>>> +	struct drm_display_mode *mode = &crtc_state->mode;
>>>> +	u8 max_bpc = conn_state->max_requested_bpc;
>>>> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
>>>> +			     (info->color_formats &
>>>
>>> DRM_COLOR_FORMAT_YCRCB420);
>>>
>>>> +	u32 *output_fmts;
>>>> +	int i = 0;
>>>> +
>>>> +	*num_output_fmts = 0;
>>>> +
>>>> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, 
> sizeof(*output_fmts),
>>>> +			      GFP_KERNEL);
>>>> +	if (!output_fmts)
>>>> +		return NULL;
>>>> +
>>>> +	/*
>>>> +	 * If the current mode enforces 4:2:0, force the output but format
>>>> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
>>>> +	 */
>>>> +	if (conn->ycbcr_420_allowed &&
>>>> +	    (drm_mode_is_420_only(info, mode) ||
>>>> +	     ())) {
>>>> +
>>>> +		/* Order bus formats from 16bit to 8bit if supported */
>>>> +		if (max_bpc >= 16 && info->bpc == 16 &&
>>>> +		    (info->hdmi.y420_dc_modes &
>>>
>>> DRM_EDID_YCBCR420_DC_48))
>>>
>>>> +			output_fmts[i++] =
>>>
>>> MEDIA_BUS_FMT_UYYVYY16_0_5X48;
>>>
>>>> +
>>>> +		if (max_bpc >= 12 && info->bpc >= 12 &&
>>>> +		    (info->hdmi.y420_dc_modes &
>>>
>>> DRM_EDID_YCBCR420_DC_36))
>>>
>>>> +			output_fmts[i++] =
>>>
>>> MEDIA_BUS_FMT_UYYVYY12_0_5X36;
>>>
>>>> +
>>>> +		if (max_bpc >= 10 && info->bpc >= 10 &&
>>>> +		    (info->hdmi.y420_dc_modes &
>>>
>>> DRM_EDID_YCBCR420_DC_30))
>>>
>>>> +			output_fmts[i++] =
>>>
>>> MEDIA_BUS_FMT_UYYVYY10_0_5X30;
>>>
>>>> +
>>>> +		/* Default 8bit fallback */
>>>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
>>>> +
>>>> +		*num_output_fmts = i;
>>>> +
>>>> +		return output_fmts;
>>>
>>> Driver shouldn't return just yet for case "is_hdmi2_sink &&
>>> drm_mode_is_420_also(info, mode)", because monitor/TV also supports YCbCr
>>> 4:4:4 in that case. IMO YCbCr 4:4:4 should be even prefered. What do you
>>> think?
>>
>> I think we need to have some way for controller driver and userspace to
>> control what hdmi output format gets selected. I know for a fact that some
>> Samsung TV have issues with 444 YCbCr modes at 4k 50/60hz but have no
>> problems with 420 modes. The Samsung TV edid lie and/or the TV is not fully
>> following HDMI specs
> 
> Interesting, maybe just some bandwith issues? I guess we should have a 
> blacklist for such cases. I know that at least Allwinner BSP driver for DW 
> HDMI has a blacklist, in this case for 2 monitors which claim to support YCbCr 
> 4:4:4 mode but they not.
> 
>>
>> From a personal and mediaplayer userspace perspective I would like to prefer
>> 420/444 YCbCr mode as soon as any yuv drm plane is active and rgb 444
>> anytime else.
> 
> I would argue that YCbCr is always prefered:
> - CEA 861 prefers it for all CEA modes
> - avoid dealing with quantization range - it's always limited range for < hdmi 
> 2.0 and selectable on some hdmi 2.0 capable sinks

This is probably true if your sink is a TV, for monitors with HDMI connections
I would expect or at least like to have an option to use rgb444 full range mode
for any desktop or gaming or similar use-case.

> 
> Anyway, there is no universal solution to avoid color space conversion in all 
> cases. For example, due to design of Allwinner Display Engine 2, it can only 
> work in RGB format internally, but it can convert final output to YCbCr right 
> before it's feeded to DW HDMI. On the other hand, you have meson display 
> pipeline which works in YCbCr format internally and relies on DW HDMI CSC unit 
> to convert output to RGB. Fortunately, there are also display pipelines which 
> can work in any colorspace internally, like Allwinner Display Engine 3. Not 
> sure in which category Rockchip display pipeline falls into.

Agree, and for Rockchip to my knowledge RK3288 VOP (Video Output Processor)
can only output 8/10-bit rgb (full range) to DW-HDMI.
And the VOP in RK322x/RK3328/RK3399 can output 8/10-bit rgb and 444/420 yuv.
I do not know how the VOP handles internal color conversion.

> 
>>
>> On Rockchip SoCs the display controller cannot output yuv422 to dw-hdmi
>> block, the optimal output format selection in such case should put yuv422
>> last.
> 
> Note that DW HDMI has decimation support which converts 444 to 422. This is 
> part of CSC unit.

This works as it should (after a patch to disable color conversion for 444 to 422),
the issue I see is that the format negotiation code will currently favor 444 to 422
decimation over using 444 output.
Note: 422 will not be selected over 444 currently in case sink report deep color support
due to drm edid parsing code following HDMI 1.3 spec, see [1].

[1] https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/drm_edid.c#L4801-L4806

> 
> Side note: CSC unit is optional feature of DW-HDMI and presence is indicated 
> by config register. However, it seems that CSC support is broken in DW HDMI 
> controller on 40nm Allwinner SoCs. If it is enabled, TV loses signal. I have 
> to investigate if only CSC is broken or decimation also don't work.
> 
>>
>> Maybe dw-hdmi can call a dw-hdmi glue driver callback to get the preferred
>> output format order?
>>
>> On a side note but related issue, the dw-hdmi format negotiation code should
>> probably also filter modes on tmds rate, something like [1].
>> It is needed to filter out deep color modes that is not supported by the
>> sink or hdmi spec.
> 
> Ah, you mean on TMDS rates supported by the sink. Could this avoid Samsung 
> deep color issues? If so, we don't need blacklist then.

I do not think so, the initial issue was reported with intel graphics but looking
at the edid and comparing to the manual of supported modes they do not fully match.
See manual info at [2] and edid when UHD mode is off at [3] and when on at [4].

[2] https://gitlab.freedesktop.org/drm/intel/uploads/36630c8a727bf8c66a53fd7470c88383/MU7000_manual_-_UHD_colour_modes.PNG
[3] http://ix.io/1H25
[4] http://ix.io/1H2e

> 
> Best regards,
> Jernej
> 
>>
>> [1]
>> https://github.com/Kwiboo/linux-rockchip/commit/fc3df6903384e764ab6ac59879c
>> 489cbef55fcbe
>>
>> Best regards,
>> Jonas
>>
>>> Best regards,
>>> Jernej
>>>
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
>>>> +	 * if supported. In any case the default RGB888 format is added
>>>> +	 */
>>>> +
>>>> +	if (max_bpc >= 16 && info->bpc == 16) {
>>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>>>> +
>>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>>>> +	}
>>>> +
>>>> +	if (max_bpc >= 12 && info->bpc >= 12) {
>>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>>>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYVY12_1X24;
>>>> +
>>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>>> +
>>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>>> +	}
>>>> +
>>>> +	if (max_bpc >= 10 && info->bpc >= 10) {
>>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>>>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYVY10_1X20;
>>>> +
>>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>>> +
>>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>>> +	}
>>>> +
>>>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>>>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>>> +
>>>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>>> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>>> +
>>>> +	/* Default 8bit RGB fallback */
>>>> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>>> +
>>>> +	*num_output_fmts = i;
>>>> +
>>>> +	return output_fmts;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Possible input formats :
>>>> + * - MEDIA_BUS_FMT_RGB888_1X24
>>>> + * - MEDIA_BUS_FMT_YUV8_1X24
>>>> + * - MEDIA_BUS_FMT_UYVY8_1X16
>>>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
>>>> + * - MEDIA_BUS_FMT_RGB101010_1X30
>>>> + * - MEDIA_BUS_FMT_YUV10_1X30
>>>> + * - MEDIA_BUS_FMT_UYVY10_1X20
>>>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
>>>> + * - MEDIA_BUS_FMT_RGB121212_1X36
>>>> + * - MEDIA_BUS_FMT_YUV12_1X36
>>>> + * - MEDIA_BUS_FMT_UYVY12_1X24
>>>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
>>>> + * - MEDIA_BUS_FMT_RGB161616_1X48
>>>> + * - MEDIA_BUS_FMT_YUV16_1X48
>>>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
>>>> + */
>>>> +
>>>> +/* Can return a maximum of 4 possible input formats for an output format
>>>> */ +#define MAX_INPUT_SEL_FORMATS	4
>>>> +
>>>> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge
>>>> *bridge, +					struct
>>>
>>> drm_bridge_state *bridge_state,
>>>
>>>> +					struct drm_crtc_state
>>>
>>> *crtc_state,
>>>
>>>> +					struct
>>>
>>> drm_connector_state *conn_state,
>>>
>>>> +					u32 output_fmt,
>>>> +					unsigned int
>>>
>>> *num_input_fmts)
>>>
>>>> +{
>>>> +	u32 *input_fmts;
>>>> +	int i = 0;
>>>> +
>>>> +	*num_input_fmts = 0;
>>>> +
>>>> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
>>>> +			     GFP_KERNEL);
>>>> +	if (!input_fmts)
>>>> +		return NULL;
>>>> +
>>>> +	switch (output_fmt) {
>>>> +	/* 8bit */
>>>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>>> +		break;
>>>> +	case MEDIA_BUS_FMT_YUV8_1X24:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>>> +		break;
>>>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>>> +		break;
>>>> +
>>>> +	/* 10bit */
>>>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>>>> +		break;
>>>> +	case MEDIA_BUS_FMT_YUV10_1X30:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>>> +		break;
>>>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>>> +		break;
>>>> +
>>>> +	/* 12bit */
>>>> +	case MEDIA_BUS_FMT_RGB121212_1X36:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>>>> +		break;
>>>> +	case MEDIA_BUS_FMT_YUV12_1X36:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>>> +		break;
>>>> +	case MEDIA_BUS_FMT_UYVY12_1X24:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>>> +		break;
>>>> +
>>>> +	/* 16bit */
>>>> +	case MEDIA_BUS_FMT_RGB161616_1X48:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>>>> +		break;
>>>> +	case MEDIA_BUS_FMT_YUV16_1X48:
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>>>> +		break;
>>>> +
>>>> +	/* 420 */
>>>> +	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:
>>>> +		input_fmts[i++] = output_fmt;
>>>> +		break;
>>>> +	}
>>>> +
>>>> +	*num_input_fmts = i;
>>>> +
>>>> +	if (*num_input_fmts == 0) {
>>>> +		kfree(input_fmts);
>>>> +		input_fmts = NULL;
>>>> +	}
>>>> +
>>>> +	return input_fmts;
>>>> +}
>>>> +
>>>> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
>>>> +				       struct drm_bridge_state
>>>
>>> *bridge_state,
>>>
>>>> +				       struct drm_crtc_state
>>>
>>> *crtc_state,
>>>
>>>> +				       struct drm_connector_state
>>>
>>> *conn_state)
>>>
>>>> +{
>>>> +	struct dw_hdmi *hdmi = bridge->driver_private;
>>>> +
>>>> +	dev_dbg(hdmi->dev, "selected output format %x\n",
>>>> +			bridge_state->output_bus_cfg.format);
>>>> +
>>>> +	hdmi->hdmi_data.enc_out_bus_format =
>>>> +			bridge_state->output_bus_cfg.format;
>>>> +
>>>> +	dev_dbg(hdmi->dev, "selected input format %x\n",
>>>> +			bridge_state->input_bus_cfg.format);
>>>> +
>>>> +	hdmi->hdmi_data.enc_in_bus_format =
>>>> +			bridge_state->input_bus_cfg.format;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>>
>>>>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>>>>  {
>>>>  
>>>>  	struct dw_hdmi *hdmi = bridge->driver_private;
>>>>
>>>> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs
>>>> dw_hdmi_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset,
>>>>
>>>>  	.attach = dw_hdmi_bridge_attach,
>>>>  	.detach = dw_hdmi_bridge_detach,
>>>>
>>>> +	.atomic_check = dw_hdmi_bridge_atomic_check,
>>>> +	.atomic_get_output_bus_fmts =
>>>
>>> dw_hdmi_bridge_atomic_get_output_bus_fmts,
>>>
>>>> +	.atomic_get_input_bus_fmts =
>>>
>>> dw_hdmi_bridge_atomic_get_input_bus_fmts,
>>>
>>>>  	.enable = dw_hdmi_bridge_enable,
>>>>  	.disable = dw_hdmi_bridge_disable,
>>>>  	.mode_set = dw_hdmi_bridge_mode_set,
>>>>
>>>> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>>>
>>>>  	hdmi->bridge.driver_private = hdmi;
>>>>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
>>>>
>>>> +
>>>>
>>>>  #ifdef CONFIG_OF
>>>>  
>>>>  	hdmi->bridge.of_node = pdev->dev.of_node;
>>>>  
>>>>  #endif
> 
> 
> 
> 

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-29 12:15         ` Jonas Karlman
@ 2020-02-29 14:42           ` Jernej Škrabec
  0 siblings, 0 replies; 41+ messages in thread
From: Jernej Škrabec @ 2020-02-29 14:42 UTC (permalink / raw)
  To: a.hajda, Laurent.pinchart, boris.brezillon, Neil Armstrong,
	Jonas Karlman
  Cc: linux-amlogic, linux-kernel, dri-devel

Dne sobota, 29. februar 2020 ob 13:15:26 CET je Jonas Karlman napisal(a):
> On 2020-02-29 12:07, Jernej Škrabec wrote:
> > Dne sobota, 29. februar 2020 ob 11:09:14 CET je Jonas Karlman napisal(a):
> >> Hi Jernej,
> >> 
> >> On 2020-02-29 08:42, Jernej Škrabec wrote:
> >>> Hi Neil!
> >>> 
> >>> Dne četrtek, 06. februar 2020 ob 20:18:27 CET je Neil Armstrong
> > 
> > napisal(a):
> >>>> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to
> >>>> negociate
> >>>> the possible output and input formats for the current mode and monitor,
> >>>> and use the negotiated formats in a basic atomic_check callback.
> >>>> 
> >>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> >>>> ---
> >>>> 
> >>>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
> >>>>  1 file changed, 268 insertions(+), 4 deletions(-)
> >>>> 
> >>>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >>>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
> >>>> fec4a4bcd1fe..15048ad694bc 100644
> >>>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >>>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >>>> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
> >>>> struct drm_display_mode *mode)
> >>>> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
> >>>> 
> >>>>  	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)
> >>>>  	
> >>>>  		hdmi->hdmi_data.enc_in_bus_format =
> >>>>  		
> >>>>  			hdmi->plat_data->input_bus_format;
> >>>> 
> >>>> -	else
> >>>> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
> >>>> 
> >>>>  		hdmi->hdmi_data.enc_in_bus_format =
> >>> 
> >>> MEDIA_BUS_FMT_RGB888_1X24;
> >>> 
> >>>>  	/* TOFIX: Get input encoding from plat data or fallback to none */
> >>>> 
> >>>> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
> >>>> struct
> >>>> drm_display_mode *mode) 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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
> >>>> +		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;
> >>>> 
> >>>> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs
> >>>> dw_hdmi_connector_helper_funcs = .atomic_check =
> >>>> dw_hdmi_connector_atomic_check,
> >>>> 
> >>>>  };
> >>>> 
> >>>> +/*
> >>>> + * Possible output formats :
> >>>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
> >>>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
> >>>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
> >>>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
> >>>> + * - MEDIA_BUS_FMT_YUV16_1X48,
> >>>> + * - MEDIA_BUS_FMT_RGB161616_1X48,
> >>>> + * - MEDIA_BUS_FMT_UYVY12_1X24,
> >>>> + * - MEDIA_BUS_FMT_YUV12_1X36,
> >>>> + * - MEDIA_BUS_FMT_RGB121212_1X36,
> >>>> + * - MEDIA_BUS_FMT_UYVY10_1X20,
> >>>> + * - MEDIA_BUS_FMT_YUV10_1X30,
> >>>> + * - MEDIA_BUS_FMT_RGB101010_1X30,
> >>>> + * - MEDIA_BUS_FMT_UYVY8_1X16,
> >>>> + * - MEDIA_BUS_FMT_YUV8_1X24,
> >>>> + * - MEDIA_BUS_FMT_RGB888_1X24,
> >>>> + */
> >>>> +
> >>>> +/* Can return a maximum of 12 possible output formats for a
> >>>> mode/connector
> >>>> */ +#define MAX_OUTPUT_SEL_FORMATS	12
> >>>> +
> >>>> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct
> >>>> drm_bridge
> >>>> *bridge, +					struct
> >>> 
> >>> drm_bridge_state *bridge_state,
> >>> 
> >>>> +					struct drm_crtc_state
> >>> 
> >>> *crtc_state,
> >>> 
> >>>> +					struct
> >>> 
> >>> drm_connector_state *conn_state,
> >>> 
> >>>> +					unsigned int
> >>> 
> >>> *num_output_fmts)
> >>> 
> >>>> +{
> >>>> +	struct drm_connector *conn = conn_state->connector;
> >>>> +	struct drm_display_info *info = &conn->display_info;
> >>>> +	struct drm_display_mode *mode = &crtc_state->mode;
> >>>> +	u8 max_bpc = conn_state->max_requested_bpc;
> >>>> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
> >>>> +			     (info->color_formats &
> >>> 
> >>> DRM_COLOR_FORMAT_YCRCB420);
> >>> 
> >>>> +	u32 *output_fmts;
> >>>> +	int i = 0;
> >>>> +
> >>>> +	*num_output_fmts = 0;
> >>>> +
> >>>> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS,
> > 
> > sizeof(*output_fmts),
> > 
> >>>> +			      GFP_KERNEL);
> >>>> +	if (!output_fmts)
> >>>> +		return NULL;
> >>>> +
> >>>> +	/*
> >>>> +	 * If the current mode enforces 4:2:0, force the output but format
> >>>> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
> >>>> +	 */
> >>>> +	if (conn->ycbcr_420_allowed &&
> >>>> +	    (drm_mode_is_420_only(info, mode) ||
> >>>> +	     ())) {
> >>>> +
> >>>> +		/* Order bus formats from 16bit to 8bit if supported */
> >>>> +		if (max_bpc >= 16 && info->bpc == 16 &&
> >>>> +		    (info->hdmi.y420_dc_modes &
> >>> 
> >>> DRM_EDID_YCBCR420_DC_48))
> >>> 
> >>>> +			output_fmts[i++] =
> >>> 
> >>> MEDIA_BUS_FMT_UYYVYY16_0_5X48;
> >>> 
> >>>> +
> >>>> +		if (max_bpc >= 12 && info->bpc >= 12 &&
> >>>> +		    (info->hdmi.y420_dc_modes &
> >>> 
> >>> DRM_EDID_YCBCR420_DC_36))
> >>> 
> >>>> +			output_fmts[i++] =
> >>> 
> >>> MEDIA_BUS_FMT_UYYVYY12_0_5X36;
> >>> 
> >>>> +
> >>>> +		if (max_bpc >= 10 && info->bpc >= 10 &&
> >>>> +		    (info->hdmi.y420_dc_modes &
> >>> 
> >>> DRM_EDID_YCBCR420_DC_30))
> >>> 
> >>>> +			output_fmts[i++] =
> >>> 
> >>> MEDIA_BUS_FMT_UYYVYY10_0_5X30;
> >>> 
> >>>> +
> >>>> +		/* Default 8bit fallback */
> >>>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
> >>>> +
> >>>> +		*num_output_fmts = i;
> >>>> +
> >>>> +		return output_fmts;
> >>> 
> >>> Driver shouldn't return just yet for case "is_hdmi2_sink &&
> >>> drm_mode_is_420_also(info, mode)", because monitor/TV also supports
> >>> YCbCr
> >>> 4:4:4 in that case. IMO YCbCr 4:4:4 should be even prefered. What do you
> >>> think?
> >> 
> >> I think we need to have some way for controller driver and userspace to
> >> control what hdmi output format gets selected. I know for a fact that
> >> some
> >> Samsung TV have issues with 444 YCbCr modes at 4k 50/60hz but have no
> >> problems with 420 modes. The Samsung TV edid lie and/or the TV is not
> >> fully
> >> following HDMI specs
> > 
> > Interesting, maybe just some bandwith issues? I guess we should have a
> > blacklist for such cases. I know that at least Allwinner BSP driver for DW
> > HDMI has a blacklist, in this case for 2 monitors which claim to support
> > YCbCr 4:4:4 mode but they not.
> > 
> >> From a personal and mediaplayer userspace perspective I would like to
> >> prefer 420/444 YCbCr mode as soon as any yuv drm plane is active and rgb
> >> 444 anytime else.
> > 
> > I would argue that YCbCr is always prefered:
> > - CEA 861 prefers it for all CEA modes
> > - avoid dealing with quantization range - it's always limited range for <
> > hdmi 2.0 and selectable on some hdmi 2.0 capable sinks
> 
> This is probably true if your sink is a TV, for monitors with HDMI
> connections I would expect or at least like to have an option to use rgb444
> full range mode for any desktop or gaming or similar use-case.

Well, thing is that CEA 861 clearly states that for CEA modes (720p, 1080p, 
2160p, etc.) limited range should be also used for RGB color space. With 
implemented logic to detect if RGB limited range is needed or not and 
indicating that in AVI frame, I finally get proper (better?) color reproduction 
with PC monitor and TV at the same time. I'm not sure if there is any way to 
detect "full range RGB" capable displays. However, we can always implement 
connector property like Intel did in i915 driver "Broadcast RGB", which can 
override RGB quantization mode.

> 
> > Anyway, there is no universal solution to avoid color space conversion in
> > all cases. For example, due to design of Allwinner Display Engine 2, it
> > can only work in RGB format internally, but it can convert final output
> > to YCbCr right before it's feeded to DW HDMI. On the other hand, you have
> > meson display pipeline which works in YCbCr format internally and relies
> > on DW HDMI CSC unit to convert output to RGB. Fortunately, there are also
> > display pipelines which can work in any colorspace internally, like
> > Allwinner Display Engine 3. Not sure in which category Rockchip display
> > pipeline falls into.
> 
> Agree, and for Rockchip to my knowledge RK3288 VOP (Video Output Processor)
> can only output 8/10-bit rgb (full range) to DW-HDMI.
> And the VOP in RK322x/RK3328/RK3399 can output 8/10-bit rgb and 444/420 yuv.
> I do not know how the VOP handles internal color conversion.
> 
> >> On Rockchip SoCs the display controller cannot output yuv422 to dw-hdmi
> >> block, the optimal output format selection in such case should put yuv422
> >> last.
> > 
> > Note that DW HDMI has decimation support which converts 444 to 422. This
> > is
> > part of CSC unit.
> 
> This works as it should (after a patch to disable color conversion for 444
> to 422), 

Yeah, I noticed that too, I plan to send a patch for that soon.

> the issue I see is that the format negotiation code will currently
> favor 444 to 422 decimation over using 444 output.
> Note: 422 will not be selected over 444 currently in case sink report deep
> color support due to drm edid parsing code following HDMI 1.3 spec, see
> [1].
> 
> [1]
> https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/drm_edid.c#L4
> 801-L4806
> > Side note: CSC unit is optional feature of DW-HDMI and presence is
> > indicated by config register. However, it seems that CSC support is
> > broken in DW HDMI controller on 40nm Allwinner SoCs. If it is enabled, TV
> > loses signal. I have to investigate if only CSC is broken or decimation
> > also don't work.> 

Scratch above, DW HDMI CSC unit works ok on Allwinner SoCs, I just forgot to 
enable CSC clock.

> >> Maybe dw-hdmi can call a dw-hdmi glue driver callback to get the
> >> preferred
> >> output format order?
> >> 
> >> On a side note but related issue, the dw-hdmi format negotiation code
> >> should probably also filter modes on tmds rate, something like [1].
> >> It is needed to filter out deep color modes that is not supported by the
> >> sink or hdmi spec.
> > 
> > Ah, you mean on TMDS rates supported by the sink. Could this avoid Samsung
> > deep color issues? If so, we don't need blacklist then.
> 
> I do not think so, the initial issue was reported with intel graphics but
> looking at the edid and comparing to the manual of supported modes they do
> not fully match. See manual info at [2] and edid when UHD mode is off at
> [3] and when on at [4].

Which part doesn't match? I don't see any issue.

Best regards,
Jernej

> 
> [2]
> https://gitlab.freedesktop.org/drm/intel/uploads/36630c8a727bf8c66a53fd7470
> c88383/MU7000_manual_-_UHD_colour_modes.PNG [3] http://ix.io/1H25
> [4] http://ix.io/1H2e
> 
> > Best regards,
> > Jernej
> > 
> >> [1]
> >> https://github.com/Kwiboo/linux-rockchip/commit/fc3df6903384e764ab6ac5987
> >> 9c
> >> 489cbef55fcbe
> >> 
> >> Best regards,
> >> Jonas
> >> 
> >>> Best regards,
> >>> Jernej
> >>> 
> >>>> +	}
> >>>> +
> >>>> +	/*
> >>>> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
> >>>> +	 * if supported. In any case the default RGB888 format is added
> >>>> +	 */
> >>>> +
> >>>> +	if (max_bpc >= 16 && info->bpc == 16) {
> >>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> >>>> +
> >>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> >>>> +	}
> >>>> +
> >>>> +	if (max_bpc >= 12 && info->bpc >= 12) {
> >>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> >>>> +			output_fmts[i++] =
> > 
> > MEDIA_BUS_FMT_UYVY12_1X24;
> > 
> >>>> +
> >>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >>>> +
> >>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >>>> +	}
> >>>> +
> >>>> +	if (max_bpc >= 10 && info->bpc >= 10) {
> >>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> >>>> +			output_fmts[i++] =
> > 
> > MEDIA_BUS_FMT_UYVY10_1X20;
> > 
> >>>> +
> >>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >>>> +
> >>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >>>> +	}
> >>>> +
> >>>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> >>>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >>>> +
> >>>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> >>>> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >>>> +
> >>>> +	/* Default 8bit RGB fallback */
> >>>> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >>>> +
> >>>> +	*num_output_fmts = i;
> >>>> +
> >>>> +	return output_fmts;
> >>>> +}
> >>>> +
> >>>> +/*
> >>>> + * Possible input formats :
> >>>> + * - MEDIA_BUS_FMT_RGB888_1X24
> >>>> + * - MEDIA_BUS_FMT_YUV8_1X24
> >>>> + * - MEDIA_BUS_FMT_UYVY8_1X16
> >>>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
> >>>> + * - MEDIA_BUS_FMT_RGB101010_1X30
> >>>> + * - MEDIA_BUS_FMT_YUV10_1X30
> >>>> + * - MEDIA_BUS_FMT_UYVY10_1X20
> >>>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
> >>>> + * - MEDIA_BUS_FMT_RGB121212_1X36
> >>>> + * - MEDIA_BUS_FMT_YUV12_1X36
> >>>> + * - MEDIA_BUS_FMT_UYVY12_1X24
> >>>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
> >>>> + * - MEDIA_BUS_FMT_RGB161616_1X48
> >>>> + * - MEDIA_BUS_FMT_YUV16_1X48
> >>>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
> >>>> + */
> >>>> +
> >>>> +/* Can return a maximum of 4 possible input formats for an output
> >>>> format
> >>>> */ +#define MAX_INPUT_SEL_FORMATS	4
> >>>> +
> >>>> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge
> >>>> *bridge, +					struct
> >>> 
> >>> drm_bridge_state *bridge_state,
> >>> 
> >>>> +					struct drm_crtc_state
> >>> 
> >>> *crtc_state,
> >>> 
> >>>> +					struct
> >>> 
> >>> drm_connector_state *conn_state,
> >>> 
> >>>> +					u32 output_fmt,
> >>>> +					unsigned int
> >>> 
> >>> *num_input_fmts)
> >>> 
> >>>> +{
> >>>> +	u32 *input_fmts;
> >>>> +	int i = 0;
> >>>> +
> >>>> +	*num_input_fmts = 0;
> >>>> +
> >>>> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
> >>>> +			     GFP_KERNEL);
> >>>> +	if (!input_fmts)
> >>>> +		return NULL;
> >>>> +
> >>>> +	switch (output_fmt) {
> >>>> +	/* 8bit */
> >>>> +	case MEDIA_BUS_FMT_RGB888_1X24:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >>>> +		break;
> >>>> +	case MEDIA_BUS_FMT_YUV8_1X24:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >>>> +		break;
> >>>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> >>>> +		break;
> >>>> +
> >>>> +	/* 10bit */
> >>>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> >>>> +		break;
> >>>> +	case MEDIA_BUS_FMT_YUV10_1X30:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >>>> +		break;
> >>>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> >>>> +		break;
> >>>> +
> >>>> +	/* 12bit */
> >>>> +	case MEDIA_BUS_FMT_RGB121212_1X36:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> >>>> +		break;
> >>>> +	case MEDIA_BUS_FMT_YUV12_1X36:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >>>> +		break;
> >>>> +	case MEDIA_BUS_FMT_UYVY12_1X24:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> >>>> +		break;
> >>>> +
> >>>> +	/* 16bit */
> >>>> +	case MEDIA_BUS_FMT_RGB161616_1X48:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> >>>> +		break;
> >>>> +	case MEDIA_BUS_FMT_YUV16_1X48:
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> >>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> >>>> +		break;
> >>>> +
> >>>> +	/* 420 */
> >>>> +	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:
> >>>> +		input_fmts[i++] = output_fmt;
> >>>> +		break;
> >>>> +	}
> >>>> +
> >>>> +	*num_input_fmts = i;
> >>>> +
> >>>> +	if (*num_input_fmts == 0) {
> >>>> +		kfree(input_fmts);
> >>>> +		input_fmts = NULL;
> >>>> +	}
> >>>> +
> >>>> +	return input_fmts;
> >>>> +}
> >>>> +
> >>>> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
> >>>> +				       struct drm_bridge_state
> >>> 
> >>> *bridge_state,
> >>> 
> >>>> +				       struct drm_crtc_state
> >>> 
> >>> *crtc_state,
> >>> 
> >>>> +				       struct drm_connector_state
> >>> 
> >>> *conn_state)
> >>> 
> >>>> +{
> >>>> +	struct dw_hdmi *hdmi = bridge->driver_private;
> >>>> +
> >>>> +	dev_dbg(hdmi->dev, "selected output format %x\n",
> >>>> +			bridge_state->output_bus_cfg.format);
> >>>> +
> >>>> +	hdmi->hdmi_data.enc_out_bus_format =
> >>>> +			bridge_state->output_bus_cfg.format;
> >>>> +
> >>>> +	dev_dbg(hdmi->dev, "selected input format %x\n",
> >>>> +			bridge_state->input_bus_cfg.format);
> >>>> +
> >>>> +	hdmi->hdmi_data.enc_in_bus_format =
> >>>> +			bridge_state->input_bus_cfg.format;
> >>>> +
> >>>> +	return 0;
> >>>> +}
> >>>> +
> >>>> 
> >>>>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
> >>>>  {
> >>>>  
> >>>>  	struct dw_hdmi *hdmi = bridge->driver_private;
> >>>> 
> >>>> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs
> >>>> dw_hdmi_bridge_funcs = { .atomic_reset =
> >>>> drm_atomic_helper_bridge_reset,
> >>>> 
> >>>>  	.attach = dw_hdmi_bridge_attach,
> >>>>  	.detach = dw_hdmi_bridge_detach,
> >>>> 
> >>>> +	.atomic_check = dw_hdmi_bridge_atomic_check,
> >>>> +	.atomic_get_output_bus_fmts =
> >>> 
> >>> dw_hdmi_bridge_atomic_get_output_bus_fmts,
> >>> 
> >>>> +	.atomic_get_input_bus_fmts =
> >>> 
> >>> dw_hdmi_bridge_atomic_get_input_bus_fmts,
> >>> 
> >>>>  	.enable = dw_hdmi_bridge_enable,
> >>>>  	.disable = dw_hdmi_bridge_disable,
> >>>>  	.mode_set = dw_hdmi_bridge_mode_set,
> >>>> 
> >>>> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
> >>>> 
> >>>>  	hdmi->bridge.driver_private = hdmi;
> >>>>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
> >>>> 
> >>>> +
> >>>> 
> >>>>  #ifdef CONFIG_OF
> >>>>  
> >>>>  	hdmi->bridge.of_node = pdev->dev.of_node;
> >>>>  
> >>>>  #endif





_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-29  7:42   ` Jernej Škrabec
  2020-02-29 10:09     ` Jonas Karlman
@ 2020-03-02  8:04     ` Neil Armstrong
  1 sibling, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02  8:04 UTC (permalink / raw)
  To: Jernej Škrabec, a.hajda, Laurent.pinchart, jonas, boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel

On 29/02/2020 08:42, Jernej Škrabec wrote:
> Hi Neil!
> 
> Dne četrtek, 06. februar 2020 ob 20:18:27 CET je Neil Armstrong napisal(a):
>> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
>> the possible output and input formats for the current mode and monitor,
>> and use the negotiated formats in a basic atomic_check callback.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
>>  1 file changed, 268 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
>> fec4a4bcd1fe..15048ad694bc 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
>> struct drm_display_mode *mode)
>> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
>>  	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)
>>  		hdmi->hdmi_data.enc_in_bus_format =
>>  			hdmi->plat_data->input_bus_format;
>> -	else
>> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
>>  		hdmi->hdmi_data.enc_in_bus_format = 
> MEDIA_BUS_FMT_RGB888_1X24;
>>
>>  	/* TOFIX: Get input encoding from plat data or fallback to none */
>> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct
>> drm_display_mode *mode) 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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
>> +		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;
>> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs
>> dw_hdmi_connector_helper_funcs = .atomic_check =
>> dw_hdmi_connector_atomic_check,
>>  };
>>
>> +/*
>> + * Possible output formats :
>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
>> + * - MEDIA_BUS_FMT_YUV16_1X48,
>> + * - MEDIA_BUS_FMT_RGB161616_1X48,
>> + * - MEDIA_BUS_FMT_UYVY12_1X24,
>> + * - MEDIA_BUS_FMT_YUV12_1X36,
>> + * - MEDIA_BUS_FMT_RGB121212_1X36,
>> + * - MEDIA_BUS_FMT_UYVY10_1X20,
>> + * - MEDIA_BUS_FMT_YUV10_1X30,
>> + * - MEDIA_BUS_FMT_RGB101010_1X30,
>> + * - MEDIA_BUS_FMT_UYVY8_1X16,
>> + * - MEDIA_BUS_FMT_YUV8_1X24,
>> + * - MEDIA_BUS_FMT_RGB888_1X24,
>> + */
>> +
>> +/* Can return a maximum of 12 possible output formats for a mode/connector
>> */ +#define MAX_OUTPUT_SEL_FORMATS	12
>> +
>> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge
>> *bridge, +					struct 
> drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state 
> *crtc_state,
>> +					struct 
> drm_connector_state *conn_state,
>> +					unsigned int 
> *num_output_fmts)
>> +{
>> +	struct drm_connector *conn = conn_state->connector;
>> +	struct drm_display_info *info = &conn->display_info;
>> +	struct drm_display_mode *mode = &crtc_state->mode;
>> +	u8 max_bpc = conn_state->max_requested_bpc;
>> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
>> +			     (info->color_formats & 
> DRM_COLOR_FORMAT_YCRCB420);
>> +	u32 *output_fmts;
>> +	int i = 0;
>> +
>> +	*num_output_fmts = 0;
>> +
>> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
>> +			      GFP_KERNEL);
>> +	if (!output_fmts)
>> +		return NULL;
>> +
>> +	/*
>> +	 * If the current mode enforces 4:2:0, force the output but format
>> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
>> +	 */
>> +	if (conn->ycbcr_420_allowed &&
>> +	    (drm_mode_is_420_only(info, mode) ||
>> +	     ())) {
>> +
>> +		/* Order bus formats from 16bit to 8bit if supported */
>> +		if (max_bpc >= 16 && info->bpc == 16 &&
>> +		    (info->hdmi.y420_dc_modes & 
> DRM_EDID_YCBCR420_DC_48))
>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYYVYY16_0_5X48;
>> +
>> +		if (max_bpc >= 12 && info->bpc >= 12 &&
>> +		    (info->hdmi.y420_dc_modes & 
> DRM_EDID_YCBCR420_DC_36))
>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYYVYY12_0_5X36;
>> +
>> +		if (max_bpc >= 10 && info->bpc >= 10 &&
>> +		    (info->hdmi.y420_dc_modes & 
> DRM_EDID_YCBCR420_DC_30))
>> +			output_fmts[i++] = 
> MEDIA_BUS_FMT_UYYVYY10_0_5X30;
>> +
>> +		/* Default 8bit fallback */
>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
>> +
>> +		*num_output_fmts = i;
>> +
>> +		return output_fmts;
> 
> Driver shouldn't return just yet for case "is_hdmi2_sink && 
> drm_mode_is_420_also(info, mode)", because monitor/TV also supports YCbCr 
> 4:4:4 in that case. IMO YCbCr 4:4:4 should be even prefered. What do you 
> think?

The code is right.

If drm_mode_is_420_only(info, mode), then the selected mode is 4:2:0 only, so only
4:2:0 bus formats will be allowed in this case.

In this 4:2:0 only mode, the TV only support 4:2:0 4k60 modes and doesn't support
SCDC and high tmds frequency pattern & co.

Neil

> 
> Best regards,
> Jernej
> 
>> +	}
>> +
>> +	/*
>> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
>> +	 * if supported. In any case the default RGB888 format is added
>> +	 */
>> +
>> +	if (max_bpc >= 16 && info->bpc == 16) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +	}
>> +
>> +	if (max_bpc >= 12 && info->bpc >= 12) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +	}
>> +
>> +	if (max_bpc >= 10 && info->bpc >= 10) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +	}
>> +
>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +
>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +
>> +	/* Default 8bit RGB fallback */
>> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +
>> +	*num_output_fmts = i;
>> +
>> +	return output_fmts;
>> +}
>> +
>> +/*
>> + * Possible input formats :
>> + * - MEDIA_BUS_FMT_RGB888_1X24
>> + * - MEDIA_BUS_FMT_YUV8_1X24
>> + * - MEDIA_BUS_FMT_UYVY8_1X16
>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
>> + * - MEDIA_BUS_FMT_RGB101010_1X30
>> + * - MEDIA_BUS_FMT_YUV10_1X30
>> + * - MEDIA_BUS_FMT_UYVY10_1X20
>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
>> + * - MEDIA_BUS_FMT_RGB121212_1X36
>> + * - MEDIA_BUS_FMT_YUV12_1X36
>> + * - MEDIA_BUS_FMT_UYVY12_1X24
>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
>> + * - MEDIA_BUS_FMT_RGB161616_1X48
>> + * - MEDIA_BUS_FMT_YUV16_1X48
>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
>> + */
>> +
>> +/* Can return a maximum of 4 possible input formats for an output format */
>> +#define MAX_INPUT_SEL_FORMATS	4
>> +
>> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge
>> *bridge, +					struct 
> drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state 
> *crtc_state,
>> +					struct 
> drm_connector_state *conn_state,
>> +					u32 output_fmt,
>> +					unsigned int 
> *num_input_fmts)
>> +{
>> +	u32 *input_fmts;
>> +	int i = 0;
>> +
>> +	*num_input_fmts = 0;
>> +
>> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
>> +			     GFP_KERNEL);
>> +	if (!input_fmts)
>> +		return NULL;
>> +
>> +	switch (output_fmt) {
>> +	/* 8bit */
>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV8_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +
>> +	/* 10bit */
>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV10_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +
>> +	/* 12bit */
>> +	case MEDIA_BUS_FMT_RGB121212_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV12_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY12_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +
>> +	/* 16bit */
>> +	case MEDIA_BUS_FMT_RGB161616_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV16_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		break;
>> +
>> +	/* 420 */
>> +	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:
>> +		input_fmts[i++] = output_fmt;
>> +		break;
>> +	}
>> +
>> +	*num_input_fmts = i;
>> +
>> +	if (*num_input_fmts == 0) {
>> +		kfree(input_fmts);
>> +		input_fmts = NULL;
>> +	}
>> +
>> +	return input_fmts;
>> +}
>> +
>> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
>> +				       struct drm_bridge_state 
> *bridge_state,
>> +				       struct drm_crtc_state 
> *crtc_state,
>> +				       struct drm_connector_state 
> *conn_state)
>> +{
>> +	struct dw_hdmi *hdmi = bridge->driver_private;
>> +
>> +	dev_dbg(hdmi->dev, "selected output format %x\n",
>> +			bridge_state->output_bus_cfg.format);
>> +
>> +	hdmi->hdmi_data.enc_out_bus_format =
>> +			bridge_state->output_bus_cfg.format;
>> +
>> +	dev_dbg(hdmi->dev, "selected input format %x\n",
>> +			bridge_state->input_bus_cfg.format);
>> +
>> +	hdmi->hdmi_data.enc_in_bus_format =
>> +			bridge_state->input_bus_cfg.format;
>> +
>> +	return 0;
>> +}
>> +
>>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>>  {
>>  	struct dw_hdmi *hdmi = bridge->driver_private;
>> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs
>> dw_hdmi_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset,
>>  	.attach = dw_hdmi_bridge_attach,
>>  	.detach = dw_hdmi_bridge_detach,
>> +	.atomic_check = dw_hdmi_bridge_atomic_check,
>> +	.atomic_get_output_bus_fmts = 
> dw_hdmi_bridge_atomic_get_output_bus_fmts,
>> +	.atomic_get_input_bus_fmts = 
> dw_hdmi_bridge_atomic_get_input_bus_fmts,
>>  	.enable = dw_hdmi_bridge_enable,
>>  	.disable = dw_hdmi_bridge_disable,
>>  	.mode_set = dw_hdmi_bridge_mode_set,
>> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>
>>  	hdmi->bridge.driver_private = hdmi;
>>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
>> +
>>  #ifdef CONFIG_OF
>>  	hdmi->bridge.of_node = pdev->dev.of_node;
>>  #endif
> 
> 
> 
> 


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-29 10:09     ` Jonas Karlman
  2020-02-29 11:07       ` Jernej Škrabec
@ 2020-03-02  8:08       ` Neil Armstrong
  1 sibling, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02  8:08 UTC (permalink / raw)
  To: Jonas Karlman, Jernej Škrabec, a.hajda, Laurent.pinchart,
	boris.brezillon
  Cc: linux-amlogic, linux-kernel, dri-devel

On 29/02/2020 11:09, Jonas Karlman wrote:
> Hi Jernej,
> 
> On 2020-02-29 08:42, Jernej Škrabec wrote:
>> Hi Neil!
>>
>> Dne četrtek, 06. februar 2020 ob 20:18:27 CET je Neil Armstrong napisal(a):
>>> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
>>> the possible output and input formats for the current mode and monitor,
>>> and use the negotiated formats in a basic atomic_check callback.
>>>
>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>> ---
>>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
>>>  1 file changed, 268 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
>>> fec4a4bcd1fe..15048ad694bc 100644
>>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
>>> struct drm_display_mode *mode)
>>> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
>>>  	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)
>>>  		hdmi->hdmi_data.enc_in_bus_format =
>>>  			hdmi->plat_data->input_bus_format;
>>> -	else
>>> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
>>>  		hdmi->hdmi_data.enc_in_bus_format = 
>> MEDIA_BUS_FMT_RGB888_1X24;
>>>
>>>  	/* TOFIX: Get input encoding from plat data or fallback to none */
>>> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct
>>> drm_display_mode *mode) 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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
>>> +		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;
>>> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs
>>> dw_hdmi_connector_helper_funcs = .atomic_check =
>>> dw_hdmi_connector_atomic_check,
>>>  };
>>>
>>> +/*
>>> + * Possible output formats :
>>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
>>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
>>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
>>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
>>> + * - MEDIA_BUS_FMT_YUV16_1X48,
>>> + * - MEDIA_BUS_FMT_RGB161616_1X48,
>>> + * - MEDIA_BUS_FMT_UYVY12_1X24,
>>> + * - MEDIA_BUS_FMT_YUV12_1X36,
>>> + * - MEDIA_BUS_FMT_RGB121212_1X36,
>>> + * - MEDIA_BUS_FMT_UYVY10_1X20,
>>> + * - MEDIA_BUS_FMT_YUV10_1X30,
>>> + * - MEDIA_BUS_FMT_RGB101010_1X30,
>>> + * - MEDIA_BUS_FMT_UYVY8_1X16,
>>> + * - MEDIA_BUS_FMT_YUV8_1X24,
>>> + * - MEDIA_BUS_FMT_RGB888_1X24,
>>> + */
>>> +
>>> +/* Can return a maximum of 12 possible output formats for a mode/connector
>>> */ +#define MAX_OUTPUT_SEL_FORMATS	12
>>> +
>>> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge
>>> *bridge, +					struct 
>> drm_bridge_state *bridge_state,
>>> +					struct drm_crtc_state 
>> *crtc_state,
>>> +					struct 
>> drm_connector_state *conn_state,
>>> +					unsigned int 
>> *num_output_fmts)
>>> +{
>>> +	struct drm_connector *conn = conn_state->connector;
>>> +	struct drm_display_info *info = &conn->display_info;
>>> +	struct drm_display_mode *mode = &crtc_state->mode;
>>> +	u8 max_bpc = conn_state->max_requested_bpc;
>>> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
>>> +			     (info->color_formats & 
>> DRM_COLOR_FORMAT_YCRCB420);
>>> +	u32 *output_fmts;
>>> +	int i = 0;
>>> +
>>> +	*num_output_fmts = 0;
>>> +
>>> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
>>> +			      GFP_KERNEL);
>>> +	if (!output_fmts)
>>> +		return NULL;
>>> +
>>> +	/*
>>> +	 * If the current mode enforces 4:2:0, force the output but format
>>> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
>>> +	 */
>>> +	if (conn->ycbcr_420_allowed &&
>>> +	    (drm_mode_is_420_only(info, mode) ||
>>> +	     ())) {
>>> +
>>> +		/* Order bus formats from 16bit to 8bit if supported */
>>> +		if (max_bpc >= 16 && info->bpc == 16 &&
>>> +		    (info->hdmi.y420_dc_modes & 
>> DRM_EDID_YCBCR420_DC_48))
>>> +			output_fmts[i++] = 
>> MEDIA_BUS_FMT_UYYVYY16_0_5X48;
>>> +
>>> +		if (max_bpc >= 12 && info->bpc >= 12 &&
>>> +		    (info->hdmi.y420_dc_modes & 
>> DRM_EDID_YCBCR420_DC_36))
>>> +			output_fmts[i++] = 
>> MEDIA_BUS_FMT_UYYVYY12_0_5X36;
>>> +
>>> +		if (max_bpc >= 10 && info->bpc >= 10 &&
>>> +		    (info->hdmi.y420_dc_modes & 
>> DRM_EDID_YCBCR420_DC_30))
>>> +			output_fmts[i++] = 
>> MEDIA_BUS_FMT_UYYVYY10_0_5X30;
>>> +
>>> +		/* Default 8bit fallback */
>>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
>>> +
>>> +		*num_output_fmts = i;
>>> +
>>> +		return output_fmts;
>>
>> Driver shouldn't return just yet for case "is_hdmi2_sink && 
>> drm_mode_is_420_also(info, mode)", because monitor/TV also supports YCbCr 
>> 4:4:4 in that case. IMO YCbCr 4:4:4 should be even prefered. What do you 
>> think?
> 
> I think we need to have some way for controller driver and userspace to control what
> hdmi output format gets selected. I know for a fact that some Samsung TV have issues
> with 444 YCbCr modes at 4k 50/60hz but have no problems with 420 modes.
> The Samsung TV edid lie and/or the TV is not fully following HDMI specs.

In this case this must be handled in the EDID quirks, by disabling SCDC & co for this TV.

> 
> From a personal and mediaplayer userspace perspective I would like to prefer
> 420/444 YCbCr mode as soon as any yuv drm plane is active and rgb 444 anytime else.
> 
> On Rockchip SoCs the display controller cannot output yuv422 to dw-hdmi block,
> the optimal output format selection in such case should put yuv422 last.

I think 4:2:2 should be moved after 4:4:4 indeed, but on another side, 10bit cannot be
done in 4k60 4:4:4, so only 4:2:2 is possible when the tv is not 4:2:0 capable.

> 
> Maybe dw-hdmi can call a dw-hdmi glue driver callback to get the preferred output format order?

This seems complex to handle...

> 
> On a side note but related issue, the dw-hdmi format negotiation code should 
> probably also filter modes on tmds rate, something like [1].
> It is needed to filter out deep color modes that is not supported by the sink or hdmi spec.

Indeed.

> 
> [1] https://github.com/Kwiboo/linux-rockchip/commit/fc3df6903384e764ab6ac59879c489cbef55fcbe
> 
> Best regards,
> Jonas

Neil

> 
>>
>> Best regards,
>> Jernej
>>
>>> +	}
>>> +
>>> +	/*
>>> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
>>> +	 * if supported. In any case the default RGB888 format is added
>>> +	 */
>>> +
>>> +	if (max_bpc >= 16 && info->bpc == 16) {
>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>>> +
>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>>> +	}
>>> +
>>> +	if (max_bpc >= 12 && info->bpc >= 12) {
>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>>> +
>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>> +
>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>> +	}
>>> +
>>> +	if (max_bpc >= 10 && info->bpc >= 10) {
>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>>> +
>>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>> +
>>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>> +	}
>>> +
>>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>> +
>>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>>> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>> +
>>> +	/* Default 8bit RGB fallback */
>>> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>> +
>>> +	*num_output_fmts = i;
>>> +
>>> +	return output_fmts;
>>> +}
>>> +
>>> +/*
>>> + * Possible input formats :
>>> + * - MEDIA_BUS_FMT_RGB888_1X24
>>> + * - MEDIA_BUS_FMT_YUV8_1X24
>>> + * - MEDIA_BUS_FMT_UYVY8_1X16
>>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
>>> + * - MEDIA_BUS_FMT_RGB101010_1X30
>>> + * - MEDIA_BUS_FMT_YUV10_1X30
>>> + * - MEDIA_BUS_FMT_UYVY10_1X20
>>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
>>> + * - MEDIA_BUS_FMT_RGB121212_1X36
>>> + * - MEDIA_BUS_FMT_YUV12_1X36
>>> + * - MEDIA_BUS_FMT_UYVY12_1X24
>>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
>>> + * - MEDIA_BUS_FMT_RGB161616_1X48
>>> + * - MEDIA_BUS_FMT_YUV16_1X48
>>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
>>> + */
>>> +
>>> +/* Can return a maximum of 4 possible input formats for an output format */
>>> +#define MAX_INPUT_SEL_FORMATS	4
>>> +
>>> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge
>>> *bridge, +					struct 
>> drm_bridge_state *bridge_state,
>>> +					struct drm_crtc_state 
>> *crtc_state,
>>> +					struct 
>> drm_connector_state *conn_state,
>>> +					u32 output_fmt,
>>> +					unsigned int 
>> *num_input_fmts)
>>> +{
>>> +	u32 *input_fmts;
>>> +	int i = 0;
>>> +
>>> +	*num_input_fmts = 0;
>>> +
>>> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
>>> +			     GFP_KERNEL);
>>> +	if (!input_fmts)
>>> +		return NULL;
>>> +
>>> +	switch (output_fmt) {
>>> +	/* 8bit */
>>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>> +		break;
>>> +	case MEDIA_BUS_FMT_YUV8_1X24:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>> +		break;
>>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>>> +		break;
>>> +
>>> +	/* 10bit */
>>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>>> +		break;
>>> +	case MEDIA_BUS_FMT_YUV10_1X30:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>> +		break;
>>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>>> +		break;
>>> +
>>> +	/* 12bit */
>>> +	case MEDIA_BUS_FMT_RGB121212_1X36:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>>> +		break;
>>> +	case MEDIA_BUS_FMT_YUV12_1X36:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>> +		break;
>>> +	case MEDIA_BUS_FMT_UYVY12_1X24:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>>> +		break;
>>> +
>>> +	/* 16bit */
>>> +	case MEDIA_BUS_FMT_RGB161616_1X48:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>>> +		break;
>>> +	case MEDIA_BUS_FMT_YUV16_1X48:
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>>> +		break;
>>> +
>>> +	/* 420 */
>>> +	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:
>>> +		input_fmts[i++] = output_fmt;
>>> +		break;
>>> +	}
>>> +
>>> +	*num_input_fmts = i;
>>> +
>>> +	if (*num_input_fmts == 0) {
>>> +		kfree(input_fmts);
>>> +		input_fmts = NULL;
>>> +	}
>>> +
>>> +	return input_fmts;
>>> +}
>>> +
>>> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
>>> +				       struct drm_bridge_state 
>> *bridge_state,
>>> +				       struct drm_crtc_state 
>> *crtc_state,
>>> +				       struct drm_connector_state 
>> *conn_state)
>>> +{
>>> +	struct dw_hdmi *hdmi = bridge->driver_private;
>>> +
>>> +	dev_dbg(hdmi->dev, "selected output format %x\n",
>>> +			bridge_state->output_bus_cfg.format);
>>> +
>>> +	hdmi->hdmi_data.enc_out_bus_format =
>>> +			bridge_state->output_bus_cfg.format;
>>> +
>>> +	dev_dbg(hdmi->dev, "selected input format %x\n",
>>> +			bridge_state->input_bus_cfg.format);
>>> +
>>> +	hdmi->hdmi_data.enc_in_bus_format =
>>> +			bridge_state->input_bus_cfg.format;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>>>  {
>>>  	struct dw_hdmi *hdmi = bridge->driver_private;
>>> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs
>>> dw_hdmi_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset,
>>>  	.attach = dw_hdmi_bridge_attach,
>>>  	.detach = dw_hdmi_bridge_detach,
>>> +	.atomic_check = dw_hdmi_bridge_atomic_check,
>>> +	.atomic_get_output_bus_fmts = 
>> dw_hdmi_bridge_atomic_get_output_bus_fmts,
>>> +	.atomic_get_input_bus_fmts = 
>> dw_hdmi_bridge_atomic_get_input_bus_fmts,
>>>  	.enable = dw_hdmi_bridge_enable,
>>>  	.disable = dw_hdmi_bridge_disable,
>>>  	.mode_set = dw_hdmi_bridge_mode_set,
>>> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>>
>>>  	hdmi->bridge.driver_private = hdmi;
>>>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
>>> +
>>>  #ifdef CONFIG_OF
>>>  	hdmi->bridge.of_node = pdev->dev.of_node;
>>>  #endif
>>
>>
>>
>>


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
  2020-02-06 19:18 ` [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color Neil Armstrong
@ 2020-03-02  9:05   ` Laurent Pinchart
  2020-03-02  9:21     ` Neil Armstrong
  2020-03-02 15:54     ` Neil Armstrong
  0 siblings, 2 replies; 41+ messages in thread
From: Laurent Pinchart @ 2020-03-02  9:05 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

Hi Neil and Jonas,

Thank you for the patch.

On Thu, Feb 06, 2020 at 08:18:24PM +0100, Neil Armstrong wrote:
> From: Jonas Karlman <jonas@kwiboo.se>
> 
> Configure the correct mtmdsclock for deep colors to prepare support
> for 10, 12 & 16bit output.
> 
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 67fca439bbfb..9e0927d22db6 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -1818,9 +1818,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
>  
>  	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);

Nitpicking a bit, I would change

-	vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
+	vmode->mpixelclock = mode->clock * 1000;

above, and here add

	vmode->mtmdsclock = vmode->mpixelclock;

to keep all mtmdsclock calculation in a single place.

> +	if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
> +		switch (hdmi_bus_fmt_color_depth(
> +				hdmi->hdmi_data.enc_out_bus_format)) {
> +		case 16:
> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 2;

Both mpixelclock and mtmdsclock are unsigned int. Is the cast to u64
needed ?

On a separate but related note, what does the 'm' in tmdsclock stand for
? It seems to originate from the 'm' prefix for mpixelclock, which has
been there from the start. Unless there's a good reason for the prefix,
renaming mtmdsclock to tmds_clock (and handling the other fields in the
hdmi_vmode structure similarly) would increase clarity I think.

> +			break;
> +		case 12:
> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2;
> +			break;
> +		case 10:
> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4;
> +			break;
> +		}
> +	}
> +
>  	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
>  		vmode->mtmdsclock /= 2;
>  
> +	dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);

s/tmdsclk/tmdsclock/ to match the field name ?

> +
>  	/* Set up HDMI_FC_INVIDCONF */
>  	inv_val = (hdmi->hdmi_data.hdcp_enable ||
>  		   (dw_hdmi_support_scdc(hdmi) &&

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
  2020-02-21  8:50     ` Neil Armstrong
@ 2020-03-02  9:18       ` Laurent Pinchart
  2020-03-02 15:55         ` Neil Armstrong
  0 siblings, 1 reply; 41+ messages in thread
From: Laurent Pinchart @ 2020-03-02  9:18 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Jernej Škrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, Daniel Vetter, linux-amlogic

Hi Neil and Jonas,

(CC'ing Daniel for a framework question)

Thank you for the patch.

On Fri, Feb 21, 2020 at 09:50:18AM +0100, Neil Armstrong wrote:
> On 17/02/2020 07:38, Jernej Škrabec wrote:
> > Dne četrtek, 06. februar 2020 ob 20:18:25 CET je Neil Armstrong napisal(a):
> >> From: Jonas Karlman <jonas@kwiboo.se>
> >>
> >> Add the max_bpc property to the dw-hdmi connector to prepare support
> >> for 10, 12 & 16bit output support.
> >>
> >> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
> >> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> >> ---
> >>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
> >>  1 file changed, 4 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
> >> 9e0927d22db6..051001f77dd4 100644
> >> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> @@ -2406,6 +2406,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge
> >> *bridge) DRM_MODE_CONNECTOR_HDMIA,
> >>  				    hdmi->ddc);
> >>
> >> +	drm_atomic_helper_connector_reset(connector);
> > 
> > Why is this reset needed?
> 
> I assume it's to allocate a new connector state to attach a the bpc propery.
> 
> But indeed, this helper is never used here, but only as callback to the drm_connector_funcs->reset.
> 
> But, amdgpu calls :
> 	/*
> 	 * Some of the properties below require access to state, like bpc.
> 	 * Allocate some default initial connector state with our reset helper.
> 	 */
> 	if (aconnector->base.funcs->reset)
> 		aconnector->base.funcs->reset(&aconnector->base);
> 
> which is the same.

A comment would be useful:

	/*
	 * drm_connector_attach_max_bpc_property() requires the
	 * connector to have a state.
	 */
	drm_atomic_helper_connector_reset(connector);

	drm_connector_attach_max_bpc_property(connector, 8, 16);

I don't like this much though, it feels like the initial reset performed
by drm_mode_config_reset() should set default values for all state
members that are related to properties. Daniel, what's the rationale
behind the current implementation ?

This is a DRM core issue that shouldn't block this patch though, so

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> >> +
> >> +	drm_connector_attach_max_bpc_property(connector, 8, 16);
> >> +
> >>  	if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
> >>  		drm_object_attach_property(&connector->base,
> >>  			connector->dev-
> >> mode_config.hdr_output_metadata_property, 0);

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
  2020-03-02  9:05   ` Laurent Pinchart
@ 2020-03-02  9:21     ` Neil Armstrong
  2020-03-02 15:54     ` Neil Armstrong
  1 sibling, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02  9:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

On 02/03/2020 10:05, Laurent Pinchart wrote:
> Hi Neil and Jonas,
> 
> Thank you for the patch.
> 
> On Thu, Feb 06, 2020 at 08:18:24PM +0100, Neil Armstrong wrote:
>> From: Jonas Karlman <jonas@kwiboo.se>
>>
>> Configure the correct mtmdsclock for deep colors to prepare support
>> for 10, 12 & 16bit output.
>>
>> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
>>  1 file changed, 17 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> index 67fca439bbfb..9e0927d22db6 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -1818,9 +1818,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
>>  
>>  	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
> 
> Nitpicking a bit, I would change
> 
> -	vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
> +	vmode->mpixelclock = mode->clock * 1000;
> 
> above, and here add
> 
> 	vmode->mtmdsclock = vmode->mpixelclock;
> 
> to keep all mtmdsclock calculation in a single place.
> 
>> +	if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
>> +		switch (hdmi_bus_fmt_color_depth(
>> +				hdmi->hdmi_data.enc_out_bus_format)) {
>> +		case 16:
>> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 2;
> 
> Both mpixelclock and mtmdsclock are unsigned int. Is the cast to u64
> needed ?

Good question, should probably be removed.

> 
> On a separate but related note, what does the 'm' in tmdsclock stand for
> ? It seems to originate from the 'm' prefix for mpixelclock, which has
> been there from the start. Unless there's a good reason for the prefix,
> renaming mtmdsclock to tmds_clock (and handling the other fields in the
> hdmi_vmode structure similarly) would increase clarity I think.

The mode->clock is is KHz, thus it seems the m was added to express it's in Hz,
so yeah we could drop the m in tmdsclock.

> 
>> +			break;
>> +		case 12:
>> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2;
>> +			break;
>> +		case 10:
>> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4;
>> +			break;
>> +		}
>> +	}
>> +
>>  	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
>>  		vmode->mtmdsclock /= 2;
>>  
>> +	dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);
> 
> s/tmdsclk/tmdsclock/ to match the field name ?

yep

> 
>> +
>>  	/* Set up HDMI_FC_INVIDCONF */
>>  	inv_val = (hdmi->hdmi_data.hdcp_enable ||
>>  		   (dw_hdmi_support_scdc(hdmi) &&
> 

Neil

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
  2020-02-06 19:18 ` [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation Neil Armstrong
  2020-02-07 10:57   ` Boris Brezillon
@ 2020-03-02  9:56   ` Laurent Pinchart
  2020-03-02 15:55     ` Neil Armstrong
  1 sibling, 1 reply; 41+ messages in thread
From: Laurent Pinchart @ 2020-03-02  9:56 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

Hi Neil,

Thank you for the patch.

On Thu, Feb 06, 2020 at 08:18:26PM +0100, Neil Armstrong wrote:
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

How about adding a commit message ?

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 051001f77dd4..fec4a4bcd1fe 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2494,6 +2494,9 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
>  }
>  
>  static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
> +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset = drm_atomic_helper_bridge_reset,
>  	.attach = dw_hdmi_bridge_attach,
>  	.detach = dw_hdmi_bridge_detach,
>  	.enable = dw_hdmi_bridge_enable,

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
  2020-02-06 19:18 ` [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const Neil Armstrong
  2020-02-07 13:39   ` Neil Armstrong
@ 2020-03-02  9:59   ` Laurent Pinchart
  1 sibling, 0 replies; 41+ messages in thread
From: Laurent Pinchart @ 2020-03-02  9:59 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

Hi Neil,

Thank you for the patch.

On Thu, Feb 06, 2020 at 08:18:29PM +0100, Neil Armstrong wrote:
> Before switching to bridge funcs, make sure drm_display_mode is passed
> as const to the venc functions.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  drivers/gpu/drm/meson/meson_venc.c | 2 +-
>  drivers/gpu/drm/meson/meson_venc.h | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
> index 4efd7864d5bf..a9ab78970bfe 100644
> --- a/drivers/gpu/drm/meson/meson_venc.c
> +++ b/drivers/gpu/drm/meson/meson_venc.c
> @@ -946,7 +946,7 @@ 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,
> -			      struct drm_display_mode *mode)
> +			      const struct drm_display_mode *mode)
>  {
>  	union meson_hdmi_venc_mode *vmode = NULL;
>  	union meson_hdmi_venc_mode vmode_dmt;
> diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
> index 576768bdd08d..1abdcbdf51c0 100644
> --- a/drivers/gpu/drm/meson/meson_venc.h
> +++ b/drivers/gpu/drm/meson/meson_venc.h
> @@ -60,7 +60,7 @@ 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,
> -			      struct drm_display_mode *mode);
> +			      const struct drm_display_mode *mode);
>  unsigned int meson_venci_get_field(struct meson_drm *priv);
>  
>  void meson_venc_enable_vsync(struct meson_drm *priv);

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2020-02-06 19:18 ` [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
  2020-02-07 13:38   ` Neil Armstrong
@ 2020-03-02 10:03   ` Laurent Pinchart
  2020-03-02 15:58     ` Neil Armstrong
  1 sibling, 1 reply; 41+ messages in thread
From: Laurent Pinchart @ 2020-03-02 10:03 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

Hi Neil,

Thank you for the patch.

On Thu, Feb 06, 2020 at 08:18:28PM +0100, Neil Armstrong wrote:
> 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 15048ad694bc..4b35ea1427df 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -3231,6 +3231,12 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  	hdmi->bridge.of_node = pdev->dev.of_node;
>  #endif
>  
> +	if (hdmi->version >= 0x200a)
> +		hdmi->connector.ycbcr_420_allowed =
> +			hdmi->plat_data->ycbcr_420_allowed;
> +	else
> +		hdmi->connector.ycbcr_420_allowed = false;
> +

The hdmi structure being allocated with kzalloc, you don't need the
second branch of the if, but I'm fine if you prefer keeping it. Any
either case,

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

>  	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 9d4d5cc47969..0b34a12c4a1c 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -129,6 +129,7 @@ struct dw_hdmi_plat_data {
>  	unsigned long input_bus_format;
>  	unsigned long input_bus_encoding;
>  	bool use_drm_infoframe;
> +	bool ycbcr_420_allowed;
>  
>  	/* Vendor PHY support */
>  	const struct dw_hdmi_phy_ops *phy_ops;

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18 ` [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation Neil Armstrong
  2020-02-07 11:02   ` Boris Brezillon
  2020-02-29  7:42   ` Jernej Škrabec
@ 2020-03-02 10:18   ` Laurent Pinchart
  2020-03-02 15:57     ` Neil Armstrong
  2 siblings, 1 reply; 41+ messages in thread
From: Laurent Pinchart @ 2020-03-02 10:18 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

Hi Neil,

Thank you for the patch.

On Thu, Feb 06, 2020 at 08:18:27PM +0100, Neil Armstrong wrote:
> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
> the possible output and input formats for the current mode and monitor,
> and use the negotiated formats in a basic atomic_check callback.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
>  1 file changed, 268 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index fec4a4bcd1fe..15048ad694bc 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>  	hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
>  	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)
>  		hdmi->hdmi_data.enc_in_bus_format =
>  			hdmi->plat_data->input_bus_format;
> -	else
> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
>  		hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
>  
>  	/* TOFIX: Get input encoding from plat data or fallback to none */
> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>  	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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
> +		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;
> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
>  	.atomic_check = dw_hdmi_connector_atomic_check,
>  };
>  
> +/*
> + * Possible output formats :
> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
> + * - MEDIA_BUS_FMT_YUV16_1X48,
> + * - MEDIA_BUS_FMT_RGB161616_1X48,
> + * - MEDIA_BUS_FMT_UYVY12_1X24,
> + * - MEDIA_BUS_FMT_YUV12_1X36,
> + * - MEDIA_BUS_FMT_RGB121212_1X36,
> + * - MEDIA_BUS_FMT_UYVY10_1X20,
> + * - MEDIA_BUS_FMT_YUV10_1X30,
> + * - MEDIA_BUS_FMT_RGB101010_1X30,
> + * - MEDIA_BUS_FMT_UYVY8_1X16,
> + * - MEDIA_BUS_FMT_YUV8_1X24,
> + * - MEDIA_BUS_FMT_RGB888_1X24,
> + */

I'd drop this comment as I don't think it brings much, except for a risk
of getting out of sync with the implementation below :-)

> +
> +/* Can return a maximum of 12 possible output formats for a mode/connector */
> +#define MAX_OUTPUT_SEL_FORMATS	12

I count 11 below.

> +
> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					unsigned int *num_output_fmts)
> +{
> +	struct drm_connector *conn = conn_state->connector;
> +	struct drm_display_info *info = &conn->display_info;
> +	struct drm_display_mode *mode = &crtc_state->mode;
> +	u8 max_bpc = conn_state->max_requested_bpc;
> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
> +			     (info->color_formats & DRM_COLOR_FORMAT_YCRCB420);
> +	u32 *output_fmts;
> +	int i = 0;

i is never negative, you can make it an unsigned int.

> +
> +	*num_output_fmts = 0;
> +
> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
> +			      GFP_KERNEL);
> +	if (!output_fmts)
> +		return NULL;
> +
> +	/*
> +	 * If the current mode enforces 4:2:0, force the output but format
> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
> +	 */
> +	if (conn->ycbcr_420_allowed &&
> +	    (drm_mode_is_420_only(info, mode) ||
> +	     (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) {
> +
> +		/* Order bus formats from 16bit to 8bit if supported */
> +		if (max_bpc >= 16 && info->bpc == 16 &&
> +		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48))
> +			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48;
> +
> +		if (max_bpc >= 12 && info->bpc >= 12 &&
> +		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36))
> +			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
> +
> +		if (max_bpc >= 10 && info->bpc >= 10 &&
> +		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30))
> +			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
> +
> +		/* Default 8bit fallback */
> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
> +
> +		*num_output_fmts = i;
> +
> +		return output_fmts;
> +	}
> +
> +	/*
> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
> +	 * if supported. In any case the default RGB888 format is added
> +	 */
> +
> +	if (max_bpc >= 16 && info->bpc == 16) {
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +
> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +	}
> +
> +	if (max_bpc >= 12 && info->bpc >= 12) {
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +
> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +	}
> +
> +	if (max_bpc >= 10 && info->bpc >= 10) {
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +
> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +
> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +	}
> +
> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +
> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +
> +	/* Default 8bit RGB fallback */
> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +
> +	*num_output_fmts = i;
> +
> +	return output_fmts;
> +}
> +
> +/*
> + * Possible input formats :
> + * - MEDIA_BUS_FMT_RGB888_1X24
> + * - MEDIA_BUS_FMT_YUV8_1X24
> + * - MEDIA_BUS_FMT_UYVY8_1X16
> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
> + * - MEDIA_BUS_FMT_RGB101010_1X30
> + * - MEDIA_BUS_FMT_YUV10_1X30
> + * - MEDIA_BUS_FMT_UYVY10_1X20
> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
> + * - MEDIA_BUS_FMT_RGB121212_1X36
> + * - MEDIA_BUS_FMT_YUV12_1X36
> + * - MEDIA_BUS_FMT_UYVY12_1X24
> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
> + * - MEDIA_BUS_FMT_RGB161616_1X48
> + * - MEDIA_BUS_FMT_YUV16_1X48
> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
> + */

Same here.

> +
> +/* Can return a maximum of 4 possible input formats for an output format */
> +#define MAX_INPUT_SEL_FORMATS	4

As Boris pointed out, that should be 3.

> +
> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +	int i = 0;

i is never negative, you can make it an unsigned int.

> +
> +	*num_input_fmts = 0;
> +
> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
> +			     GFP_KERNEL);
> +	if (!input_fmts)
> +		return NULL;
> +
> +	switch (output_fmt) {
> +	/* 8bit */
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		break;
> +	case MEDIA_BUS_FMT_YUV8_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +
> +	/* 10bit */
> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		break;
> +	case MEDIA_BUS_FMT_YUV10_1X30:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
> +		break;
> +
> +	/* 12bit */
> +	case MEDIA_BUS_FMT_RGB121212_1X36:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		break;
> +	case MEDIA_BUS_FMT_YUV12_1X36:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY12_1X24:
> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
> +		break;
> +
> +	/* 16bit */
> +	case MEDIA_BUS_FMT_RGB161616_1X48:
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +		break;
> +	case MEDIA_BUS_FMT_YUV16_1X48:
> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
> +		break;
> +
> +	/* 420 */

s/420/YUV 4:2:0/ ?

> +	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:
> +		input_fmts[i++] = output_fmt;
> +		break;
> +	}
> +
> +	*num_input_fmts = i;
> +
> +	if (*num_input_fmts == 0) {
> +		kfree(input_fmts);
> +		input_fmts = NULL;
> +	}
> +
> +	return input_fmts;
> +}
> +
> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
> +				       struct drm_bridge_state *bridge_state,
> +				       struct drm_crtc_state *crtc_state,
> +				       struct drm_connector_state *conn_state)
> +{
> +	struct dw_hdmi *hdmi = bridge->driver_private;
> +
> +	dev_dbg(hdmi->dev, "selected output format %x\n",

s/%x/0x%04x/

> +			bridge_state->output_bus_cfg.format);

Misalignment ?

> +
> +	hdmi->hdmi_data.enc_out_bus_format =
> +			bridge_state->output_bus_cfg.format;
> +
> +	dev_dbg(hdmi->dev, "selected input format %x\n",
> +			bridge_state->input_bus_cfg.format);

Same here. I would combine both messages:

	dev_dbg(hdmi->dev, "input format: 0x%04x, output format: 0x04x\n",
		bridge_state->input_bus_cfg.format,
		bridge_state->output_bus_cfg.format);

> +
> +	hdmi->hdmi_data.enc_in_bus_format =
> +			bridge_state->input_bus_cfg.format;
> +
> +	return 0;
> +}
> +
>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>  {
>  	struct dw_hdmi *hdmi = bridge->driver_private;
> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>  	.atomic_reset = drm_atomic_helper_bridge_reset,
>  	.attach = dw_hdmi_bridge_attach,
>  	.detach = dw_hdmi_bridge_detach,
> +	.atomic_check = dw_hdmi_bridge_atomic_check,
> +	.atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
> +	.atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
>  	.enable = dw_hdmi_bridge_enable,
>  	.disable = dw_hdmi_bridge_disable,
>  	.mode_set = dw_hdmi_bridge_mode_set,
> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  
>  	hdmi->bridge.driver_private = hdmi;
>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
> +

This seems unrelated.

>  #ifdef CONFIG_OF
>  	hdmi->bridge.of_node = pdev->dev.of_node;
>  #endif

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
  2020-03-02  9:05   ` Laurent Pinchart
  2020-03-02  9:21     ` Neil Armstrong
@ 2020-03-02 15:54     ` Neil Armstrong
  2020-03-02 16:01       ` Laurent Pinchart
  1 sibling, 1 reply; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02 15:54 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

Hi,

On 02/03/2020 10:05, Laurent Pinchart wrote:
> Hi Neil and Jonas,
> 
> Thank you for the patch.
> 
> On Thu, Feb 06, 2020 at 08:18:24PM +0100, Neil Armstrong wrote:
>> From: Jonas Karlman <jonas@kwiboo.se>
>>
>> Configure the correct mtmdsclock for deep colors to prepare support
>> for 10, 12 & 16bit output.
>>
>> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
>>  1 file changed, 17 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> index 67fca439bbfb..9e0927d22db6 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -1818,9 +1818,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
>>  
>>  	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
> 
> Nitpicking a bit, I would change
> 
> -	vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
> +	vmode->mpixelclock = mode->clock * 1000;
> 
> above, and here add
> 
> 	vmode->mtmdsclock = vmode->mpixelclock;
> 
> to keep all mtmdsclock calculation in a single place.
> 
>> +	if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
>> +		switch (hdmi_bus_fmt_color_depth(
>> +				hdmi->hdmi_data.enc_out_bus_format)) {
>> +		case 16:
>> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 2;
> 
> Both mpixelclock and mtmdsclock are unsigned int. Is the cast to u64
> needed ?
> 
> On a separate but related note, what does the 'm' in tmdsclock stand for
> ? It seems to originate from the 'm' prefix for mpixelclock, which has
> been there from the start. Unless there's a good reason for the prefix,
> renaming mtmdsclock to tmds_clock (and handling the other fields in the
> hdmi_vmode structure similarly) would increase clarity I think.
> 
>> +			break;
>> +		case 12:
>> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2;
>> +			break;
>> +		case 10:
>> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4;
>> +			break;
>> +		}
>> +	}
>> +
>>  	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
>>  		vmode->mtmdsclock /= 2;
>>  
>> +	dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);
> 
> s/tmdsclk/tmdsclock/ to match the field name ?
> 
>> +
>>  	/* Set up HDMI_FC_INVIDCONF */
>>  	inv_val = (hdmi->hdmi_data.hdcp_enable ||
>>  		   (dw_hdmi_support_scdc(hdmi) &&
> 

I fixed the calculus and the cast, but I'll rename the mtmdsclock in a following patch.

is it ok for you ?

Neil

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
  2020-03-02  9:18       ` Laurent Pinchart
@ 2020-03-02 15:55         ` Neil Armstrong
  0 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02 15:55 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Škrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, Daniel Vetter, linux-amlogic

On 02/03/2020 10:18, Laurent Pinchart wrote:
> Hi Neil and Jonas,
> 
> (CC'ing Daniel for a framework question)
> 
> Thank you for the patch.
> 
> On Fri, Feb 21, 2020 at 09:50:18AM +0100, Neil Armstrong wrote:
>> On 17/02/2020 07:38, Jernej Škrabec wrote:
>>> Dne četrtek, 06. februar 2020 ob 20:18:25 CET je Neil Armstrong napisal(a):
>>>> From: Jonas Karlman <jonas@kwiboo.se>
>>>>
>>>> Add the max_bpc property to the dw-hdmi connector to prepare support
>>>> for 10, 12 & 16bit output support.
>>>>
>>>> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
>>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>>> ---
>>>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
>>>>  1 file changed, 4 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>>> b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index
>>>> 9e0927d22db6..051001f77dd4 100644
>>>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>>>> @@ -2406,6 +2406,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge
>>>> *bridge) DRM_MODE_CONNECTOR_HDMIA,
>>>>  				    hdmi->ddc);
>>>>
>>>> +	drm_atomic_helper_connector_reset(connector);
>>>
>>> Why is this reset needed?
>>
>> I assume it's to allocate a new connector state to attach a the bpc propery.
>>
>> But indeed, this helper is never used here, but only as callback to the drm_connector_funcs->reset.
>>
>> But, amdgpu calls :
>> 	/*
>> 	 * Some of the properties below require access to state, like bpc.
>> 	 * Allocate some default initial connector state with our reset helper.
>> 	 */
>> 	if (aconnector->base.funcs->reset)
>> 		aconnector->base.funcs->reset(&aconnector->base);
>>
>> which is the same.
> 
> A comment would be useful:
> 
> 	/*
> 	 * drm_connector_attach_max_bpc_property() requires the
> 	 * connector to have a state.
> 	 */
> 	drm_atomic_helper_connector_reset(connector);
> 
> 	drm_connector_attach_max_bpc_property(connector, 8, 16);
> 

Done

> I don't like this much though, it feels like the initial reset performed
> by drm_mode_config_reset() should set default values for all state
> members that are related to properties. Daniel, what's the rationale
> behind the current implementation ?
> 
> This is a DRM core issue that shouldn't block this patch though, so

I'll investigate why, but I haven't found out how the intel driver got the
connector state initialized since they don't use the atomic helpers....

> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
>>>> +
>>>> +	drm_connector_attach_max_bpc_property(connector, 8, 16);
>>>> +
>>>>  	if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
>>>>  		drm_object_attach_property(&connector->base,
>>>>  			connector->dev-
>>>> mode_config.hdr_output_metadata_property, 0);
> 


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
  2020-03-02  9:56   ` Laurent Pinchart
@ 2020-03-02 15:55     ` Neil Armstrong
  0 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02 15:55 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

On 02/03/2020 10:56, Laurent Pinchart wrote:
> Hi Neil,
> 
> Thank you for the patch.
> 
> On Thu, Feb 06, 2020 at 08:18:26PM +0100, Neil Armstrong wrote:
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> 
> How about adding a commit message ?

Done, thanks

> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> index 051001f77dd4..fec4a4bcd1fe 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -2494,6 +2494,9 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
>>  }
>>  
>>  static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>> +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
>> +	.atomic_reset = drm_atomic_helper_bridge_reset,
>>  	.attach = dw_hdmi_bridge_attach,
>>  	.detach = dw_hdmi_bridge_detach,
>>  	.enable = dw_hdmi_bridge_enable,
> 


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-03-02 10:18   ` Laurent Pinchart
@ 2020-03-02 15:57     ` Neil Armstrong
  0 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02 15:57 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

On 02/03/2020 11:18, Laurent Pinchart wrote:
> Hi Neil,
> 
> Thank you for the patch.
> 
> On Thu, Feb 06, 2020 at 08:18:27PM +0100, Neil Armstrong wrote:
>> Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
>> the possible output and input formats for the current mode and monitor,
>> and use the negotiated formats in a basic atomic_check callback.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
>>  1 file changed, 268 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> index fec4a4bcd1fe..15048ad694bc 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>>  	hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
>>  	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)
>>  		hdmi->hdmi_data.enc_in_bus_format =
>>  			hdmi->plat_data->input_bus_format;
>> -	else
>> +	else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
>>  		hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
>>  
>>  	/* TOFIX: Get input encoding from plat data or fallback to none */
>> @@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>>  	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->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
>> +		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;
>> @@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
>>  	.atomic_check = dw_hdmi_connector_atomic_check,
>>  };
>>  
>> +/*
>> + * Possible output formats :
>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
>> + * - MEDIA_BUS_FMT_YUV16_1X48,
>> + * - MEDIA_BUS_FMT_RGB161616_1X48,
>> + * - MEDIA_BUS_FMT_UYVY12_1X24,
>> + * - MEDIA_BUS_FMT_YUV12_1X36,
>> + * - MEDIA_BUS_FMT_RGB121212_1X36,
>> + * - MEDIA_BUS_FMT_UYVY10_1X20,
>> + * - MEDIA_BUS_FMT_YUV10_1X30,
>> + * - MEDIA_BUS_FMT_RGB101010_1X30,
>> + * - MEDIA_BUS_FMT_UYVY8_1X16,
>> + * - MEDIA_BUS_FMT_YUV8_1X24,
>> + * - MEDIA_BUS_FMT_RGB888_1X24,
>> + */
> 
> I'd drop this comment as I don't think it brings much, except for a risk
> of getting out of sync with the implementation below :-)

I know it's redundant, but I'll prefer having it here to clarify which bus formats
are handled.

> 
>> +
>> +/* Can return a maximum of 12 possible output formats for a mode/connector */
>> +#define MAX_OUTPUT_SEL_FORMATS	12
> 
> I count 11 below.

Exact !

> 
>> +
>> +static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
>> +					struct drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state *crtc_state,
>> +					struct drm_connector_state *conn_state,
>> +					unsigned int *num_output_fmts)
>> +{
>> +	struct drm_connector *conn = conn_state->connector;
>> +	struct drm_display_info *info = &conn->display_info;
>> +	struct drm_display_mode *mode = &crtc_state->mode;
>> +	u8 max_bpc = conn_state->max_requested_bpc;
>> +	bool is_hdmi2_sink = info->hdmi.scdc.supported ||
>> +			     (info->color_formats & DRM_COLOR_FORMAT_YCRCB420);
>> +	u32 *output_fmts;
>> +	int i = 0;
> 
> i is never negative, you can make it an unsigned int.
ok

> 
>> +
>> +	*num_output_fmts = 0;
>> +
>> +	output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
>> +			      GFP_KERNEL);
>> +	if (!output_fmts)
>> +		return NULL;
>> +
>> +	/*
>> +	 * If the current mode enforces 4:2:0, force the output but format
>> +	 * to 4:2:0 and do not add the YUV422/444/RGB formats
>> +	 */
>> +	if (conn->ycbcr_420_allowed &&
>> +	    (drm_mode_is_420_only(info, mode) ||
>> +	     (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) {
>> +
>> +		/* Order bus formats from 16bit to 8bit if supported */
>> +		if (max_bpc >= 16 && info->bpc == 16 &&
>> +		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48))
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48;
>> +
>> +		if (max_bpc >= 12 && info->bpc >= 12 &&
>> +		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36))
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
>> +
>> +		if (max_bpc >= 10 && info->bpc >= 10 &&
>> +		    (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30))
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
>> +
>> +		/* Default 8bit fallback */
>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
>> +
>> +		*num_output_fmts = i;
>> +
>> +		return output_fmts;
>> +	}
>> +
>> +	/*
>> +	 * Order bus formats from 16bit to 8bit and from YUV422 to RGB
>> +	 * if supported. In any case the default RGB888 format is added
>> +	 */
>> +
>> +	if (max_bpc >= 16 && info->bpc == 16) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +	}
>> +
>> +	if (max_bpc >= 12 && info->bpc >= 12) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +	}
>> +
>> +	if (max_bpc >= 10 && info->bpc >= 10) {
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +
>> +		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +			output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +
>> +		output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +	}
>> +
>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
>> +		output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +
>> +	if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
>> +		output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +
>> +	/* Default 8bit RGB fallback */
>> +	output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +
>> +	*num_output_fmts = i;
>> +
>> +	return output_fmts;
>> +}
>> +
>> +/*
>> + * Possible input formats :
>> + * - MEDIA_BUS_FMT_RGB888_1X24
>> + * - MEDIA_BUS_FMT_YUV8_1X24
>> + * - MEDIA_BUS_FMT_UYVY8_1X16
>> + * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
>> + * - MEDIA_BUS_FMT_RGB101010_1X30
>> + * - MEDIA_BUS_FMT_YUV10_1X30
>> + * - MEDIA_BUS_FMT_UYVY10_1X20
>> + * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
>> + * - MEDIA_BUS_FMT_RGB121212_1X36
>> + * - MEDIA_BUS_FMT_YUV12_1X36
>> + * - MEDIA_BUS_FMT_UYVY12_1X24
>> + * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
>> + * - MEDIA_BUS_FMT_RGB161616_1X48
>> + * - MEDIA_BUS_FMT_YUV16_1X48
>> + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
>> + */
> 
> Same here.

I'll prefer keeping these aswell

> 
>> +
>> +/* Can return a maximum of 4 possible input formats for an output format */
>> +#define MAX_INPUT_SEL_FORMATS	4
> 
> As Boris pointed out, that should be 3.

Yep

> 
>> +
>> +static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
>> +					struct drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state *crtc_state,
>> +					struct drm_connector_state *conn_state,
>> +					u32 output_fmt,
>> +					unsigned int *num_input_fmts)
>> +{
>> +	u32 *input_fmts;
>> +	int i = 0;
> 
> i is never negative, you can make it an unsigned int.
ok

> 
>> +
>> +	*num_input_fmts = 0;
>> +
>> +	input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
>> +			     GFP_KERNEL);
>> +	if (!input_fmts)
>> +		return NULL;
>> +
>> +	switch (output_fmt) {
>> +	/* 8bit */
>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV8_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
>> +		break;
>> +
>> +	/* 10bit */
>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV10_1X30:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
>> +		break;
>> +
>> +	/* 12bit */
>> +	case MEDIA_BUS_FMT_RGB121212_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV12_1X36:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY12_1X24:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
>> +		break;
>> +
>> +	/* 16bit */
>> +	case MEDIA_BUS_FMT_RGB161616_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		break;
>> +	case MEDIA_BUS_FMT_YUV16_1X48:
>> +		input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
>> +		input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
>> +		break;
>> +
>> +	/* 420 */
> 
> s/420/YUV 4:2:0/ ?

Looks better

> 
>> +	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:
>> +		input_fmts[i++] = output_fmt;
>> +		break;
>> +	}
>> +
>> +	*num_input_fmts = i;
>> +
>> +	if (*num_input_fmts == 0) {
>> +		kfree(input_fmts);
>> +		input_fmts = NULL;
>> +	}
>> +
>> +	return input_fmts;
>> +}
>> +
>> +static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
>> +				       struct drm_bridge_state *bridge_state,
>> +				       struct drm_crtc_state *crtc_state,
>> +				       struct drm_connector_state *conn_state)
>> +{
>> +	struct dw_hdmi *hdmi = bridge->driver_private;
>> +
>> +	dev_dbg(hdmi->dev, "selected output format %x\n",
> 
> s/%x/0x%04x/
> 
>> +			bridge_state->output_bus_cfg.format);
> 
> Misalignment ?

Fixed

> 
>> +
>> +	hdmi->hdmi_data.enc_out_bus_format =
>> +			bridge_state->output_bus_cfg.format;
>> +
>> +	dev_dbg(hdmi->dev, "selected input format %x\n",
>> +			bridge_state->input_bus_cfg.format);
> 
> Same here. I would combine both messages:
> 
> 	dev_dbg(hdmi->dev, "input format: 0x%04x, output format: 0x04x\n",
> 		bridge_state->input_bus_cfg.format,
> 		bridge_state->output_bus_cfg.format);

Looks better

> 
>> +
>> +	hdmi->hdmi_data.enc_in_bus_format =
>> +			bridge_state->input_bus_cfg.format;
>> +
>> +	return 0;
>> +}
>> +
>>  static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
>>  {
>>  	struct dw_hdmi *hdmi = bridge->driver_private;
>> @@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
>>  	.atomic_reset = drm_atomic_helper_bridge_reset,
>>  	.attach = dw_hdmi_bridge_attach,
>>  	.detach = dw_hdmi_bridge_detach,
>> +	.atomic_check = dw_hdmi_bridge_atomic_check,
>> +	.atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
>> +	.atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
>>  	.enable = dw_hdmi_bridge_enable,
>>  	.disable = dw_hdmi_bridge_disable,
>>  	.mode_set = dw_hdmi_bridge_mode_set,
>> @@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>  
>>  	hdmi->bridge.driver_private = hdmi;
>>  	hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
>> +
> 
> This seems unrelated.

Yep

> 
>>  #ifdef CONFIG_OF
>>  	hdmi->bridge.of_node = pdev->dev.of_node;
>>  #endif
> 

Thanks,
Neil

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2020-03-02 10:03   ` Laurent Pinchart
@ 2020-03-02 15:58     ` Neil Armstrong
  0 siblings, 0 replies; 41+ messages in thread
From: Neil Armstrong @ 2020-03-02 15:58 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

On 02/03/2020 11:03, Laurent Pinchart wrote:
> Hi Neil,
> 
> Thank you for the patch.
> 
> On Thu, Feb 06, 2020 at 08:18:28PM +0100, Neil Armstrong wrote:
>> 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 15048ad694bc..4b35ea1427df 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -3231,6 +3231,12 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>  	hdmi->bridge.of_node = pdev->dev.of_node;
>>  #endif
>>  
>> +	if (hdmi->version >= 0x200a)
>> +		hdmi->connector.ycbcr_420_allowed =
>> +			hdmi->plat_data->ycbcr_420_allowed;
>> +	else
>> +		hdmi->connector.ycbcr_420_allowed = false;
>> +
> 
> The hdmi structure being allocated with kzalloc, you don't need the
> second branch of the if, but I'm fine if you prefer keeping it. Any
> either case,

Yep Andrzej said the same, but I prefer it to be explicit.

> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Thanks,
Neil

> 
>>  	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 9d4d5cc47969..0b34a12c4a1c 100644
>> --- a/include/drm/bridge/dw_hdmi.h
>> +++ b/include/drm/bridge/dw_hdmi.h
>> @@ -129,6 +129,7 @@ struct dw_hdmi_plat_data {
>>  	unsigned long input_bus_format;
>>  	unsigned long input_bus_encoding;
>>  	bool use_drm_infoframe;
>> +	bool ycbcr_420_allowed;
>>  
>>  	/* Vendor PHY support */
>>  	const struct dw_hdmi_phy_ops *phy_ops;
> 


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
  2020-03-02 15:54     ` Neil Armstrong
@ 2020-03-02 16:01       ` Laurent Pinchart
  0 siblings, 0 replies; 41+ messages in thread
From: Laurent Pinchart @ 2020-03-02 16:01 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jernej.skrabec, jonas, linux-kernel, dri-devel, a.hajda,
	boris.brezillon, linux-amlogic

Hi Neil,
 
On Mon, Mar 02, 2020 at 04:54:17PM +0100, Neil Armstrong wrote:
> On 02/03/2020 10:05, Laurent Pinchart wrote:
> > On Thu, Feb 06, 2020 at 08:18:24PM +0100, Neil Armstrong wrote:
> >> From: Jonas Karlman <jonas@kwiboo.se>
> >>
> >> Configure the correct mtmdsclock for deep colors to prepare support
> >> for 10, 12 & 16bit output.
> >>
> >> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
> >> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> >> ---
> >>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
> >>  1 file changed, 17 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> index 67fca439bbfb..9e0927d22db6 100644
> >> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> >> @@ -1818,9 +1818,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
> >>  
> >>  	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
> > 
> > Nitpicking a bit, I would change
> > 
> > -	vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
> > +	vmode->mpixelclock = mode->clock * 1000;
> > 
> > above, and here add
> > 
> > 	vmode->mtmdsclock = vmode->mpixelclock;
> > 
> > to keep all mtmdsclock calculation in a single place.
> > 
> >> +	if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
> >> +		switch (hdmi_bus_fmt_color_depth(
> >> +				hdmi->hdmi_data.enc_out_bus_format)) {
> >> +		case 16:
> >> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 2;
> > 
> > Both mpixelclock and mtmdsclock are unsigned int. Is the cast to u64
> > needed ?
> > 
> > On a separate but related note, what does the 'm' in tmdsclock stand for
> > ? It seems to originate from the 'm' prefix for mpixelclock, which has
> > been there from the start. Unless there's a good reason for the prefix,
> > renaming mtmdsclock to tmds_clock (and handling the other fields in the
> > hdmi_vmode structure similarly) would increase clarity I think.
> > 
> >> +			break;
> >> +		case 12:
> >> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2;
> >> +			break;
> >> +		case 10:
> >> +			vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4;
> >> +			break;
> >> +		}
> >> +	}
> >> +
> >>  	if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
> >>  		vmode->mtmdsclock /= 2;
> >>  
> >> +	dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);
> > 
> > s/tmdsclk/tmdsclock/ to match the field name ?
> > 
> >> +
> >>  	/* Set up HDMI_FC_INVIDCONF */
> >>  	inv_val = (hdmi->hdmi_data.hdcp_enable ||
> >>  		   (dw_hdmi_support_scdc(hdmi) &&
> > 
> 
> I fixed the calculus and the cast, but I'll rename the mtmdsclock in a following patch.
> 
> is it ok for you ?

Sure, works for me.

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

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

end of thread, other threads:[~2020-03-02 16:02 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-06 19:18 [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color Neil Armstrong
2020-03-02  9:05   ` Laurent Pinchart
2020-03-02  9:21     ` Neil Armstrong
2020-03-02 15:54     ` Neil Armstrong
2020-03-02 16:01       ` Laurent Pinchart
2020-02-06 19:18 ` [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property Neil Armstrong
2020-02-17  6:38   ` Jernej Škrabec
2020-02-21  8:50     ` Neil Armstrong
2020-03-02  9:18       ` Laurent Pinchart
2020-03-02 15:55         ` Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation Neil Armstrong
2020-02-07 10:57   ` Boris Brezillon
2020-03-02  9:56   ` Laurent Pinchart
2020-03-02 15:55     ` Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation Neil Armstrong
2020-02-07 11:02   ` Boris Brezillon
2020-02-07 13:36     ` Neil Armstrong
2020-02-29  7:42   ` Jernej Škrabec
2020-02-29 10:09     ` Jonas Karlman
2020-02-29 11:07       ` Jernej Škrabec
2020-02-29 12:15         ` Jonas Karlman
2020-02-29 14:42           ` Jernej Škrabec
2020-03-02  8:08       ` Neil Armstrong
2020-03-02  8:04     ` Neil Armstrong
2020-03-02 10:18   ` Laurent Pinchart
2020-03-02 15:57     ` Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a Neil Armstrong
2020-02-07 13:38   ` Neil Armstrong
2020-03-02 10:03   ` Laurent Pinchart
2020-03-02 15:58     ` Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const Neil Armstrong
2020-02-07 13:39   ` Neil Armstrong
2020-03-02  9:59   ` Laurent Pinchart
2020-02-06 19:18 ` [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs Neil Armstrong
2020-02-07 14:57   ` Boris Brezillon
2020-02-07 15:36     ` Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 08/11] drm/meson: dw-hdmi: stop enforcing input_bus_format Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 09/11] drm/meson: venc: add support for YUV420 setup Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 10/11] drm/meson: vclk: " Neil Armstrong
2020-02-06 19:18 ` [PATCH v4 11/11] drm/meson: Add YUV420 output support 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).