All of lore.kernel.org
 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
  0 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


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

* [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support
@ 2020-02-06 19:18 ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 00/11] drm/bridge: dw-hdmi: implement bus-format negotiation and YUV420 support
@ 2020-02-06 19:18 ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel, 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


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

* [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel, 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


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

* [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


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

* [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


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

* [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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

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

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 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


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

* [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


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

* [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


^ permalink raw reply related	[flat|nested] 128+ 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   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 128+ 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   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 08/11] drm/meson: dw-hdmi: stop enforcing input_bus_format
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


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

* [PATCH v4 08/11] drm/meson: dw-hdmi: stop enforcing input_bus_format
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 08/11] drm/meson: dw-hdmi: stop enforcing input_bus_format
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 09/11] drm/meson: venc: add support for YUV420 setup
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


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

* [PATCH v4 09/11] drm/meson: venc: add support for YUV420 setup
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 09/11] drm/meson: venc: add support for YUV420 setup
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 10/11] drm/meson: vclk: add support for YUV420 setup
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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


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

* [PATCH v4 10/11] drm/meson: vclk: add support for YUV420 setup
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 10/11] drm/meson: vclk: add support for YUV420 setup
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* [PATCH v4 11/11] drm/meson: Add YUV420 output support
  2020-02-06 19:18 ` Neil Armstrong
  (?)
@ 2020-02-06 19:18   ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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

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

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

This patch 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


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

* [PATCH v4 11/11] drm/meson: Add YUV420 output support
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v4 11/11] drm/meson: Add YUV420 output support
@ 2020-02-06 19:18   ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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   ` Neil Armstrong
  (?)
@ 2020-02-07 10:57     ` Boris Brezillon
  -1 siblings, 0 replies; 128+ messages in thread
From: Boris Brezillon @ 2020-02-07 10:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, linux-amlogic,
	dri-devel, linux-kernel

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,


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

* Re: [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
@ 2020-02-07 10:57     ` Boris Brezillon
  0 siblings, 0 replies; 128+ 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,

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
@ 2020-02-07 10:57     ` Boris Brezillon
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

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

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


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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-07 11:02     ` Boris Brezillon
  0 siblings, 0 replies; 128+ 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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

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
> 


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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-07 13:36       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-07 13:36       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* Re: [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
  2020-02-06 19:18   ` Neil Armstrong
  (?)
@ 2020-02-07 13:38     ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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

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

* Re: [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
@ 2020-02-07 13:38     ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 05/11] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= 0x200a
@ 2020-02-07 13:38     ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* Re: [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
  2020-02-06 19:18   ` Neil Armstrong
  (?)
@ 2020-02-07 13:39     ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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

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

* Re: [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
@ 2020-02-07 13:39     ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
@ 2020-02-07 13:39     ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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   ` Neil Armstrong
  (?)
@ 2020-02-07 14:57     ` Boris Brezillon
  -1 siblings, 0 replies; 128+ messages in thread
From: Boris Brezillon @ 2020-02-07 14:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, linux-amlogic,
	dri-devel, linux-kernel

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;


^ permalink raw reply	[flat|nested] 128+ 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
  0 siblings, 0 replies; 128+ 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;

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 128+ 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
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ messages in thread
From: Neil Armstrong @ 2020-02-07 15:36 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: a.hajda, Laurent.pinchart, jonas, jernej.skrabec, linux-amlogic,
	dri-devel, linux-kernel

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;
> 


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

* Re: [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs
@ 2020-02-07 15:36       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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;
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 07/11] drm/meson: meson_dw_hdmi: add bridge and switch to drm_bridge_funcs
@ 2020-02-07 15:36       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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   ` Neil Armstrong
                     ` (2 preceding siblings ...)
  (?)
@ 2020-02-09  8:51   ` kbuild test robot
  -1 siblings, 0 replies; 128+ messages in thread
From: kbuild test robot @ 2020-02-09  8:51 UTC (permalink / raw)
  To: kbuild-all

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

Hi Neil,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.5 next-20200207]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Neil-Armstrong/drm-bridge-dw-hdmi-implement-bus-format-negotiation-and-YUV420-support/20200209-150729
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git d4f309ca411887cd61ea389c7abfb70c2eb1e532
config: openrisc-randconfig-a001-20200209 (attached as .config)
compiler: or1k-linux-gcc (GCC) 9.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=9.2.0 make.cross ARCH=openrisc 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2497:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_duplicate_state'
    2497 |  .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
         |   ^~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2497:28: error: 'drm_atomic_helper_bridge_duplicate_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_duplicate_state'?
    2497 |  .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
         |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                            drm_atomic_helper_plane_duplicate_state
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2498:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_destroy_state'
    2498 |  .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
         |   ^~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2498:26: error: 'drm_atomic_helper_bridge_destroy_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_destroy_state'?
    2498 |  .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                          drm_atomic_helper_plane_destroy_state
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2499:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_reset'
    2499 |  .atomic_reset = drm_atomic_helper_bridge_reset,
         |   ^~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2499:18: error: 'drm_atomic_helper_bridge_reset' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_reset'?
    2499 |  .atomic_reset = drm_atomic_helper_bridge_reset,
         |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                  drm_atomic_helper_plane_reset

vim +2497 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

  2495	
  2496	static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
> 2497		.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> 2498		.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> 2499		.atomic_reset = drm_atomic_helper_bridge_reset,
  2500		.attach = dw_hdmi_bridge_attach,
  2501		.detach = dw_hdmi_bridge_detach,
  2502		.enable = dw_hdmi_bridge_enable,
  2503		.disable = dw_hdmi_bridge_disable,
  2504		.mode_set = dw_hdmi_bridge_mode_set,
  2505		.mode_valid = dw_hdmi_bridge_mode_valid,
  2506	};
  2507	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 28337 bytes --]

^ permalink raw reply	[flat|nested] 128+ 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   ` Neil Armstrong
                     ` (3 preceding siblings ...)
  (?)
@ 2020-02-09  9:08   ` kbuild test robot
  -1 siblings, 0 replies; 128+ messages in thread
From: kbuild test robot @ 2020-02-09  9:08 UTC (permalink / raw)
  To: kbuild-all

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

Hi Neil,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.5 next-20200207]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Neil-Armstrong/drm-bridge-dw-hdmi-implement-bus-format-negotiation-and-YUV420-support/20200209-150729
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git d4f309ca411887cd61ea389c7abfb70c2eb1e532
config: s390-randconfig-a001-20200209 (attached as .config)
compiler: s390-linux-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=s390 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2497:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_duplicate_state'; did you mean 'atomic_pre_enable'?
     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
      ^~~~~~~~~~~~~~~~~~~~~~
      atomic_pre_enable
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2497:28: error: 'drm_atomic_helper_bridge_duplicate_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_duplicate_state'?
     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                               drm_atomic_helper_plane_duplicate_state
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2498:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_destroy_state'; did you mean 'atomic_post_disable'?
     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
      ^~~~~~~~~~~~~~~~~~~~
      atomic_post_disable
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2498:26: error: 'drm_atomic_helper_bridge_destroy_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_destroy_state'?
     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                             drm_atomic_helper_plane_destroy_state
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2499:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_reset'; did you mean 'atomic_enable'?
     .atomic_reset = drm_atomic_helper_bridge_reset,
      ^~~~~~~~~~~~
      atomic_enable
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2499:18: error: 'drm_atomic_helper_bridge_reset' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_reset'?
     .atomic_reset = drm_atomic_helper_bridge_reset,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     drm_atomic_helper_plane_reset

vim +2497 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

  2495	
  2496	static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
> 2497		.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
  2498		.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
  2499		.atomic_reset = drm_atomic_helper_bridge_reset,
  2500		.attach = dw_hdmi_bridge_attach,
  2501		.detach = dw_hdmi_bridge_detach,
  2502		.enable = dw_hdmi_bridge_enable,
  2503		.disable = dw_hdmi_bridge_disable,
  2504		.mode_set = dw_hdmi_bridge_mode_set,
  2505		.mode_valid = dw_hdmi_bridge_mode_valid,
  2506	};
  2507	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 31390 bytes --]

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18   ` Neil Armstrong
                     ` (2 preceding siblings ...)
  (?)
@ 2020-02-09  9:32   ` kbuild test robot
  -1 siblings, 0 replies; 128+ messages in thread
From: kbuild test robot @ 2020-02-09  9:32 UTC (permalink / raw)
  To: kbuild-all

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

Hi Neil,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.5 next-20200207]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Neil-Armstrong/drm-bridge-dw-hdmi-implement-bus-format-negotiation-and-YUV420-support/20200209-150729
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git d4f309ca411887cd61ea389c7abfb70c2eb1e532
config: openrisc-randconfig-a001-20200209 (attached as .config)
compiler: or1k-linux-gcc (GCC) 9.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=9.2.0 make.cross ARCH=openrisc 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2413:13: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
    2413 |      struct drm_bridge_state *bridge_state,
         |             ^~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2532:13: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
    2532 |      struct drm_bridge_state *bridge_state,
         |             ^~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2630:19: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
    2630 |            struct drm_bridge_state *bridge_state,
         |                   ^~~~~~~~~~~~~~~~
   In file included from include/linux/device.h:15,
                    from include/linux/hdmi.h:28,
                    from drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:12:
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c: In function 'dw_hdmi_bridge_atomic_check':
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2637:16: error: dereferencing pointer to incomplete type 'struct drm_bridge_state'
    2637 |    bridge_state->output_bus_cfg.format);
         |                ^~
   include/linux/dev_printk.h:122:47: note: in definition of macro 'dev_dbg'
     122 |   dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \
         |                                               ^~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c: At top level:
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2757:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_duplicate_state'
    2757 |  .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
         |   ^~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2757:28: error: 'drm_atomic_helper_bridge_duplicate_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_duplicate_state'?
    2757 |  .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
         |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                            drm_atomic_helper_plane_duplicate_state
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2758:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_destroy_state'
    2758 |  .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
         |   ^~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2758:26: error: 'drm_atomic_helper_bridge_destroy_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_destroy_state'?
    2758 |  .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                          drm_atomic_helper_plane_destroy_state
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2759:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_reset'
    2759 |  .atomic_reset = drm_atomic_helper_bridge_reset,
         |   ^~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2759:18: error: 'drm_atomic_helper_bridge_reset' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_reset'?
    2759 |  .atomic_reset = drm_atomic_helper_bridge_reset,
         |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                  drm_atomic_helper_plane_reset
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2762:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_check'
    2762 |  .atomic_check = dw_hdmi_bridge_atomic_check,
         |   ^~~~~~~~~~~~
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2762:18: error: initialization of 'enum drm_mode_status (*)(struct drm_bridge *, const struct drm_display_mode *)' from incompatible pointer type 'int (*)(struct drm_bridge *, struct drm_bridge_state *, struct drm_crtc_state *, struct drm_connector_state *)' [-Werror=incompatible-pointer-types]
    2762 |  .atomic_check = dw_hdmi_bridge_atomic_check,
         |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2762:18: note: (near initialization for 'dw_hdmi_bridge_funcs.mode_valid')
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2763:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_get_output_bus_fmts'
    2763 |  .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
         |   ^~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2763:32: error: initialization of 'bool (*)(struct drm_bridge *, const struct drm_display_mode *, struct drm_display_mode *)' {aka '_Bool (*)(struct drm_bridge *, const struct drm_display_mode *, struct drm_display_mode *)'} from incompatible pointer type 'u32 * (*)(struct drm_bridge *, struct drm_bridge_state *, struct drm_crtc_state *, struct drm_connector_state *, unsigned int *)' {aka 'unsigned int * (*)(struct drm_bridge *, struct drm_bridge_state *, struct drm_crtc_state *, struct drm_connector_state *, unsigned int *)'} [-Werror=incompatible-pointer-types]
    2763 |  .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
         |                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2763:32: note: (near initialization for 'dw_hdmi_bridge_funcs.mode_fixup')
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2764:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_get_input_bus_fmts'
    2764 |  .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
         |   ^~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2764:31: error: initialization of 'void (*)(struct drm_bridge *)' from incompatible pointer type 'u32 * (*)(struct drm_bridge *, struct drm_bridge_state *, struct drm_crtc_state *, struct drm_connector_state *, u32,  unsigned int *)' {aka 'unsigned int * (*)(struct drm_bridge *, struct drm_bridge_state *, struct drm_crtc_state *, struct drm_connector_state *, unsigned int,  unsigned int *)'} [-Werror=incompatible-pointer-types]
    2764 |  .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
         |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2764:31: note: (near initialization for 'dw_hdmi_bridge_funcs.disable')
   cc1: some warnings being treated as errors

vim +2762 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

  2755	
  2756	static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
  2757		.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
  2758		.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
  2759		.atomic_reset = drm_atomic_helper_bridge_reset,
  2760		.attach = dw_hdmi_bridge_attach,
  2761		.detach = dw_hdmi_bridge_detach,
> 2762		.atomic_check = dw_hdmi_bridge_atomic_check,
> 2763		.atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
> 2764		.atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
  2765		.enable = dw_hdmi_bridge_enable,
  2766		.disable = dw_hdmi_bridge_disable,
  2767		.mode_set = dw_hdmi_bridge_mode_set,
  2768		.mode_valid = dw_hdmi_bridge_mode_valid,
  2769	};
  2770	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 28337 bytes --]

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18   ` Neil Armstrong
                     ` (3 preceding siblings ...)
  (?)
@ 2020-02-09 10:01   ` kbuild test robot
  -1 siblings, 0 replies; 128+ messages in thread
From: kbuild test robot @ 2020-02-09 10:01 UTC (permalink / raw)
  To: kbuild-all

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

Hi Neil,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.5 next-20200207]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Neil-Armstrong/drm-bridge-dw-hdmi-implement-bus-format-negotiation-and-YUV420-support/20200209-150729
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git d4f309ca411887cd61ea389c7abfb70c2eb1e532
config: xtensa-allyesconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=xtensa 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2413:13: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
         struct drm_bridge_state *bridge_state,
                ^~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2532:13: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
         struct drm_bridge_state *bridge_state,
                ^~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2630:19: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
               struct drm_bridge_state *bridge_state,
                      ^~~~~~~~~~~~~~~~
   In file included from include/linux/printk.h:331:0,
                    from include/linux/kernel.h:15,
                    from include/linux/clk.h:13,
                    from drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:9:
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c: In function 'dw_hdmi_bridge_atomic_check':
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2637:16: error: dereferencing pointer to incomplete type 'struct drm_bridge_state'
       bridge_state->output_bus_cfg.format);
                   ^
   include/linux/dynamic_debug.h:125:15: note: in definition of macro '__dynamic_func_call'
      func(&id, ##__VA_ARGS__);  \
                  ^~~~~~~~~~~
   include/linux/dynamic_debug.h:157:2: note: in expansion of macro '_dynamic_func_call'
     _dynamic_func_call(fmt,__dynamic_dev_dbg,   \
     ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:114:2: note: in expansion of macro 'dynamic_dev_dbg'
     dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2636:2: note: in expansion of macro 'dev_dbg'
     dev_dbg(hdmi->dev, "selected output format %x\n",
     ^~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c: At top level:
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2757:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_duplicate_state'; did you mean 'atomic_pre_enable'?
     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
      ^~~~~~~~~~~~~~~~~~~~~~
      atomic_pre_enable
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2757:28: error: 'drm_atomic_helper_bridge_duplicate_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_duplicate_state'?
     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                               drm_atomic_helper_plane_duplicate_state
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2758:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_destroy_state'; did you mean 'atomic_post_disable'?
     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
      ^~~~~~~~~~~~~~~~~~~~
      atomic_post_disable
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2758:26: error: 'drm_atomic_helper_bridge_destroy_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_destroy_state'?
     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                             drm_atomic_helper_plane_destroy_state
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2759:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_reset'; did you mean 'atomic_enable'?
     .atomic_reset = drm_atomic_helper_bridge_reset,
      ^~~~~~~~~~~~
      atomic_enable
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2759:18: error: 'drm_atomic_helper_bridge_reset' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_reset'?
     .atomic_reset = drm_atomic_helper_bridge_reset,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     drm_atomic_helper_plane_reset
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2762:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_check'; did you mean 'atomic_enable'?
     .atomic_check = dw_hdmi_bridge_atomic_check,
      ^~~~~~~~~~~~
      atomic_enable
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2762:18: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .atomic_check = dw_hdmi_bridge_atomic_check,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2762:18: note: (near initialization for 'dw_hdmi_bridge_funcs.mode_valid')
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2763:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_get_output_bus_fmts'
     .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
      ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2763:32: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2763:32: note: (near initialization for 'dw_hdmi_bridge_funcs.mode_fixup')
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2764:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_get_input_bus_fmts'
     .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
      ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2764:31: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:2764:31: note: (near initialization for 'dw_hdmi_bridge_funcs.disable')
   cc1: some warnings being treated as errors

vim +/dev_dbg +2636 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

  2628	
  2629	static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
  2630					       struct drm_bridge_state *bridge_state,
  2631					       struct drm_crtc_state *crtc_state,
  2632					       struct drm_connector_state *conn_state)
  2633	{
  2634		struct dw_hdmi *hdmi = bridge->driver_private;
  2635	
> 2636		dev_dbg(hdmi->dev, "selected output format %x\n",
  2637				bridge_state->output_bus_cfg.format);
  2638	
  2639		hdmi->hdmi_data.enc_out_bus_format =
  2640				bridge_state->output_bus_cfg.format;
  2641	
  2642		dev_dbg(hdmi->dev, "selected input format %x\n",
  2643				bridge_state->input_bus_cfg.format);
  2644	
  2645		hdmi->hdmi_data.enc_in_bus_format =
  2646				bridge_state->input_bus_cfg.format;
  2647	
  2648		return 0;
  2649	}
  2650	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 61560 bytes --]

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

* Re: [PATCH v4 11/11] drm/meson: Add YUV420 output support
  2020-02-06 19:18   ` Neil Armstrong
  (?)
  (?)
@ 2020-02-09 13:06   ` kbuild test robot
  -1 siblings, 0 replies; 128+ messages in thread
From: kbuild test robot @ 2020-02-09 13:06 UTC (permalink / raw)
  To: kbuild-all

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

Hi Neil,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.5 next-20200207]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Neil-Armstrong/drm-bridge-dw-hdmi-implement-bus-format-negotiation-and-YUV420-support/20200209-150729
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git d4f309ca411887cd61ea389c7abfb70c2eb1e532
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/gpu/drm/meson/meson_dw_hdmi.c:719:14: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
          struct drm_bridge_state *bridge_state,
                 ^~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c:739:13: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
         struct drm_bridge_state *bridge_state,
                ^~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c:769:13: warning: 'struct drm_bridge_state' declared inside parameter list will not be visible outside of this definition or declaration
         struct drm_bridge_state *bridge_state,
                ^~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c: In function 'meson_venc_hdmi_encoder_atomic_check':
>> drivers/gpu/drm/meson/meson_dw_hdmi.c:775:40: error: dereferencing pointer to incomplete type 'struct drm_bridge_state'
     dw_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format;
                                           ^~
   drivers/gpu/drm/meson/meson_dw_hdmi.c: At top level:
   drivers/gpu/drm/meson/meson_dw_hdmi.c:842:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_duplicate_state'; did you mean 'atomic_disable'?
     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
      ^~~~~~~~~~~~~~~~~~~~~~
      atomic_disable
   drivers/gpu/drm/meson/meson_dw_hdmi.c:842:28: error: 'drm_atomic_helper_bridge_duplicate_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_duplicate_state'?
     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                               drm_atomic_helper_plane_duplicate_state
   drivers/gpu/drm/meson/meson_dw_hdmi.c:842:28: error: positional initialization of field in 'struct' declared with 'designated_init' attribute [-Werror=designated-init]
   drivers/gpu/drm/meson/meson_dw_hdmi.c:842:28: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:843:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_destroy_state'; did you mean 'atomic_post_disable'?
     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
      ^~~~~~~~~~~~~~~~~~~~
      atomic_post_disable
   drivers/gpu/drm/meson/meson_dw_hdmi.c:843:26: error: 'drm_atomic_helper_bridge_destroy_state' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_destroy_state'?
     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                             drm_atomic_helper_plane_destroy_state
   drivers/gpu/drm/meson/meson_dw_hdmi.c:843:26: error: positional initialization of field in 'struct' declared with 'designated_init' attribute [-Werror=designated-init]
   drivers/gpu/drm/meson/meson_dw_hdmi.c:843:26: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:844:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_get_output_bus_fmts'
     .atomic_get_output_bus_fmts = meson_venc_hdmi_encoder_get_out_bus_fmts,
      ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c:844:32: error: positional initialization of field in 'struct' declared with 'designated_init' attribute [-Werror=designated-init]
     .atomic_get_output_bus_fmts = meson_venc_hdmi_encoder_get_out_bus_fmts,
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c:844:32: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:844:32: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
   drivers/gpu/drm/meson/meson_dw_hdmi.c:844:32: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs.disable')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:845:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_get_input_bus_fmts'
     .atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts,
      ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c:845:31: error: positional initialization of field in 'struct' declared with 'designated_init' attribute [-Werror=designated-init]
     .atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts,
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c:845:31: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:845:31: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
   drivers/gpu/drm/meson/meson_dw_hdmi.c:845:31: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs.atomic_enable')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:846:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_reset'; did you mean 'atomic_enable'?
     .atomic_reset = drm_atomic_helper_bridge_reset,
      ^~~~~~~~~~~~
      atomic_enable
   drivers/gpu/drm/meson/meson_dw_hdmi.c:846:18: error: 'drm_atomic_helper_bridge_reset' undeclared here (not in a function); did you mean 'drm_atomic_helper_plane_reset'?
     .atomic_reset = drm_atomic_helper_bridge_reset,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     drm_atomic_helper_plane_reset
   drivers/gpu/drm/meson/meson_dw_hdmi.c:846:18: error: positional initialization of field in 'struct' declared with 'designated_init' attribute [-Werror=designated-init]
   drivers/gpu/drm/meson/meson_dw_hdmi.c:846:18: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:847:3: error: 'const struct drm_bridge_funcs' has no member named 'atomic_check'; did you mean 'atomic_enable'?
     .atomic_check = meson_venc_hdmi_encoder_atomic_check,
      ^~~~~~~~~~~~
      atomic_enable
   drivers/gpu/drm/meson/meson_dw_hdmi.c:847:18: error: positional initialization of field in 'struct' declared with 'designated_init' attribute [-Werror=designated-init]
     .atomic_check = meson_venc_hdmi_encoder_atomic_check,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_dw_hdmi.c:847:18: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs')
   drivers/gpu/drm/meson/meson_dw_hdmi.c:847:18: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
   drivers/gpu/drm/meson/meson_dw_hdmi.c:847:18: note: (near initialization for 'meson_venc_hdmi_encoder_bridge_funcs.atomic_disable')
   cc1: some warnings being treated as errors

vim +775 drivers/gpu/drm/meson/meson_dw_hdmi.c

   767	
   768	static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge,
   769						struct drm_bridge_state *bridge_state,
   770						struct drm_crtc_state *crtc_state,
   771						struct drm_connector_state *conn_state)
   772	{
   773		struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
   774	
 > 775		dw_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format;
   776	
   777		DRM_DEBUG_DRIVER("output_bus_fmt %lx\n", dw_hdmi->output_bus_fmt);
   778	
   779		return 0;
   780	}
   781	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 73516 bytes --]

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
  2020-02-06 19:18   ` Neil Armstrong
  (?)
@ 2020-02-17  6:38     ` Jernej Škrabec
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel, 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);





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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-02-17  6:38     ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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);




_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-02-17  6:38     ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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);
> 
> 
> 
> 


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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-02-21  8:50       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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);
> 
> 
> 
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-02-21  8:50       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
  2020-02-06 19:18   ` Neil Armstrong
  (?)
@ 2020-02-29  7:42     ` Jernej Škrabec
  -1 siblings, 0 replies; 128+ 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: Neil Armstrong, linux-amlogic, dri-devel, linux-kernel

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





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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29  7:42     ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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




_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29  7:42     ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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
> 
> 
> 
> 

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 10:09       ` Jonas Karlman
  0 siblings, 0 replies; 128+ 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
> 
> 
> 
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 10:09       ` Jonas Karlman
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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





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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 11:07         ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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




_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 11:07         ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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
> 
> 
> 
> 

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 12:15           ` Jonas Karlman
  0 siblings, 0 replies; 128+ 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
> 
> 
> 
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 12:15           ` Jonas Karlman
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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





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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 14:42             ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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




_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-02-29 14:42             ` Jernej Škrabec
  0 siblings, 0 replies; 128+ 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] 128+ 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-03-02  8:04       ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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
> 
> 
> 
> 


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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-03-02  8:04       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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
> 
> 
> 
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-03-02  8:04       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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-03-02  8:08         ` Neil Armstrong
  -1 siblings, 0 replies; 128+ 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, dri-devel, linux-kernel

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
>>
>>
>>
>>


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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-03-02  8:08         ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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
>>
>>
>>
>>

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-03-02  8:08         ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

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

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

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-03-02  9:05     ` Laurent Pinchart
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-03-02  9:05     ` Laurent Pinchart
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ messages in thread
From: Laurent Pinchart @ 2020-03-02  9:18 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Jernej Škrabec, a.hajda, jonas, boris.brezillon,
	linux-amlogic, dri-devel, linux-kernel, Daniel Vetter

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

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-03-02  9:18         ` Laurent Pinchart
  0 siblings, 0 replies; 128+ 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, 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-03-02  9:18         ` Laurent Pinchart
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ messages in thread
From: Neil Armstrong @ 2020-03-02  9:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: a.hajda, jonas, jernej.skrabec, boris.brezillon, linux-amlogic,
	dri-devel, linux-kernel

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

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-03-02  9:21       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-03-02  9:21       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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   ` Neil Armstrong
  (?)
@ 2020-03-02  9:56     ` Laurent Pinchart
  -1 siblings, 0 replies; 128+ messages in thread
From: Laurent Pinchart @ 2020-03-02  9:56 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: a.hajda, jonas, jernej.skrabec, boris.brezillon, linux-amlogic,
	dri-devel, linux-kernel

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

^ permalink raw reply	[flat|nested] 128+ 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
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 128+ 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
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

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

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

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

* Re: [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
@ 2020-03-02  9:59     ` Laurent Pinchart
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 06/11] drm/meson: venc: make drm_display_mode const
@ 2020-03-02  9:59     ` Laurent Pinchart
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

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

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

^ permalink raw reply	[flat|nested] 128+ 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
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 128+ 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
  0 siblings, 0 replies; 128+ 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] 128+ messages in thread

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

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

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

* Re: [PATCH v4 04/11] drm/bridge: synopsys: dw-hdmi: add bus format negociation
@ 2020-03-02 10:18     ` Laurent Pinchart
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

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

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-03-02 15:54       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 01/11] drm/bridge: dw-hdmi: set mtmdsclock for deep color
@ 2020-03-02 15:54       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ messages in thread
From: Neil Armstrong @ 2020-03-02 15:55 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Škrabec, a.hajda, jonas, boris.brezillon,
	linux-amlogic, dri-devel, linux-kernel, Daniel Vetter

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);
> 


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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-03-02 15:55           ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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, 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);
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v4 02/11] drm/bridge: dw-hdmi: add max bpc connector property
@ 2020-03-02 15:55           ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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] 128+ 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
  -1 siblings, 0 replies; 128+ messages in thread
From: Neil Armstrong @ 2020-03-02 15:55 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: a.hajda, jonas, jernej.skrabec, boris.brezillon, linux-amlogic,
	dri-devel, linux-kernel

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,
> 


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

* Re: [PATCH v4 03/11] drm/bridge: dw-hdmi: Plug atomic state hooks to the default implementation
@ 2020-03-02 15:55       ` Neil Armstrong
  0 siblings, 0 replies; 128+ 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,
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

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_h