All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 00/19] drm: Add support for bus-format negotiation
@ 2019-08-08 15:11 Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h Boris Brezillon
                   ` (19 more replies)
  0 siblings, 20 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Hello,

This patch series aims at adding support for runtime bus-format
negotiation between all elements of the
'encoder -> bridges -> connector/display' section of the pipeline.

In order to support that, we need drm bridges to fully take part in the
atomic state validation process, which requires addition of a
drm_bridge_state + a new drm_bridge_funcs.atomic_check() hook (patches
10 - 12).
Once those basic building blocks are in place, we can add new helpers
to facilitate bus-format negotiation between element of the encoder
chain (patches 13 - 14).

Patches 1 to 9 are preparatory patches for patches 10 - 14. Patch 1 is
needed to allow inclusion of drm_atomic.h from drm_bridge.h, which we
need to make drm_bridge/drm_bridge_state inherit from
drm_private_obj/drm_private_obj_state.
Patches 2 to 9 are about transitioning the bridge chain to a
double-linked list, which is needed to allow bridge elements to
negotiate with the next and prev element in the pipeline.
Most of those patches can be applied independently of the rest of the
series, especially patches 2 - 7 which I think fix some misuses of the
drm_bridge API.

To finish, patches 15 - 17 demonstrate how bus-format negotiation can
be done, and patches 18 - 19 were needed for the use case I used to test
whole solution.

As you've noticed, this is an RFC, so any kind of feedback is welcome
(apart from checkpatch reports :P).

Thanks,

Boris

Boris Brezillon (19):
  drm: Stop including drm_bridge.h from drm_crtc.h
  drm: Support custom encoder/bridge enable/disable sequences officially
  drm/vc4: Get rid of the dsi->bridge field
  drm/exynos: Get rid of exynos_dsi->out_bridge
  drm/exynos: Don't reset bridge->next
  drm/bridge: Create drm_bridge_chain_xx() wrappers
  drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder
  drm/bridge: Introduce drm_bridge_chain_get_{first,last,next}_bridge()
  drm/bridge: Make the bridge chain a double-linked list
  drm/bridge: Add a drm_bridge_state object
  drm/bridge: Patch atomic hooks to take a drm_bridge_state
  drm/bridge: Add an ->atomic_check() hook
  drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper
  drm/bridge: Add the necessary bits to support bus format negotiation
  drm/imx: pd: Use bus format/flags provided by the bridge when
    available
  drm/bridge: lvds-encoder: Add a way to support custom ->atomic_check()
    implem
  drm/bridge: lvds-encoder: Implement bus format negotiation for
    sn75lvds83
  drm/panel: simple: Add support for Toshiba LTA089AC29000 panel
  ARM: dts: imx: imx51-zii-rdu1: Fix the display pipeline definition

 .../display/panel/toshiba,lt089ac29000.txt    |   5 +-
 arch/arm/boot/dts/imx51-zii-rdu1.dts          |  24 +-
 drivers/gpu/drm/arc/arcpgu_hdmi.c             |   1 +
 drivers/gpu/drm/bridge/analogix-anx78xx.c     |   1 +
 .../drm/bridge/analogix/analogix_dp_core.c    |  13 +-
 drivers/gpu/drm/bridge/dumb-vga-dac.c         |   1 +
 drivers/gpu/drm/bridge/lvds-encoder.c         |  75 ++
 .../bridge/megachips-stdpxxxx-ge-b850v3-fw.c  |   1 +
 drivers/gpu/drm/bridge/nxp-ptn3460.c          |   1 +
 drivers/gpu/drm/bridge/panel.c                |   1 +
 drivers/gpu/drm/bridge/parade-ps8622.c        |   1 +
 drivers/gpu/drm/bridge/sii902x.c              |   1 +
 drivers/gpu/drm/bridge/sii9234.c              |   1 +
 drivers/gpu/drm/bridge/sil-sii8620.c          |   1 +
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     |   1 +
 drivers/gpu/drm/bridge/tc358764.c             |   1 +
 drivers/gpu/drm/bridge/tc358767.c             |   1 +
 drivers/gpu/drm/bridge/ti-sn65dsi86.c         |   1 +
 drivers/gpu/drm/bridge/ti-tfp410.c            |   1 +
 drivers/gpu/drm/drm_atomic.c                  |  40 +
 drivers/gpu/drm/drm_atomic_helper.c           |  46 +-
 drivers/gpu/drm/drm_bridge.c                  | 794 ++++++++++++++----
 drivers/gpu/drm/drm_crtc_helper.c             |  46 +-
 drivers/gpu/drm/drm_encoder.c                 |  16 +-
 drivers/gpu/drm/drm_probe_helper.c            |   3 +-
 drivers/gpu/drm/drm_simple_kms_helper.c       |   1 +
 drivers/gpu/drm/exynos/exynos_dp.c            |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_dsi.c       |  18 +-
 drivers/gpu/drm/exynos/exynos_drm_mic.c       |   1 +
 drivers/gpu/drm/exynos/exynos_hdmi.c          |   1 +
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c     |   1 +
 drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c  |   1 +
 drivers/gpu/drm/i2c/tda998x_drv.c             |   1 +
 drivers/gpu/drm/imx/imx-ldb.c                 |   1 +
 drivers/gpu/drm/imx/parallel-display.c        |  29 +-
 drivers/gpu/drm/ingenic/ingenic-drm.c         |   1 +
 drivers/gpu/drm/mediatek/mtk_dpi.c            |   1 +
 drivers/gpu/drm/mediatek/mtk_dsi.c            |   1 +
 drivers/gpu/drm/mediatek/mtk_hdmi.c           |   7 +-
 drivers/gpu/drm/msm/dsi/dsi.h                 |   1 +
 drivers/gpu/drm/msm/edp/edp.c                 |   4 +-
 drivers/gpu/drm/msm/edp/edp.h                 |   1 +
 drivers/gpu/drm/msm/edp/edp_bridge.c          |   2 +-
 drivers/gpu/drm/msm/hdmi/hdmi.c               |   4 +-
 drivers/gpu/drm/msm/hdmi/hdmi.h               |   2 +
 drivers/gpu/drm/omapdrm/dss/output.c          |   1 +
 drivers/gpu/drm/omapdrm/omap_drv.c            |   8 +-
 drivers/gpu/drm/omapdrm/omap_encoder.c        |   4 +-
 drivers/gpu/drm/panel/panel-simple.c          |  36 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c        |  10 +-
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c     |   1 +
 drivers/gpu/drm/rockchip/rockchip_lvds.c      |   1 +
 drivers/gpu/drm/rockchip/rockchip_rgb.c       |   1 +
 drivers/gpu/drm/sti/sti_dvo.c                 |   1 +
 drivers/gpu/drm/sti/sti_hda.c                 |   1 +
 drivers/gpu/drm/sti/sti_hdmi.c                |   1 +
 drivers/gpu/drm/sun4i/sun4i_lvds.c            |   1 +
 drivers/gpu/drm/sun4i/sun4i_rgb.c             |   1 +
 drivers/gpu/drm/sun4i/sun4i_tcon.c            |   1 +
 drivers/gpu/drm/tilcdc/tilcdc_external.c      |   1 +
 drivers/gpu/drm/vc4/vc4_dsi.c                 |  38 +-
 include/drm/drm_atomic.h                      |   3 +
 include/drm/drm_bridge.h                      | 252 +++++-
 include/drm/drm_crtc.h                        |   1 -
 include/drm/drm_encoder.h                     |  19 +-
 65 files changed, 1242 insertions(+), 297 deletions(-)

-- 
2.21.0

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

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

* [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 18:05   ` Sam Ravnborg
  2019-08-20 18:53   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially Boris Brezillon
                   ` (18 subsequent siblings)
  19 siblings, 2 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

We are about to add a drm_bridge_state that inherits from
drm_private_state which is defined in drm_atomic.h. Problem is,
drm_atomic.h includes drm_crtc.h which in turn includes drm_bridge.h,
leading to "drm_private_state has incomplete type" error.

Let's force all users of the drm_bridge API to explicitly include
drm_bridge.h.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/arc/arcpgu_hdmi.c                        | 1 +
 drivers/gpu/drm/bridge/analogix-anx78xx.c                | 1 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c       | 1 +
 drivers/gpu/drm/bridge/dumb-vga-dac.c                    | 1 +
 drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 1 +
 drivers/gpu/drm/bridge/nxp-ptn3460.c                     | 1 +
 drivers/gpu/drm/bridge/panel.c                           | 1 +
 drivers/gpu/drm/bridge/parade-ps8622.c                   | 1 +
 drivers/gpu/drm/bridge/sii902x.c                         | 1 +
 drivers/gpu/drm/bridge/sii9234.c                         | 1 +
 drivers/gpu/drm/bridge/sil-sii8620.c                     | 1 +
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c                | 1 +
 drivers/gpu/drm/bridge/tc358764.c                        | 1 +
 drivers/gpu/drm/bridge/tc358767.c                        | 1 +
 drivers/gpu/drm/bridge/ti-sn65dsi86.c                    | 1 +
 drivers/gpu/drm/bridge/ti-tfp410.c                       | 1 +
 drivers/gpu/drm/drm_atomic_helper.c                      | 1 +
 drivers/gpu/drm/drm_crtc_helper.c                        | 1 +
 drivers/gpu/drm/drm_encoder.c                            | 1 +
 drivers/gpu/drm/drm_probe_helper.c                       | 1 +
 drivers/gpu/drm/drm_simple_kms_helper.c                  | 1 +
 drivers/gpu/drm/exynos/exynos_dp.c                       | 1 +
 drivers/gpu/drm/exynos/exynos_drm_dsi.c                  | 1 +
 drivers/gpu/drm/exynos/exynos_drm_mic.c                  | 1 +
 drivers/gpu/drm/exynos/exynos_hdmi.c                     | 1 +
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c                | 1 +
 drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c             | 1 +
 drivers/gpu/drm/i2c/tda998x_drv.c                        | 1 +
 drivers/gpu/drm/imx/imx-ldb.c                            | 1 +
 drivers/gpu/drm/imx/parallel-display.c                   | 1 +
 drivers/gpu/drm/ingenic/ingenic-drm.c                    | 1 +
 drivers/gpu/drm/mediatek/mtk_dpi.c                       | 1 +
 drivers/gpu/drm/mediatek/mtk_dsi.c                       | 1 +
 drivers/gpu/drm/mediatek/mtk_hdmi.c                      | 1 +
 drivers/gpu/drm/msm/dsi/dsi.h                            | 1 +
 drivers/gpu/drm/msm/edp/edp.h                            | 1 +
 drivers/gpu/drm/msm/hdmi/hdmi.h                          | 2 ++
 drivers/gpu/drm/omapdrm/dss/output.c                     | 1 +
 drivers/gpu/drm/omapdrm/omap_drv.c                       | 1 +
 drivers/gpu/drm/omapdrm/omap_encoder.c                   | 1 +
 drivers/gpu/drm/rcar-du/rcar_du_encoder.c                | 1 +
 drivers/gpu/drm/rockchip/rockchip_lvds.c                 | 1 +
 drivers/gpu/drm/rockchip/rockchip_rgb.c                  | 1 +
 drivers/gpu/drm/sti/sti_dvo.c                            | 1 +
 drivers/gpu/drm/sti/sti_hda.c                            | 1 +
 drivers/gpu/drm/sti/sti_hdmi.c                           | 1 +
 drivers/gpu/drm/sun4i/sun4i_lvds.c                       | 1 +
 drivers/gpu/drm/sun4i/sun4i_rgb.c                        | 1 +
 drivers/gpu/drm/sun4i/sun4i_tcon.c                       | 1 +
 drivers/gpu/drm/tilcdc/tilcdc_external.c                 | 1 +
 drivers/gpu/drm/vc4/vc4_dsi.c                            | 1 +
 include/drm/drm_crtc.h                                   | 1 -
 52 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c
index 98aac743cc26..8fd7094beece 100644
--- a/drivers/gpu/drm/arc/arcpgu_hdmi.c
+++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
  */
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_encoder.h>
 #include <drm/drm_device.h>
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c
index 3c7cc5af735c..e3f4fd2a5ad4 100644
--- a/drivers/gpu/drm/bridge/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_edid.h>
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index f2f7f69d6cc3..b096a7a75c14 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -21,6 +21,7 @@
 #include <drm/bridge/analogix_dp.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
index 8ef6539ae78a..a974077913bf 100644
--- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
+++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
@@ -12,6 +12,7 @@
 #include <linux/regulator/consumer.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
index 6e81e5db57f2..e8a49f6146c6 100644
--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -25,6 +25,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
index d4a1cc5052c3..57ff01339559 100644
--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index b12ae3a4c5f1..6cffeb4a42f2 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -5,6 +5,7 @@
  */
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_encoder.h>
 #include <drm/drm_modeset_helper_vtables.h>
diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
index 93c68e2e9484..b7a72dfdcac3 100644
--- a/drivers/gpu/drm/bridge/parade-ps8622.c
+++ b/drivers/gpu/drm/bridge/parade-ps8622.c
@@ -17,6 +17,7 @@
 #include <linux/regulator/consumer.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 38f75ac580df..b70e8c5cf2e1 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -20,6 +20,7 @@
 #include <linux/clk.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c
index 25d4ad8c7ad6..ad00d841ed9e 100644
--- a/drivers/gpu/drm/bridge/sii9234.c
+++ b/drivers/gpu/drm/bridge/sii9234.c
@@ -13,6 +13,7 @@
  *    Dharam Kumar <dharam.kr@samsung.com>
  */
 #include <drm/bridge/mhl.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index bd3165ee5354..14643923a721 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -9,6 +9,7 @@
 #include <asm/unaligned.h>
 
 #include <drm/bridge/mhl.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder.h>
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 83b94b66e464..b4901b174a90 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -26,6 +26,7 @@
 
 #include <drm/bridge/dw_hdmi.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
 #include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
index 170f162ffa55..db298f550a5a 100644
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -16,6 +16,7 @@
 #include <video/mipi_display.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_mipi_dsi.h>
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 42f03a985ac0..02c172151165 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 0a580957c8cf..43abf01ebd4c 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -17,6 +17,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index 61cc2354ef1b..aa3198dc9903 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index aa16ea17ff9b..4706439fb490 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -30,6 +30,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_uapi.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_device.h>
 #include <drm/drm_plane_helper.h>
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 6dd49a60deac..fa3694836c22 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -36,6 +36,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_uapi.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_drv.h>
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 7fb47b7b8b44..80d88a55302e 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -22,6 +22,7 @@
 
 #include <linux/export.h>
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_encoder.h>
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index ef2c468205a2..351cbc40f0f8 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -32,6 +32,7 @@
 #include <linux/export.h>
 #include <linux/moduleparam.h>
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index b11910f14c46..046055719245 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -8,6 +8,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 3a0f0ba8c63a..1e6aa24bf45e 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -19,6 +19,7 @@
 
 #include <drm/bridge/analogix_dp.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 6926cee91b36..72726f2c7a9f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -24,6 +24,7 @@
 #include <video/videomode.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index b78e8c5ba553..f41d75923557 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -21,6 +21,7 @@
 #include <video/of_videomode.h>
 #include <video/videomode.h>
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_encoder.h>
 #include <drm/drm_print.h>
 
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index bc1565f1822a..2e3795c2c794 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -34,6 +34,7 @@
 #include <media/cec-notifier.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
index 279d83eaffc0..11ff06c81dd8 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -9,6 +9,7 @@
 #include <linux/of_graph.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index 5bf8138941de..bdcf9c6ae9e9 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_device.h>
 #include <drm/drm_encoder_slave.h>
 #include <drm/drm_mipi_dsi.h>
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 61e042918a7f..b578189b908c 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -15,6 +15,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
 #include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index db461b6a257f..96e9f031b713 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -20,6 +20,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 2e51b2fade75..35f20edab9fd 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -13,6 +13,7 @@
 #include <video/of_display_timing.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.c b/drivers/gpu/drm/ingenic/ingenic-drm.c
index ce1fae3a78a9..1daa1378fc36 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm.c
@@ -13,6 +13,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_drv.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index be6d95c5ff25..01fa8b8d763d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -17,6 +17,7 @@
 #include <video/videomode.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_of.h>
 
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 224afb666881..a413f5ff442d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -16,6 +16,7 @@
 #include <video/videomode.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index ce91b61364eb..c79b1f855d89 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -23,6 +23,7 @@
 #include <sound/hdmi-codec.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 0da8a4e428ad..eff1a4c61258 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -9,6 +9,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/msm/edp/edp.h b/drivers/gpu/drm/msm/edp/edp.h
index f2c17858a703..eb34243dad53 100644
--- a/drivers/gpu/drm/msm/edp/edp.h
+++ b/drivers/gpu/drm/msm/edp/edp.h
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_dp_helper.h>
 
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 982865866a29..c681a9e22484 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -7,6 +7,8 @@
 #ifndef __HDMI_CONNECTOR_H__
 #define __HDMI_CONNECTOR_H__
 
+#include <drm/drm_bridge.h>
+
 #include <linux/i2c.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
index de0f882f0f7b..de500bb05bdc 100644
--- a/drivers/gpu/drm/omapdrm/dss/output.c
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
@@ -11,6 +11,7 @@
 #include <linux/of.h>
 #include <linux/of_graph.h>
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_panel.h>
 
 #include "dss.h"
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 9f652d2e7af1..224ec6fdc800 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -11,6 +11,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_file.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
index 6fe14111cd95..24bbe9f2a32e 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -6,6 +6,7 @@
 
 #include <linux/list.h>
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_modeset_helper_vtables.h>
 #include <drm/drm_edid.h>
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index 0f00bdfe2366..3a1139b725c0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -9,6 +9,7 @@
 
 #include <linux/export.h>
 
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_modeset_helper_vtables.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 64aefa856896..8a4c9af0ba73 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -16,6 +16,7 @@
 #include <linux/regmap.h>
 #include <linux/reset.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index 89e0bb0fe0ab..db1be1f3925c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -9,6 +9,7 @@
 #include <linux/of_graph.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index e55870190bf5..0a4f00253f39 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_device.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 94e404f13234..9d3fd6370a29 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -12,6 +12,7 @@
 #include <linux/seq_file.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_device.h>
 #include <drm/drm_file.h>
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 9862c322f0c4..84318d0832a0 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -14,6 +14,7 @@
 #include <linux/reset.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_edid.h>
diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c
index 7fbf425acb55..25ab2ef6d545 100644
--- a/drivers/gpu/drm/sun4i/sun4i_lvds.c
+++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c
@@ -7,6 +7,7 @@
 #include <linux/clk.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index aac56983f208..e74b9eddca01 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 690aeb822704..eb187da56aba 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -16,6 +16,7 @@
 #include <linux/reset.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_encoder.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index 43d756b7810e..4fc10838de80 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -8,6 +8,7 @@
 #include <linux/of_graph.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_of.h>
 
 #include "tilcdc_drv.h"
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index c78fa8144776..3f63943e5472 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -31,6 +31,7 @@
 #include <linux/pm_runtime.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 7d14c11bdc0a..7e2963cad543 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -41,7 +41,6 @@
 #include <drm/drm_connector.h>
 #include <drm/drm_device.h>
 #include <drm/drm_property.h>
-#include <drm/drm_bridge.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_plane.h>
 #include <drm/drm_blend.h>
-- 
2.21.0

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

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

* [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-20 19:05   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 03/19] drm/vc4: Get rid of the dsi->bridge field Boris Brezillon
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

The VC4 and Exynos DSI encoder drivers need a custom enable/disable
sequence and manually set encoder->bridge to NULL to prevent the core
from calling the bridge hooks.

Let's provide a more official way to support custom bridge/encoder
enable/disable sequences.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 13 +++++++---
 drivers/gpu/drm/drm_crtc_helper.c   | 38 ++++++++++++++++++-----------
 include/drm/drm_encoder.h           |  9 +++++++
 3 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 4706439fb490..15ea61877122 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1030,7 +1030,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call disable hooks twice.
 		 */
-		drm_atomic_bridge_disable(encoder->bridge, old_state);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_atomic_bridge_disable(encoder->bridge, old_state);
 
 		/* Right function depends upon target state. */
 		if (funcs) {
@@ -1044,7 +1045,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
 		}
 
-		drm_atomic_bridge_post_disable(encoder->bridge, old_state);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_atomic_bridge_post_disable(encoder->bridge,
+						       old_state);
 	}
 
 	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -1342,7 +1345,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call enable hooks twice.
 		 */
-		drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
 
 		if (funcs) {
 			if (funcs->atomic_enable)
@@ -1353,7 +1357,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 				funcs->commit(encoder);
 		}
 
-		drm_atomic_bridge_enable(encoder->bridge, old_state);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_atomic_bridge_enable(encoder->bridge, old_state);
 	}
 
 	drm_atomic_helper_commit_writebacks(dev, old_state);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index fa3694836c22..87dae37fec12 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -160,14 +160,16 @@ drm_encoder_disable(struct drm_encoder *encoder)
 	if (!encoder_funcs)
 		return;
 
-	drm_bridge_disable(encoder->bridge);
+	if (!encoder->custom_bridge_enable_disable_seq)
+		drm_bridge_disable(encoder->bridge);
 
 	if (encoder_funcs->disable)
 		(*encoder_funcs->disable)(encoder);
 	else if (encoder_funcs->dpms)
 		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
 
-	drm_bridge_post_disable(encoder->bridge);
+	if (!encoder->custom_bridge_enable_disable_seq)
+		drm_bridge_post_disable(encoder->bridge);
 }
 
 static void __drm_helper_disable_unused_functions(struct drm_device *dev)
@@ -365,13 +367,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 		if (!encoder_funcs)
 			continue;
 
-		drm_bridge_disable(encoder->bridge);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_bridge_disable(encoder->bridge);
 
 		/* Disable the encoders as the first thing we do. */
 		if (encoder_funcs->prepare)
 			encoder_funcs->prepare(encoder);
 
-		drm_bridge_post_disable(encoder->bridge);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_bridge_post_disable(encoder->bridge);
 	}
 
 	drm_crtc_prepare_encoders(dev);
@@ -414,12 +418,14 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 		if (!encoder_funcs)
 			continue;
 
-		drm_bridge_pre_enable(encoder->bridge);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_bridge_pre_enable(encoder->bridge);
 
 		if (encoder_funcs->commit)
 			encoder_funcs->commit(encoder);
 
-		drm_bridge_enable(encoder->bridge);
+		if (!encoder->custom_bridge_enable_disable_seq)
+			drm_bridge_enable(encoder->bridge);
 	}
 
 	/* Calculate and store various constants which
@@ -825,18 +831,22 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
 	if (!encoder_funcs)
 		return;
 
-	if (mode == DRM_MODE_DPMS_ON)
-		drm_bridge_pre_enable(bridge);
-	else
-		drm_bridge_disable(bridge);
+	if (!encoder->custom_bridge_enable_disable_seq) {
+		if (mode == DRM_MODE_DPMS_ON)
+			drm_bridge_pre_enable(bridge);
+		else
+			drm_bridge_disable(bridge);
+	}
 
 	if (encoder_funcs->dpms)
 		encoder_funcs->dpms(encoder, mode);
 
-	if (mode == DRM_MODE_DPMS_ON)
-		drm_bridge_enable(bridge);
-	else
-		drm_bridge_post_disable(bridge);
+	if (!encoder->custom_bridge_enable_disable_seq) {
+		if (mode == DRM_MODE_DPMS_ON)
+			drm_bridge_enable(bridge);
+		else
+			drm_bridge_post_disable(bridge);
+	}
 }
 
 static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 70cfca03d812..d986ff1197ce 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -175,6 +175,15 @@ struct drm_encoder {
 	struct drm_bridge *bridge;
 	const struct drm_encoder_funcs *funcs;
 	const struct drm_encoder_helper_funcs *helper_private;
+
+	/**
+	 * @custom_bridge_enable_disable_seq: Set to true if the encoder needs
+	 * a custom bridge/encoder enable/disable sequence. In that case the
+	 * driver is responsible for calling the
+	 * drm[_atomic]_bridge_{pre_enable,enable,disable,post_disable}()
+	 * functions as part of its encoder enable/disable handling.
+	 */
+	uint32_t custom_bridge_enable_disable_seq : 1;
 };
 
 #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
-- 
2.21.0

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

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

* [PATCH RFC 03/19] drm/vc4: Get rid of the dsi->bridge field
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 20:31   ` Eric Anholt
  2019-08-08 15:11 ` [PATCH RFC 04/19] drm/exynos: Get rid of exynos_dsi->out_bridge Boris Brezillon
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Now that we have an official way to request custom encoder/bridge
enable/disable sequences we can get rid of the extra ->bridge field
and use the encoder one.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 3f63943e5472..b670ca473786 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -498,7 +498,6 @@ struct vc4_dsi {
 
 	struct mipi_dsi_host dsi_host;
 	struct drm_encoder *encoder;
-	struct drm_bridge *bridge;
 
 	void __iomem *regs;
 
@@ -753,9 +752,9 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
 	struct vc4_dsi *dsi = vc4_encoder->dsi;
 	struct device *dev = &dsi->pdev->dev;
 
-	drm_bridge_disable(dsi->bridge);
+	drm_bridge_disable(encoder->bridge);
 	vc4_dsi_ulps(dsi, true);
-	drm_bridge_post_disable(dsi->bridge);
+	drm_bridge_post_disable(encoder->bridge);
 
 	clk_disable_unprepare(dsi->pll_phy_clock);
 	clk_disable_unprepare(dsi->escape_clock);
@@ -1055,7 +1054,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
 
 	vc4_dsi_ulps(dsi, false);
 
-	drm_bridge_pre_enable(dsi->bridge);
+	drm_bridge_pre_enable(encoder->bridge);
 
 	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
 		DSI_PORT_WRITE(DISP0_CTRL,
@@ -1072,7 +1071,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
 			       DSI_DISP0_ENABLE);
 	}
 
-	drm_bridge_enable(dsi->bridge);
+	drm_bridge_enable(encoder->bridge);
 
 	if (debug_dump_regs) {
 		struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
@@ -1445,6 +1444,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 	struct vc4_dev *vc4 = to_vc4_dev(drm);
 	struct vc4_dsi *dsi = dev_get_drvdata(dev);
 	struct vc4_dsi_encoder *vc4_dsi_encoder;
+	struct drm_bridge *bridge = NULL;
 	struct drm_panel *panel;
 	const struct of_device_id *match;
 	dma_cap_mask_t dma_mask;
@@ -1561,7 +1561,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 	}
 
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
-					  &panel, &dsi->bridge);
+					  &panel, &bridge);
 	if (ret) {
 		/* If the bridge or panel pointed by dev->of_node is not
 		 * enabled, just return 0 here so that we don't prevent the DRM
@@ -1576,10 +1576,10 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 	}
 
 	if (panel) {
-		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
-							DRM_MODE_CONNECTOR_DSI);
-		if (IS_ERR(dsi->bridge))
-			return PTR_ERR(dsi->bridge);
+		bridge = devm_drm_panel_bridge_add(dev, panel,
+						   DRM_MODE_CONNECTOR_DSI);
+		if (IS_ERR(bridge))
+			return PTR_ERR(bridge);
 	}
 
 	/* The esc clock rate is supposed to always be 100Mhz. */
@@ -1600,17 +1600,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 			 DRM_MODE_ENCODER_DSI, NULL);
 	drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
 
-	ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
-	if (ret) {
-		dev_err(dev, "bridge attach failed: %d\n", ret);
-		return ret;
-	}
 	/* Disable the atomic helper calls into the bridge.  We
 	 * manually call the bridge pre_enable / enable / etc. calls
 	 * from our driver, since we need to sequence them within the
 	 * encoder's enable/disable paths.
 	 */
-	dsi->encoder->bridge = NULL;
+	dsi->encoder->custom_bridge_enable_disable_seq = 1;
+
+	ret = drm_bridge_attach(dsi->encoder, bridge, NULL);
+	if (ret) {
+		dev_err(dev, "bridge attach failed: %d\n", ret);
+		return ret;
+	}
 
 	if (dsi->port == 0)
 		vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset);
@@ -1629,7 +1630,7 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
 	struct vc4_dev *vc4 = to_vc4_dev(drm);
 	struct vc4_dsi *dsi = dev_get_drvdata(dev);
 
-	if (dsi->bridge)
+	if (dsi->encoder->bridge)
 		pm_runtime_disable(dev);
 
 	vc4_dsi_encoder_destroy(dsi->encoder);
-- 
2.21.0

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

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

* [PATCH RFC 04/19] drm/exynos: Get rid of exynos_dsi->out_bridge
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (2 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 03/19] drm/vc4: Get rid of the dsi->bridge field Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next Boris Brezillon
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Now that we have an official way to request custom encoder/bridge
enable/disable sequences we can get rid of the extra ->out_bridge field
and use the encoder one.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 72726f2c7a9f..8593c87bdf96 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -255,7 +255,6 @@ struct exynos_dsi {
 	struct mipi_dsi_host dsi_host;
 	struct drm_connector connector;
 	struct drm_panel *panel;
-	struct drm_bridge *out_bridge;
 	struct device *dev;
 
 	void __iomem *reg_base;
@@ -1390,7 +1389,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
 		if (ret < 0)
 			goto err_put_sync;
 	} else {
-		drm_bridge_pre_enable(dsi->out_bridge);
+		drm_bridge_pre_enable(encoder->bridge);
 	}
 
 	exynos_dsi_set_display_mode(dsi);
@@ -1401,7 +1400,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
 		if (ret < 0)
 			goto err_display_disable;
 	} else {
-		drm_bridge_enable(dsi->out_bridge);
+		drm_bridge_enable(encoder->bridge);
 	}
 
 	dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
@@ -1426,10 +1425,10 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
 	dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
 
 	drm_panel_disable(dsi->panel);
-	drm_bridge_disable(dsi->out_bridge);
+	drm_bridge_disable(encoder->bridge);
 	exynos_dsi_set_display_enable(dsi, false);
 	drm_panel_unprepare(dsi->panel);
-	drm_bridge_post_disable(dsi->out_bridge);
+	drm_bridge_post_disable(encoder->bridge);
 	dsi->state &= ~DSIM_STATE_ENABLED;
 	pm_runtime_put_sync(dsi->dev);
 }
@@ -1521,8 +1520,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 	out_bridge  = of_drm_find_bridge(device->dev.of_node);
 	if (out_bridge) {
 		drm_bridge_attach(encoder, out_bridge, NULL);
-		dsi->out_bridge = out_bridge;
-		encoder->bridge = NULL;
 	} else {
 		int ret = exynos_dsi_create_connector(encoder);
 
@@ -1584,10 +1581,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
 		dsi->panel = NULL;
 		dsi->connector.status = connector_status_disconnected;
 		mutex_unlock(&drm->mode_config.mutex);
-	} else {
-		if (dsi->out_bridge->funcs->detach)
-			dsi->out_bridge->funcs->detach(dsi->out_bridge);
-		dsi->out_bridge = NULL;
 	}
 
 	if (drm->mode_config.poll_enabled)
@@ -1686,7 +1679,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 
 	drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
-
+	encoder->custom_bridge_enable_disable_seq = 1;
 	drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
 
 	ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
-- 
2.21.0

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

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

* [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (3 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 04/19] drm/exynos: Get rid of exynos_dsi->out_bridge Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 21:04   ` Boris Brezillon
  2019-08-21 14:01   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 06/19] drm/bridge: Create drm_bridge_chain_xx() wrappers Boris Brezillon
                   ` (14 subsequent siblings)
  19 siblings, 2 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

bridge->next is only points to the new bridge if drm_bridge_attach()
succeeds. No need to reset it manually here.

Note that this change is part of the attempt to make the bridge chain
a double-linked list. In order to do that we must patch all drivers
manipulating the bridge->next field.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/exynos/exynos_dp.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 1e6aa24bf45e..4785885c0f4f 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -110,7 +110,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
 		if (ret) {
 			DRM_DEV_ERROR(dp->dev,
 				      "Failed to attach bridge to drm\n");
-			bridge->next = NULL;
 			return ret;
 		}
 	}
-- 
2.21.0

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

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

* [PATCH RFC 06/19] drm/bridge: Create drm_bridge_chain_xx() wrappers
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (4 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-21 14:45   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 07/19] drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder Boris Brezillon
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

DRM bridges should not be operated independently. Let's rename the
drm_bridge_xxx() helpers that take the first bridge of the chain and
iterate over the whole chain into drm_bridge_chain_xx(). We also pass
it the encoder containing the bridge chain instead of the dereferencing
encoder->bridge.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_atomic_helper.c     |  19 +-
 drivers/gpu/drm/drm_bridge.c            | 365 +++++++++++++-----------
 drivers/gpu/drm/drm_crtc_helper.c       |  27 +-
 drivers/gpu/drm/drm_probe_helper.c      |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_dsi.c |   8 +-
 drivers/gpu/drm/mediatek/mtk_hdmi.c     |   4 +-
 drivers/gpu/drm/vc4/vc4_dsi.c           |   8 +-
 include/drm/drm_bridge.h                |  64 +++--
 8 files changed, 273 insertions(+), 224 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 15ea61877122..0deb54099570 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -445,8 +445,9 @@ mode_fixup(struct drm_atomic_state *state)
 		encoder = new_conn_state->best_encoder;
 		funcs = encoder->helper_private;
 
-		ret = drm_bridge_mode_fixup(encoder->bridge, &new_crtc_state->mode,
-				&new_crtc_state->adjusted_mode);
+		ret = drm_bridge_chain_mode_fixup(encoder,
+					&new_crtc_state->mode,
+					&new_crtc_state->adjusted_mode);
 		if (!ret) {
 			DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
 			return -EINVAL;
@@ -511,7 +512,7 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector,
 		return ret;
 	}
 
-	ret = drm_bridge_mode_valid(encoder->bridge, mode);
+	ret = drm_bridge_chain_mode_valid(encoder, mode);
 	if (ret != MODE_OK) {
 		DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n");
 		return ret;
@@ -1031,7 +1032,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 		 * it away), so we won't call disable hooks twice.
 		 */
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_atomic_bridge_disable(encoder->bridge, old_state);
+			drm_atomic_bridge_chain_disable(encoder, old_state);
 
 		/* Right function depends upon target state. */
 		if (funcs) {
@@ -1046,8 +1047,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 		}
 
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_atomic_bridge_post_disable(encoder->bridge,
-						       old_state);
+			drm_atomic_bridge_chain_post_disable(encoder,
+							     old_state);
 	}
 
 	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -1228,7 +1229,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 			funcs->mode_set(encoder, mode, adjusted_mode);
 		}
 
-		drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
+		drm_bridge_chain_mode_set(encoder, mode, adjusted_mode);
 	}
 }
 
@@ -1346,7 +1347,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 		 * it away), so we won't call enable hooks twice.
 		 */
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
+			drm_atomic_bridge_chain_pre_enable(encoder, old_state);
 
 		if (funcs) {
 			if (funcs->atomic_enable)
@@ -1358,7 +1359,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 		}
 
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_atomic_bridge_enable(encoder->bridge, old_state);
+			drm_atomic_bridge_chain_enable(encoder, old_state);
 	}
 
 	drm_atomic_helper_commit_writebacks(dev, old_state);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index cba537c99e43..2bf9a19e11bf 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -171,24 +171,9 @@ void drm_bridge_detach(struct drm_bridge *bridge)
  * For detailed specification of the bridge callbacks see &drm_bridge_funcs.
  */
 
-/**
- * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the
- *			   encoder chain
- * @bridge: bridge control structure
- * @mode: desired mode to be set for the bridge
- * @adjusted_mode: updated mode that works for this bridge
- *
- * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the
- * encoder chain, starting from the first bridge to the last.
- *
- * Note: the bridge passed should be the one closest to the encoder
- *
- * RETURNS:
- * true on success, false on failure
- */
-bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
-			const struct drm_display_mode *mode,
-			struct drm_display_mode *adjusted_mode)
+static bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
+				  const struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
 {
 	bool ret = true;
 
@@ -202,25 +187,10 @@ bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
 
 	return ret;
 }
-EXPORT_SYMBOL(drm_bridge_mode_fixup);
 
-/**
- * drm_bridge_mode_valid - validate the mode against all bridges in the
- * 			   encoder chain.
- * @bridge: bridge control structure
- * @mode: desired mode to be validated
- *
- * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
- * chain, starting from the first bridge to the last. If at least one bridge
- * does not accept the mode the function returns the error code.
- *
- * Note: the bridge passed should be the one closest to the encoder.
- *
- * RETURNS:
- * MODE_OK on success, drm_mode_status Enum error code on failure
- */
-enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
-					   const struct drm_display_mode *mode)
+static enum drm_mode_status
+drm_bridge_mode_valid(struct drm_bridge *bridge,
+		      const struct drm_display_mode *mode)
 {
 	enum drm_mode_status ret = MODE_OK;
 
@@ -235,19 +205,8 @@ enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
 
 	return drm_bridge_mode_valid(bridge->next, mode);
 }
-EXPORT_SYMBOL(drm_bridge_mode_valid);
 
-/**
- * drm_bridge_disable - disables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called before
- * calling the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_disable(struct drm_bridge *bridge)
+static void drm_bridge_disable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
@@ -257,19 +216,8 @@ void drm_bridge_disable(struct drm_bridge *bridge)
 	if (bridge->funcs->disable)
 		bridge->funcs->disable(bridge);
 }
-EXPORT_SYMBOL(drm_bridge_disable);
 
-/**
- * drm_bridge_post_disable - cleans up after disabling all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
- * encoder chain, starting from the first bridge to the last. These are called
- * after completing the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_post_disable(struct drm_bridge *bridge)
+static void drm_bridge_post_disable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
@@ -279,23 +227,10 @@ void drm_bridge_post_disable(struct drm_bridge *bridge)
 
 	drm_bridge_post_disable(bridge->next);
 }
-EXPORT_SYMBOL(drm_bridge_post_disable);
 
-/**
- * drm_bridge_mode_set - set proposed mode for all bridges in the
- *			 encoder chain
- * @bridge: bridge control structure
- * @mode: desired mode to be set for the bridge
- * @adjusted_mode: updated mode that works for this bridge
- *
- * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
- * encoder chain, starting from the first bridge to the last.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_mode_set(struct drm_bridge *bridge,
-			 const struct drm_display_mode *mode,
-			 const struct drm_display_mode *adjusted_mode)
+static void drm_bridge_mode_set(struct drm_bridge *bridge,
+				const struct drm_display_mode *mode,
+				const struct drm_display_mode *adjusted_mode)
 {
 	if (!bridge)
 		return;
@@ -305,20 +240,8 @@ void drm_bridge_mode_set(struct drm_bridge *bridge,
 
 	drm_bridge_mode_set(bridge->next, mode, adjusted_mode);
 }
-EXPORT_SYMBOL(drm_bridge_mode_set);
 
-/**
- * drm_bridge_pre_enable - prepares for enabling all
- *			   bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called
- * before calling the encoder's commit op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_pre_enable(struct drm_bridge *bridge)
+static void drm_bridge_pre_enable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
@@ -328,19 +251,8 @@ void drm_bridge_pre_enable(struct drm_bridge *bridge)
 	if (bridge->funcs->pre_enable)
 		bridge->funcs->pre_enable(bridge);
 }
-EXPORT_SYMBOL(drm_bridge_pre_enable);
 
-/**
- * drm_bridge_enable - enables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
- * chain, starting from the first bridge to the last. These are called
- * after completing the encoder's commit op.
- *
- * Note that the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_enable(struct drm_bridge *bridge)
+static void drm_bridge_enable(struct drm_bridge *bridge)
 {
 	if (!bridge)
 		return;
@@ -350,22 +262,127 @@ void drm_bridge_enable(struct drm_bridge *bridge)
 
 	drm_bridge_enable(bridge->next);
 }
-EXPORT_SYMBOL(drm_bridge_enable);
 
 /**
- * drm_atomic_bridge_disable - disables all bridges in the encoder chain
- * @bridge: bridge control structure
- * @state: atomic state being committed
+ * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the
+ *				 encoder chain
+ * @encoder: encoder object
+ * @mode: desired mode to be set for the bridge
+ * @adjusted_mode: updated mode that works for this bridge
  *
- * Calls &drm_bridge_funcs.atomic_disable (falls back on
- * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
- * starting from the last bridge to the first. These are called before calling
- * &drm_encoder_helper_funcs.atomic_disable
+ * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the
+ * encoder chain, starting from the first bridge to the last.
  *
- * Note: the bridge passed should be the one closest to the encoder
+ * RETURNS:
+ * true on success, false on failure
  */
-void drm_atomic_bridge_disable(struct drm_bridge *bridge,
-			       struct drm_atomic_state *state)
+bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
+{
+	return drm_bridge_mode_fixup(encoder->bridge, mode, adjusted_mode);
+}
+EXPORT_SYMBOL(drm_bridge_chain_mode_fixup);
+
+/**
+ * drm_bridge_chain_mode_valid - validate the mode against all bridges in the
+ *				 encoder chain.
+ * @encoder: encoder object
+ * @mode: desired mode to be validated
+ *
+ * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
+ * chain, starting from the first bridge to the last. If at least one bridge
+ * does not accept the mode the function returns the error code.
+ *
+ * RETURNS:
+ * MODE_OK on success, drm_mode_status Enum error code on failure
+ */
+enum drm_mode_status
+drm_bridge_chain_mode_valid(struct drm_encoder *encoder,
+			    const struct drm_display_mode *mode)
+{
+	return drm_bridge_mode_valid(encoder->bridge, mode);
+}
+EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
+
+/**
+ * drm_bridge_chain_disable - disables all bridges in the encoder chain
+ * @encoder: encoder object
+ *
+ * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
+ * chain, starting from the last bridge to the first. These are called before
+ * calling the encoder's prepare op.
+ */
+void drm_bridge_chain_disable(struct drm_encoder *encoder)
+{
+	drm_bridge_disable(encoder->bridge);
+}
+EXPORT_SYMBOL(drm_bridge_chain_disable);
+
+/**
+ * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
+ *				   encoder chain
+ * @encoder: encoder object
+ *
+ * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
+ * encoder chain, starting from the first bridge to the last. These are called
+ * after completing the encoder's prepare op.
+ */
+void drm_bridge_chain_post_disable(struct drm_encoder *encoder)
+{
+	drm_bridge_post_disable(encoder->bridge);
+}
+EXPORT_SYMBOL(drm_bridge_chain_post_disable);
+
+/**
+ * drm_bridge_chain_mode_set - set proposed mode for all bridges in the
+ *			       encoder chain
+ * @encoder: encoder object
+ * @mode: desired mode to be set for the encoder chain
+ * @adjusted_mode: updated mode that works for this encoder chain
+ *
+ * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
+ * encoder chain, starting from the first bridge to the last.
+ */
+void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
+			       const struct drm_display_mode *mode,
+			       const struct drm_display_mode *adjusted_mode)
+{
+	drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
+}
+EXPORT_SYMBOL(drm_bridge_chain_mode_set);
+
+/**
+ * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
+ *				 encoder chain
+ * @encoder: encoder object
+ *
+ * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
+ * chain, starting from the last bridge to the first. These are called
+ * before calling the encoder's commit op.
+ */
+void drm_bridge_chain_pre_enable(struct drm_encoder *encoder)
+{
+	drm_bridge_pre_enable(encoder->bridge);
+}
+EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
+
+/**
+ * drm_bridge_chain_enable - enables all bridges in the encoder chain
+ * @encoder: encoder object
+ *
+ * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
+ * chain, starting from the first bridge to the last. These are called
+ * after completing the encoder's commit op.
+ */
+void drm_bridge_chain_enable(struct drm_encoder *encoder)
+{
+	drm_bridge_enable(encoder->bridge);
+}
+EXPORT_SYMBOL(drm_bridge_chain_enable);
+
+static void drm_atomic_bridge_disable(struct drm_bridge *bridge,
+				      struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
@@ -377,23 +394,9 @@ void drm_atomic_bridge_disable(struct drm_bridge *bridge,
 	else if (bridge->funcs->disable)
 		bridge->funcs->disable(bridge);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_disable);
 
-/**
- * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the
- *				    encoder chain
- * @bridge: bridge control structure
- * @state: atomic state being committed
- *
- * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
- * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
- * starting from the first bridge to the last. These are called after completing
- * &drm_encoder_helper_funcs.atomic_disable
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
-				    struct drm_atomic_state *state)
+static void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
+					   struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
@@ -405,23 +408,9 @@ void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
 
 	drm_atomic_bridge_post_disable(bridge->next, state);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_post_disable);
 
-/**
- * drm_atomic_bridge_pre_enable - prepares for enabling all bridges in the
- *				  encoder chain
- * @bridge: bridge control structure
- * @state: atomic state being committed
- *
- * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
- * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
- * starting from the last bridge to the first. These are called before calling
- * &drm_encoder_helper_funcs.atomic_enable
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
-				  struct drm_atomic_state *state)
+static void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
+					 struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
@@ -433,22 +422,9 @@ void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
 	else if (bridge->funcs->pre_enable)
 		bridge->funcs->pre_enable(bridge);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_pre_enable);
 
-/**
- * drm_atomic_bridge_enable - enables all bridges in the encoder chain
- * @bridge: bridge control structure
- * @state: atomic state being committed
- *
- * Calls &drm_bridge_funcs.atomic_enable (falls back on
- * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
- * starting from the first bridge to the last. These are called after completing
- * &drm_encoder_helper_funcs.atomic_enable
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_atomic_bridge_enable(struct drm_bridge *bridge,
-			      struct drm_atomic_state *state)
+static void drm_atomic_bridge_enable(struct drm_bridge *bridge,
+				     struct drm_atomic_state *state)
 {
 	if (!bridge)
 		return;
@@ -460,7 +436,76 @@ void drm_atomic_bridge_enable(struct drm_bridge *bridge,
 
 	drm_atomic_bridge_enable(bridge->next, state);
 }
-EXPORT_SYMBOL(drm_atomic_bridge_enable);
+
+/**
+ * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
+ * @encoder: encoder object
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.atomic_disable (falls back on
+ * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
+ * starting from the last bridge to the first. These are called before calling
+ * &drm_encoder_helper_funcs.atomic_disable
+ */
+void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
+				     struct drm_atomic_state *state)
+{
+	drm_atomic_bridge_disable(encoder->bridge, state);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
+
+/**
+ * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
+ *					  in the encoder chain
+ * @encoder: encoder object
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
+ * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
+ * starting from the first bridge to the last. These are called after completing
+ * &drm_encoder_helper_funcs.atomic_disable
+ */
+void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
+					  struct drm_atomic_state *state)
+{
+	drm_atomic_bridge_post_disable(encoder->bridge, state);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
+
+/**
+ * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
+ *					the encoder chain
+ * @encoder: encoder object
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
+ * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
+ * starting from the last bridge to the first. These are called before calling
+ * &drm_encoder_helper_funcs.atomic_enable
+ */
+void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
+					struct drm_atomic_state *state)
+{
+	drm_atomic_bridge_pre_enable(encoder->bridge, state);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
+
+/**
+ * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain
+ * @encoder: encoder object
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.atomic_enable (falls back on
+ * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
+ * starting from the first bridge to the last. These are called after completing
+ * &drm_encoder_helper_funcs.atomic_enable
+ */
+void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
+				    struct drm_atomic_state *state)
+{
+	drm_atomic_bridge_enable(encoder->bridge, state);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
 
 #ifdef CONFIG_OF
 /**
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 87dae37fec12..f8a361d396df 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -161,7 +161,7 @@ drm_encoder_disable(struct drm_encoder *encoder)
 		return;
 
 	if (!encoder->custom_bridge_enable_disable_seq)
-		drm_bridge_disable(encoder->bridge);
+		drm_bridge_chain_disable(encoder);
 
 	if (encoder_funcs->disable)
 		(*encoder_funcs->disable)(encoder);
@@ -169,7 +169,7 @@ drm_encoder_disable(struct drm_encoder *encoder)
 		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
 
 	if (!encoder->custom_bridge_enable_disable_seq)
-		drm_bridge_post_disable(encoder->bridge);
+		drm_bridge_chain_post_disable(encoder);
 }
 
 static void __drm_helper_disable_unused_functions(struct drm_device *dev)
@@ -329,8 +329,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 		if (!encoder_funcs)
 			continue;
 
-		ret = drm_bridge_mode_fixup(encoder->bridge,
-			mode, adjusted_mode);
+		ret = drm_bridge_chain_mode_fixup(encoder, mode,
+						  adjusted_mode);
 		if (!ret) {
 			DRM_DEBUG_KMS("Bridge fixup failed\n");
 			goto done;
@@ -368,14 +368,14 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 			continue;
 
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_bridge_disable(encoder->bridge);
+			drm_bridge_chain_disable(encoder);
 
 		/* Disable the encoders as the first thing we do. */
 		if (encoder_funcs->prepare)
 			encoder_funcs->prepare(encoder);
 
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_bridge_post_disable(encoder->bridge);
+			drm_bridge_chain_post_disable(encoder);
 	}
 
 	drm_crtc_prepare_encoders(dev);
@@ -403,7 +403,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 		if (encoder_funcs->mode_set)
 			encoder_funcs->mode_set(encoder, mode, adjusted_mode);
 
-		drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
+		drm_bridge_chain_mode_set(encoder, mode, adjusted_mode);
 	}
 
 	/* Now enable the clocks, plane, pipe, and connectors that we set up. */
@@ -419,13 +419,13 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 			continue;
 
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_bridge_pre_enable(encoder->bridge);
+			drm_bridge_chain_pre_enable(encoder);
 
 		if (encoder_funcs->commit)
 			encoder_funcs->commit(encoder);
 
 		if (!encoder->custom_bridge_enable_disable_seq)
-			drm_bridge_enable(encoder->bridge);
+			drm_bridge_chain_enable(encoder);
 	}
 
 	/* Calculate and store various constants which
@@ -824,7 +824,6 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
 /* Helper which handles bridge ordering around encoder dpms */
 static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
-	struct drm_bridge *bridge = encoder->bridge;
 	const struct drm_encoder_helper_funcs *encoder_funcs;
 
 	encoder_funcs = encoder->helper_private;
@@ -833,9 +832,9 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
 
 	if (!encoder->custom_bridge_enable_disable_seq) {
 		if (mode == DRM_MODE_DPMS_ON)
-			drm_bridge_pre_enable(bridge);
+			drm_bridge_chain_pre_enable(encoder);
 		else
-			drm_bridge_disable(bridge);
+			drm_bridge_chain_disable(encoder);
 	}
 
 	if (encoder_funcs->dpms)
@@ -843,9 +842,9 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
 
 	if (!encoder->custom_bridge_enable_disable_seq) {
 		if (mode == DRM_MODE_DPMS_ON)
-			drm_bridge_enable(bridge);
+			drm_bridge_chain_enable(encoder);
 		else
-			drm_bridge_post_disable(bridge);
+			drm_bridge_chain_post_disable(encoder);
 	}
 }
 
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 351cbc40f0f8..461199bc28c0 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -113,7 +113,7 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode,
 			continue;
 		}
 
-		ret = drm_bridge_mode_valid(encoder->bridge, mode);
+		ret = drm_bridge_chain_mode_valid(encoder, mode);
 		if (ret != MODE_OK) {
 			/* There is also no point in continuing for crtc check
 			 * here. */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 8593c87bdf96..9a96bc48b81f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1389,7 +1389,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
 		if (ret < 0)
 			goto err_put_sync;
 	} else {
-		drm_bridge_pre_enable(encoder->bridge);
+		drm_bridge_chain_pre_enable(encoder);
 	}
 
 	exynos_dsi_set_display_mode(dsi);
@@ -1400,7 +1400,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
 		if (ret < 0)
 			goto err_display_disable;
 	} else {
-		drm_bridge_enable(encoder->bridge);
+		drm_bridge_chain_enable(encoder);
 	}
 
 	dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
@@ -1425,10 +1425,10 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
 	dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
 
 	drm_panel_disable(dsi->panel);
-	drm_bridge_disable(encoder->bridge);
+	drm_bridge_chain_disable(encoder);
 	exynos_dsi_set_display_enable(dsi, false);
 	drm_panel_unprepare(dsi->panel);
-	drm_bridge_post_disable(encoder->bridge);
+	drm_bridge_chain_post_disable(encoder);
 	dsi->state &= ~DSIM_STATE_ENABLED;
 	pm_runtime_put_sync(dsi->dev);
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index c79b1f855d89..6ec3d2584539 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1247,8 +1247,8 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn,
 		struct drm_display_mode adjusted_mode;
 
 		drm_mode_copy(&adjusted_mode, mode);
-		if (!drm_bridge_mode_fixup(hdmi->bridge.next, mode,
-					   &adjusted_mode))
+		if (!drm_bridge_chain_mode_fixup(hdmi->bridge.encoder, mode,
+						 &adjusted_mode))
 			return MODE_BAD;
 	}
 
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index b670ca473786..d7cd720c4efa 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -752,9 +752,9 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
 	struct vc4_dsi *dsi = vc4_encoder->dsi;
 	struct device *dev = &dsi->pdev->dev;
 
-	drm_bridge_disable(encoder->bridge);
+	drm_bridge_chain_disable(encoder);
 	vc4_dsi_ulps(dsi, true);
-	drm_bridge_post_disable(encoder->bridge);
+	drm_bridge_chain_post_disable(encoder);
 
 	clk_disable_unprepare(dsi->pll_phy_clock);
 	clk_disable_unprepare(dsi->escape_clock);
@@ -1054,7 +1054,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
 
 	vc4_dsi_ulps(dsi, false);
 
-	drm_bridge_pre_enable(encoder->bridge);
+	drm_bridge_chain_pre_enable(encoder);
 
 	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
 		DSI_PORT_WRITE(DISP0_CTRL,
@@ -1071,7 +1071,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
 			       DSI_DISP0_ENABLE);
 	}
 
-	drm_bridge_enable(encoder->bridge);
+	drm_bridge_chain_enable(encoder);
 
 	if (debug_dump_regs) {
 		struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 7616f6562fe4..3057e2153f62 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -254,9 +254,10 @@ struct drm_bridge_funcs {
 	 * there is one) when this callback is called.
 	 *
 	 * Note that this function will only be invoked in the context of an
-	 * atomic commit. It will not be invoked from &drm_bridge_pre_enable. It
-	 * would be prudent to also provide an implementation of @pre_enable if
-	 * you are expecting driver calls into &drm_bridge_pre_enable.
+	 * atomic commit. It will not be invoked from
+	 * &drm_bridge_chain_pre_enable. It would be prudent to also provide an
+	 * implementation of @pre_enable if you are expecting driver calls into
+	 * &drm_bridge_chain_pre_enable.
 	 *
 	 * The @atomic_pre_enable callback is optional.
 	 */
@@ -279,9 +280,9 @@ struct drm_bridge_funcs {
 	 * chain if there is one.
 	 *
 	 * Note that this function will only be invoked in the context of an
-	 * atomic commit. It will not be invoked from &drm_bridge_enable. It
-	 * would be prudent to also provide an implementation of @enable if
-	 * you are expecting driver calls into &drm_bridge_enable.
+	 * atomic commit. It will not be invoked from &drm_bridge_chain_enable.
+	 * It would be prudent to also provide an implementation of @enable if
+	 * you are expecting driver calls into &drm_bridge_chain_enable.
 	 *
 	 * The enable callback is optional.
 	 */
@@ -301,9 +302,10 @@ struct drm_bridge_funcs {
 	 * signals) feeding it is still running when this callback is called.
 	 *
 	 * Note that this function will only be invoked in the context of an
-	 * atomic commit. It will not be invoked from &drm_bridge_disable. It
-	 * would be prudent to also provide an implementation of @disable if
-	 * you are expecting driver calls into &drm_bridge_disable.
+	 * atomic commit. It will not be invoked from
+	 * &drm_bridge_chain_disable. It would be prudent to also provide an
+	 * implementation of @disable if you are expecting driver calls into
+	 * &drm_bridge_chain_disable.
 	 *
 	 * The disable callback is optional.
 	 */
@@ -325,10 +327,11 @@ struct drm_bridge_funcs {
 	 * called.
 	 *
 	 * Note that this function will only be invoked in the context of an
-	 * atomic commit. It will not be invoked from &drm_bridge_post_disable.
+	 * atomic commit. It will not be invoked from
+	 * &drm_bridge_chain_post_disable.
 	 * It would be prudent to also provide an implementation of
 	 * @post_disable if you are expecting driver calls into
-	 * &drm_bridge_post_disable.
+	 * &drm_bridge_chain_post_disable.
 	 *
 	 * The post_disable callback is optional.
 	 */
@@ -406,27 +409,28 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
 int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 		      struct drm_bridge *previous);
 
-bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
-			   const struct drm_display_mode *mode,
-			   struct drm_display_mode *adjusted_mode);
-enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
-					   const struct drm_display_mode *mode);
-void drm_bridge_disable(struct drm_bridge *bridge);
-void drm_bridge_post_disable(struct drm_bridge *bridge);
-void drm_bridge_mode_set(struct drm_bridge *bridge,
-			 const struct drm_display_mode *mode,
-			 const struct drm_display_mode *adjusted_mode);
-void drm_bridge_pre_enable(struct drm_bridge *bridge);
-void drm_bridge_enable(struct drm_bridge *bridge);
+bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode);
+enum drm_mode_status
+drm_bridge_chain_mode_valid(struct drm_encoder *encoder,
+			    const struct drm_display_mode *mode);
+void drm_bridge_chain_disable(struct drm_encoder *encoder);
+void drm_bridge_chain_post_disable(struct drm_encoder *encoder);
+void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
+			       const struct drm_display_mode *mode,
+			       const struct drm_display_mode *adjusted_mode);
+void drm_bridge_chain_pre_enable(struct drm_encoder *encoder);
+void drm_bridge_chain_enable(struct drm_encoder *encoder);
 
-void drm_atomic_bridge_disable(struct drm_bridge *bridge,
-			       struct drm_atomic_state *state);
-void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
+void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
+				     struct drm_atomic_state *state);
+void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
+					  struct drm_atomic_state *state);
+void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
+					struct drm_atomic_state *state);
+void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
 				    struct drm_atomic_state *state);
-void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
-				  struct drm_atomic_state *state);
-void drm_atomic_bridge_enable(struct drm_bridge *bridge,
-			      struct drm_atomic_state *state);
 
 #ifdef CONFIG_DRM_PANEL_BRIDGE
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
-- 
2.21.0

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

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

* [PATCH RFC 07/19] drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (5 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 06/19] drm/bridge: Create drm_bridge_chain_xx() wrappers Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-19 17:19   ` Sam Ravnborg
  2019-08-08 15:11 ` [PATCH RFC 08/19] drm/bridge: Introduce drm_bridge_chain_get_{first, last, next}_bridge() Boris Brezillon
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

This is part of our attempt to make the bridge chain a double-linked
list based on the generic list helpers. In order to do that, we must
patch all drivers manipulating the encoder->bridge field directly.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/msm/edp/edp.c   | 4 +++-
 drivers/gpu/drm/msm/hdmi/hdmi.c | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c
index 0f312ac5b624..ad4e963ccd9b 100644
--- a/drivers/gpu/drm/msm/edp/edp.c
+++ b/drivers/gpu/drm/msm/edp/edp.c
@@ -178,7 +178,9 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
 		goto fail;
 	}
 
-	encoder->bridge = edp->bridge;
+	ret = drm_bridge_attach(encoder, edp->bridge, NULL);
+	if (ret)
+		goto fail;
 
 	priv->bridges[priv->num_bridges++]       = edp->bridge;
 	priv->connectors[priv->num_connectors++] = edp->connector;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 0e4217be3f00..55b9a8c8312b 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -327,7 +327,9 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
 		goto fail;
 	}
 
-	encoder->bridge = hdmi->bridge;
+	ret = drm_bridge_attach(encoder, hdmi->bridge, NULL);
+	if (ret)
+		goto fail;
 
 	priv->bridges[priv->num_bridges++]       = hdmi->bridge;
 	priv->connectors[priv->num_connectors++] = hdmi->connector;
-- 
2.21.0

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

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

* [PATCH RFC 08/19] drm/bridge: Introduce drm_bridge_chain_get_{first, last, next}_bridge()
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (6 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 07/19] drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 09/19] drm/bridge: Make the bridge chain a double-linked list Boris Brezillon
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

And use them in drivers accessing the encoder->bridge or bridge->next
fields directly. This is part of our attempt to make the bridge chain
a double-linked list based on the generic list helpers.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_bridge.c           | 52 ++++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_hdmi.c    |  2 +-
 drivers/gpu/drm/msm/edp/edp_bridge.c   |  2 +-
 drivers/gpu/drm/omapdrm/omap_drv.c     |  7 ++--
 drivers/gpu/drm/omapdrm/omap_encoder.c |  3 +-
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 10 +++--
 drivers/gpu/drm/vc4/vc4_dsi.c          |  4 +-
 include/drm/drm_bridge.h               |  6 +++
 8 files changed, 75 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 2bf9a19e11bf..b96bbba05ba9 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -160,6 +160,58 @@ void drm_bridge_detach(struct drm_bridge *bridge)
 	bridge->dev = NULL;
 }
 
+/**
+ * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain
+ * @encoder: encoder object
+ *
+ * RETURNS:
+ * the first bridge in the encoder chain, or NULL if there's no bridge
+ * attached to this encoder.
+ */
+struct drm_bridge *
+drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder)
+{
+	return encoder->bridge;
+}
+EXPORT_SYMBOL(drm_bridge_chain_get_first_bridge);
+
+/**
+ * drm_bridge_chain_get_last_bridge() - Get the last bridge in the chain
+ * @encoder: encoder object
+ *
+ * RETURNS:
+ * the last bridge in the encoder chain, or NULL if there's no bridge
+ * attached to this encoder.
+ */
+struct drm_bridge *
+drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder)
+{
+	struct drm_bridge *bridge = encoder->bridge;
+
+	while(bridge && bridge->next)
+		bridge = bridge->next;
+
+	return bridge;
+}
+EXPORT_SYMBOL(drm_bridge_chain_get_last_bridge);
+
+/**
+ * drm_bridge_chain_get_next_bridge() - Get the next bridge in the chain
+ * @bridge: bridge object
+ *
+ * RETURNS:
+ * the next bridge in the chain, or NULL if there's @bridge is the last.
+ */
+struct drm_bridge *
+drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge)
+{
+	if (!bridge || !bridge->encoder)
+		return NULL;
+
+	return bridge->next;
+}
+EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
+
 /**
  * DOC: bridge callbacks
  *
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 6ec3d2584539..17e6d79303e0 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1243,7 +1243,7 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn,
 		mode->hdisplay, mode->vdisplay, mode->vrefresh,
 		!!(mode->flags & DRM_MODE_FLAG_INTERLACE), mode->clock * 1000);
 
-	if (hdmi->bridge.next) {
+	if (drm_bridge_chain_get_next_bridge(&hdmi->bridge)) {
 		struct drm_display_mode adjusted_mode;
 
 		drm_mode_copy(&adjusted_mode, mode);
diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
index 2950bba4aca9..6d2d405580d2 100644
--- a/drivers/gpu/drm/msm/edp/edp_bridge.c
+++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
@@ -56,7 +56,7 @@ static void edp_bridge_mode_set(struct drm_bridge *bridge,
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if ((connector->encoder != NULL) &&
-			(connector->encoder->bridge == bridge)) {
+		    (drm_bridge_chain_get_first_bridge(connector->encoder) == bridge)) {
 			msm_edp_ctrl_timing_cfg(edp->ctrl,
 				adjusted_mode, &connector->display_info);
 			break;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 224ec6fdc800..41fb98a9141b 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -215,11 +215,10 @@ static int omap_display_id(struct omap_dss_device *output)
 		node = display->dev->of_node;
 		omapdss_device_put(display);
 	} else if (output->bridge) {
-		struct drm_bridge *bridge = output->bridge;
-
-		while (bridge->next)
-			bridge = bridge->next;
+		struct drm_encoder *encoder = output->bridge->encoder;
+		struct drm_bridge *bridge;
 
+		bridge = drm_bridge_chain_get_last_bridge(encoder);
 		node = bridge->of_node;
 	} else if (output->panel) {
 		node = output->panel->dev->of_node;
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
index 24bbe9f2a32e..727a6bea3807 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -126,7 +126,8 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
 	for (dssdev = output; dssdev; dssdev = dssdev->next)
 		omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
 
-	for (bridge = output->bridge; bridge; bridge = bridge->next) {
+	for (bridge = drm_bridge_chain_get_first_bridge(encoder);
+	     bridge; bridge = drm_bridge_chain_get_next_bridge(bridge)) {
 		if (!bridge->timings)
 			continue;
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 2da46e3dc4ae..f2ae4c410244 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -14,6 +14,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_fb_cma_helper.h>
@@ -680,9 +681,10 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
 			rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
 		const struct drm_display_mode *mode =
 			&crtc->state->adjusted_mode;
+		struct drm_bridge *bridge;
 
-		rcar_lvds_clk_enable(encoder->base.bridge,
-				     mode->clock * 1000);
+		bridge = drm_bridge_chain_get_first_bridge(&encoder->base);
+		rcar_lvds_clk_enable(bridge, mode->clock * 1000);
 	}
 
 	rcar_du_crtc_start(rcrtc);
@@ -702,12 +704,14 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
 	    rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) {
 		struct rcar_du_encoder *encoder =
 			rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
+		struct drm_bridge *bridge;
 
 		/*
 		 * Disable the LVDS clock output, see
 		 * rcar_du_crtc_atomic_enable().
 		 */
-		rcar_lvds_clk_disable(encoder->base.bridge);
+		bridge = drm_bridge_chain_get_first_bridge(&encoder->base);
+		rcar_lvds_clk_disable(bridge);
 	}
 
 	spin_lock_irq(&crtc->dev->event_lock);
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index d7cd720c4efa..a1698417927d 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -1629,8 +1629,10 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
 	struct drm_device *drm = dev_get_drvdata(master);
 	struct vc4_dev *vc4 = to_vc4_dev(drm);
 	struct vc4_dsi *dsi = dev_get_drvdata(dev);
+	struct drm_bridge *bridge;
 
-	if (dsi->encoder->bridge)
+	bridge = drm_bridge_chain_get_first_bridge(dsi->encoder);
+	if (bridge)
 		pm_runtime_disable(dev);
 
 	vc4_dsi_encoder_destroy(dsi->encoder);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 3057e2153f62..d429bd1c00f9 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -409,6 +409,12 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
 int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 		      struct drm_bridge *previous);
 
+struct drm_bridge *
+drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder);
+struct drm_bridge *
+drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder);
+struct drm_bridge *
+drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge);
 bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
 				 const struct drm_display_mode *mode,
 				 struct drm_display_mode *adjusted_mode);
-- 
2.21.0

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

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

* [PATCH RFC 09/19] drm/bridge: Make the bridge chain a double-linked list
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (7 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 08/19] drm/bridge: Introduce drm_bridge_chain_get_{first, last, next}_bridge() Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object Boris Brezillon
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

So each element in the chain can easily access its predecessor. This
will be needed for the work we are doing on bus format negociation
between elements of the bridge chain.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_bridge.c  | 278 +++++++++++++---------------------
 drivers/gpu/drm/drm_encoder.c |  15 +-
 include/drm/drm_bridge.h      |   4 +-
 include/drm/drm_encoder.h     |   4 +-
 4 files changed, 116 insertions(+), 185 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index b96bbba05ba9..ed2410f49581 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -55,7 +55,7 @@
  * just provide additional hooks to get the desired output at the end of the
  * encoder chain.
  *
- * Bridges can also be chained up using the &drm_bridge.next pointer.
+ * Bridges can also be chained up using the &drm_bridge.chain_node field.
  *
  * Both legacy CRTC helpers and the new atomic modeset helpers support bridges.
  */
@@ -114,6 +114,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
 int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 		      struct drm_bridge *previous)
 {
+	LIST_HEAD(tmp_list);
 	int ret;
 
 	if (!encoder || !bridge)
@@ -127,6 +128,7 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 
 	bridge->dev = encoder->dev;
 	bridge->encoder = encoder;
+	list_add_tail(&bridge->chain_node, &tmp_list);
 
 	if (bridge->funcs->attach) {
 		ret = bridge->funcs->attach(bridge);
@@ -138,9 +140,9 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 	}
 
 	if (previous)
-		previous->next = bridge;
+		list_splice(&tmp_list, &previous->chain_node);
 	else
-		encoder->bridge = bridge;
+		list_splice(&tmp_list, &encoder->bridge_chain);
 
 	return 0;
 }
@@ -157,6 +159,7 @@ void drm_bridge_detach(struct drm_bridge *bridge)
 	if (bridge->funcs->detach)
 		bridge->funcs->detach(bridge);
 
+	list_del(&bridge->chain_node);
 	bridge->dev = NULL;
 }
 
@@ -171,7 +174,8 @@ void drm_bridge_detach(struct drm_bridge *bridge)
 struct drm_bridge *
 drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder)
 {
-	return encoder->bridge;
+	return list_first_entry_or_null(&encoder->bridge_chain,
+					struct drm_bridge, chain_node);
 }
 EXPORT_SYMBOL(drm_bridge_chain_get_first_bridge);
 
@@ -186,12 +190,11 @@ EXPORT_SYMBOL(drm_bridge_chain_get_first_bridge);
 struct drm_bridge *
 drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder)
 {
-	struct drm_bridge *bridge = encoder->bridge;
+	if (list_empty(&encoder->bridge_chain))
+		return NULL;
 
-	while(bridge && bridge->next)
-		bridge = bridge->next;
-
-	return bridge;
+	return list_last_entry(&encoder->bridge_chain, struct drm_bridge,
+			       chain_node);
 }
 EXPORT_SYMBOL(drm_bridge_chain_get_last_bridge);
 
@@ -205,10 +208,11 @@ EXPORT_SYMBOL(drm_bridge_chain_get_last_bridge);
 struct drm_bridge *
 drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge)
 {
-	if (!bridge || !bridge->encoder)
-		return NULL;
+	if (!bridge || !bridge->encoder ||
+	    list_is_last(&bridge->encoder->bridge_chain, &bridge->chain_node))
+                return NULL;
 
-	return bridge->next;
+	return list_next_entry(bridge, chain_node);
 }
 EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
 
@@ -223,98 +227,6 @@ EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
  * For detailed specification of the bridge callbacks see &drm_bridge_funcs.
  */
 
-static bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
-				  const struct drm_display_mode *mode,
-				  struct drm_display_mode *adjusted_mode)
-{
-	bool ret = true;
-
-	if (!bridge)
-		return true;
-
-	if (bridge->funcs->mode_fixup)
-		ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode);
-
-	ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode);
-
-	return ret;
-}
-
-static enum drm_mode_status
-drm_bridge_mode_valid(struct drm_bridge *bridge,
-		      const struct drm_display_mode *mode)
-{
-	enum drm_mode_status ret = MODE_OK;
-
-	if (!bridge)
-		return ret;
-
-	if (bridge->funcs->mode_valid)
-		ret = bridge->funcs->mode_valid(bridge, mode);
-
-	if (ret != MODE_OK)
-		return ret;
-
-	return drm_bridge_mode_valid(bridge->next, mode);
-}
-
-static void drm_bridge_disable(struct drm_bridge *bridge)
-{
-	if (!bridge)
-		return;
-
-	drm_bridge_disable(bridge->next);
-
-	if (bridge->funcs->disable)
-		bridge->funcs->disable(bridge);
-}
-
-static void drm_bridge_post_disable(struct drm_bridge *bridge)
-{
-	if (!bridge)
-		return;
-
-	if (bridge->funcs->post_disable)
-		bridge->funcs->post_disable(bridge);
-
-	drm_bridge_post_disable(bridge->next);
-}
-
-static void drm_bridge_mode_set(struct drm_bridge *bridge,
-				const struct drm_display_mode *mode,
-				const struct drm_display_mode *adjusted_mode)
-{
-	if (!bridge)
-		return;
-
-	if (bridge->funcs->mode_set)
-		bridge->funcs->mode_set(bridge, mode, adjusted_mode);
-
-	drm_bridge_mode_set(bridge->next, mode, adjusted_mode);
-}
-
-static void drm_bridge_pre_enable(struct drm_bridge *bridge)
-{
-	if (!bridge)
-		return;
-
-	drm_bridge_pre_enable(bridge->next);
-
-	if (bridge->funcs->pre_enable)
-		bridge->funcs->pre_enable(bridge);
-}
-
-static void drm_bridge_enable(struct drm_bridge *bridge)
-{
-	if (!bridge)
-		return;
-
-	if (bridge->funcs->enable)
-		bridge->funcs->enable(bridge);
-
-	drm_bridge_enable(bridge->next);
-}
-
 /**
  * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the
  *				 encoder chain
@@ -332,7 +244,17 @@ bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
 				 const struct drm_display_mode *mode,
 				 struct drm_display_mode *adjusted_mode)
 {
-	return drm_bridge_mode_fixup(encoder->bridge, mode, adjusted_mode);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+		if (!bridge->funcs->mode_fixup)
+			continue;
+
+		if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode))
+			return false;
+	}
+
+	return true;
 }
 EXPORT_SYMBOL(drm_bridge_chain_mode_fixup);
 
@@ -353,7 +275,20 @@ enum drm_mode_status
 drm_bridge_chain_mode_valid(struct drm_encoder *encoder,
 			    const struct drm_display_mode *mode)
 {
-	return drm_bridge_mode_valid(encoder->bridge, mode);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+		enum drm_mode_status ret;
+
+		if (!bridge->funcs->mode_valid)
+			continue;
+
+		ret = bridge->funcs->mode_valid(bridge, mode);
+		if (ret != MODE_OK)
+			return ret;
+	}
+
+	return MODE_OK;
 }
 EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
 
@@ -367,7 +302,13 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
  */
 void drm_bridge_chain_disable(struct drm_encoder *encoder)
 {
-	drm_bridge_disable(encoder->bridge);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
+				    chain_node) {
+		if (bridge->funcs->disable)
+			bridge->funcs->disable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_bridge_chain_disable);
 
@@ -382,7 +323,12 @@ EXPORT_SYMBOL(drm_bridge_chain_disable);
  */
 void drm_bridge_chain_post_disable(struct drm_encoder *encoder)
 {
-	drm_bridge_post_disable(encoder->bridge);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+		if (bridge->funcs->post_disable)
+			bridge->funcs->post_disable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_bridge_chain_post_disable);
 
@@ -400,7 +346,12 @@ void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
 			       const struct drm_display_mode *mode,
 			       const struct drm_display_mode *adjusted_mode)
 {
-	drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+		if (bridge->funcs->mode_set)
+			bridge->funcs->mode_set(bridge, mode, adjusted_mode);
+	}
 }
 EXPORT_SYMBOL(drm_bridge_chain_mode_set);
 
@@ -415,7 +366,13 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set);
  */
 void drm_bridge_chain_pre_enable(struct drm_encoder *encoder)
 {
-	drm_bridge_pre_enable(encoder->bridge);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
+				    chain_node) {
+		if (bridge->funcs->pre_enable)
+			bridge->funcs->pre_enable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
 
@@ -429,66 +386,15 @@ EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
  */
 void drm_bridge_chain_enable(struct drm_encoder *encoder)
 {
-	drm_bridge_enable(encoder->bridge);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+		if (bridge->funcs->enable)
+			bridge->funcs->enable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_bridge_chain_enable);
 
-static void drm_atomic_bridge_disable(struct drm_bridge *bridge,
-				      struct drm_atomic_state *state)
-{
-	if (!bridge)
-		return;
-
-	drm_atomic_bridge_disable(bridge->next, state);
-
-	if (bridge->funcs->atomic_disable)
-		bridge->funcs->atomic_disable(bridge, state);
-	else if (bridge->funcs->disable)
-		bridge->funcs->disable(bridge);
-}
-
-static void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
-					   struct drm_atomic_state *state)
-{
-	if (!bridge)
-		return;
-
-	if (bridge->funcs->atomic_post_disable)
-		bridge->funcs->atomic_post_disable(bridge, state);
-	else if (bridge->funcs->post_disable)
-		bridge->funcs->post_disable(bridge);
-
-	drm_atomic_bridge_post_disable(bridge->next, state);
-}
-
-static void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
-					 struct drm_atomic_state *state)
-{
-	if (!bridge)
-		return;
-
-	drm_atomic_bridge_pre_enable(bridge->next, state);
-
-	if (bridge->funcs->atomic_pre_enable)
-		bridge->funcs->atomic_pre_enable(bridge, state);
-	else if (bridge->funcs->pre_enable)
-		bridge->funcs->pre_enable(bridge);
-}
-
-static void drm_atomic_bridge_enable(struct drm_bridge *bridge,
-				     struct drm_atomic_state *state)
-{
-	if (!bridge)
-		return;
-
-	if (bridge->funcs->atomic_enable)
-		bridge->funcs->atomic_enable(bridge, state);
-	else if (bridge->funcs->enable)
-		bridge->funcs->enable(bridge);
-
-	drm_atomic_bridge_enable(bridge->next, state);
-}
-
 /**
  * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
  * @encoder: encoder object
@@ -502,7 +408,15 @@ static void drm_atomic_bridge_enable(struct drm_bridge *bridge,
 void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
 				     struct drm_atomic_state *state)
 {
-	drm_atomic_bridge_disable(encoder->bridge, state);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
+				    chain_node) {
+		if (bridge->funcs->atomic_disable)
+			bridge->funcs->atomic_disable(bridge, state);
+		else if (bridge->funcs->disable)
+			bridge->funcs->disable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
 
@@ -520,7 +434,14 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
 void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
 					  struct drm_atomic_state *state)
 {
-	drm_atomic_bridge_post_disable(encoder->bridge, state);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+		if (bridge->funcs->atomic_post_disable)
+			bridge->funcs->atomic_post_disable(bridge, state);
+		else if (bridge->funcs->post_disable)
+			bridge->funcs->post_disable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
 
@@ -538,7 +459,15 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
 void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
 					struct drm_atomic_state *state)
 {
-	drm_atomic_bridge_pre_enable(encoder->bridge, state);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
+				    chain_node) {
+		if (bridge->funcs->atomic_pre_enable)
+			bridge->funcs->atomic_pre_enable(bridge, state);
+		else if (bridge->funcs->pre_enable)
+			bridge->funcs->pre_enable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
 
@@ -555,7 +484,14 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
 void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
 				    struct drm_atomic_state *state)
 {
-	drm_atomic_bridge_enable(encoder->bridge, state);
+	struct drm_bridge *bridge;
+
+	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+		if (bridge->funcs->atomic_enable)
+			bridge->funcs->atomic_enable(bridge, state);
+		else if (bridge->funcs->enable)
+			bridge->funcs->enable(bridge);
+	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
 
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 80d88a55302e..e555281f43d4 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -140,6 +140,7 @@ int drm_encoder_init(struct drm_device *dev,
 		goto out_put;
 	}
 
+	INIT_LIST_HEAD(&encoder->bridge_chain);
 	list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
 	encoder->index = dev->mode_config.num_encoder++;
 
@@ -160,22 +161,16 @@ EXPORT_SYMBOL(drm_encoder_init);
 void drm_encoder_cleanup(struct drm_encoder *encoder)
 {
 	struct drm_device *dev = encoder->dev;
+	struct drm_bridge *bridge, *next;
 
 	/* Note that the encoder_list is considered to be static; should we
 	 * remove the drm_encoder at runtime we would have to decrement all
 	 * the indices on the drm_encoder after us in the encoder_list.
 	 */
 
-	if (encoder->bridge) {
-		struct drm_bridge *bridge = encoder->bridge;
-		struct drm_bridge *next;
-
-		while (bridge) {
-			next = bridge->next;
-			drm_bridge_detach(bridge);
-			bridge = next;
-		}
-	}
+	list_for_each_entry_safe(bridge, next, &encoder->bridge_chain,
+				 chain_node)
+		drm_bridge_detach(bridge);
 
 	drm_mode_object_unregister(dev, &encoder->base);
 	kfree(encoder->name);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index d429bd1c00f9..f40181274ed7 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -383,8 +383,8 @@ struct drm_bridge {
 	struct drm_device *dev;
 	/** @encoder: encoder to which this bridge is connected */
 	struct drm_encoder *encoder;
-	/** @next: the next bridge in the encoder chain */
-	struct drm_bridge *next;
+	/** @chain_node: used to form a bridge chain */
+	struct list_head chain_node;
 #ifdef CONFIG_OF
 	/** @of_node: device node pointer to the bridge */
 	struct device_node *of_node;
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index d986ff1197ce..0899f7f34e3a 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -89,7 +89,7 @@ struct drm_encoder_funcs {
  * @head: list management
  * @base: base KMS object
  * @name: human readable name, can be overwritten by the driver
- * @bridge: bridge associated to the encoder
+ * @bridge_chain: bridges associated to the encoder
  * @funcs: control functions
  * @helper_private: mid-layer private data
  *
@@ -172,7 +172,7 @@ struct drm_encoder {
 	 * &drm_connector_state.crtc.
 	 */
 	struct drm_crtc *crtc;
-	struct drm_bridge *bridge;
+	struct list_head bridge_chain;
 	const struct drm_encoder_funcs *funcs;
 	const struct drm_encoder_helper_funcs *helper_private;
 
-- 
2.21.0

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

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

* [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (8 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 09/19] drm/bridge: Make the bridge chain a double-linked list Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-21 20:14   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 11/19] drm/bridge: Patch atomic hooks to take a drm_bridge_state Boris Brezillon
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

One of the last remaining object to not have its atomic state.

This is being motivated by our attempt to support runtime bus-format
negotiation between elements of the bridge chain.
This patch just paves the road for such a feature by adding a new
drm_bridge_state object inheriting from drm_private_obj so we can
re-use some of the state initialization/tracking logic.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_atomic.c        |  40 ++++++++
 drivers/gpu/drm/drm_atomic_helper.c |  18 ++++
 drivers/gpu/drm/drm_bridge.c        | 141 +++++++++++++++++++++++++++-
 include/drm/drm_atomic.h            |   3 +
 include/drm/drm_bridge.h            |  99 +++++++++++++++++++
 5 files changed, 296 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 419381abbdd1..ed6fd3e31b56 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -30,6 +30,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_uapi.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
@@ -1010,6 +1011,45 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
 		connector->funcs->atomic_print_state(p, state);
 }
 
+/**
+ * drm_atomic_add_encoder_bridges - add bridges attached to an encoder
+ * @state: atomic state
+ * @encoder: DRM encoder
+ *
+ * This function adds all bridges attached to @encoder. This is needed to add
+ * bridge states to @state and make them available when
+ * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are
+ * called
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
+			       struct drm_encoder *encoder)
+{
+	struct drm_bridge_state *bridge_state;
+	struct drm_bridge *bridge;
+
+	if (!encoder)
+		return 0;
+
+	DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n",
+			 encoder->base.id, encoder->name, state);
+
+	for (bridge = drm_bridge_chain_get_first_bridge(encoder); bridge;
+	     bridge = drm_bridge_chain_get_next_bridge(bridge)) {
+		bridge_state = drm_atomic_get_bridge_state(state, bridge);
+		if (IS_ERR(bridge_state))
+			return PTR_ERR(bridge_state);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
+
 /**
  * drm_atomic_add_affected_connectors - add connectors for crtc
  * @state: atomic state
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 0deb54099570..e76ec9648b6f 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -736,6 +736,24 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 			return ret;
 	}
 
+	/*
+	 * Iterate over all connectors again, and add all affected bridges to
+	 * the state.
+	 */
+	for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
+		struct drm_encoder *encoder;
+
+		encoder = old_connector_state->best_encoder;
+		ret = drm_atomic_add_encoder_bridges(state, encoder);
+		if (ret)
+			return ret;
+
+		encoder = new_connector_state->best_encoder;
+		ret = drm_atomic_add_encoder_bridges(state, encoder);
+		if (ret)
+			return ret;
+	}
+
 	ret = mode_valid(state);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index ed2410f49581..0280da6be1e6 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -89,6 +89,38 @@ void drm_bridge_remove(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_remove);
 
+static struct drm_private_state *
+drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
+{
+	struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+	struct drm_bridge_state *state;
+
+	if (bridge->funcs->atomic_duplicate_state)
+		state = bridge->funcs->atomic_duplicate_state(bridge);
+	else
+		state = drm_atomic_helper_duplicate_bridge_state(bridge);
+
+	return &state->base;
+}
+
+static void
+drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
+                                     struct drm_private_state *s)
+{
+	struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
+	struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+
+	if (bridge->funcs->atomic_destroy_state)
+		bridge->funcs->atomic_destroy_state(bridge, state);
+	else
+		drm_atomic_helper_destroy_bridge_state(bridge, state);
+}
+
+static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
+	.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
+	.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
+};
+
 /**
  * drm_bridge_attach - attach the bridge to an encoder's chain
  *
@@ -114,6 +146,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
 int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 		      struct drm_bridge *previous)
 {
+	struct drm_bridge_state *state;
 	LIST_HEAD(tmp_list);
 	int ret;
 
@@ -132,19 +165,39 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 
 	if (bridge->funcs->attach) {
 		ret = bridge->funcs->attach(bridge);
-		if (ret < 0) {
-			bridge->dev = NULL;
-			bridge->encoder = NULL;
-			return ret;
-		}
+		if (ret < 0)
+			goto err_reset_bridge;
 	}
 
+	if (bridge->funcs->atomic_duplicate_state)
+		state = bridge->funcs->atomic_duplicate_state(bridge);
+	else
+		state = drm_atomic_helper_duplicate_bridge_state(bridge);
+
+	if (!state) {
+		ret = -ENOMEM;
+		goto err_detach_bridge;
+	}
+
+	drm_atomic_private_obj_init(bridge->dev, &bridge->base,
+				    &state->base,
+				    &drm_bridge_priv_state_funcs);
+
 	if (previous)
 		list_splice(&tmp_list, &previous->chain_node);
 	else
 		list_splice(&tmp_list, &encoder->bridge_chain);
 
 	return 0;
+
+err_detach_bridge:
+	if (bridge->funcs->detach)
+		bridge->funcs->detach(bridge);
+
+err_reset_bridge:
+	bridge->dev = NULL;
+	bridge->encoder = NULL;
+	return ret;
 }
 EXPORT_SYMBOL(drm_bridge_attach);
 
@@ -156,6 +209,8 @@ void drm_bridge_detach(struct drm_bridge *bridge)
 	if (WARN_ON(!bridge->dev))
 		return;
 
+	drm_atomic_private_obj_fini(&bridge->base);
+
 	if (bridge->funcs->detach)
 		bridge->funcs->detach(bridge);
 
@@ -495,6 +550,82 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
 
+/**
+ * drm_atomic_helper_init_bridge_state() - Initializes a bridge state
+ * @bridge this state is referring to
+ * @state: bridge state to initialize
+ *
+ * For now it's just a memset(0) plus a state->bridge assignment. Might
+ * be extended in the future.
+ */
+void drm_atomic_helper_init_bridge_state(struct drm_bridge *bridge,
+					 struct drm_bridge_state *state)
+{
+	memset(state, 0, sizeof(*state));
+	state->bridge = bridge;
+}
+EXPORT_SYMBOL(drm_atomic_helper_init_bridge_state);
+
+/**
+ * drm_atomic_helper_copy_bridge_state() - Copy the content of a bridge state
+ * @bridge: bridge the old and new state are referring to
+ * @old: previous bridge state to copy from
+ * @new: new bridge state to copy to
+ *
+ * Should be used by custom &drm_bridge_funcs.atomic_duplicate() implementation
+ * to copy the previous state into the new object.
+ */
+void drm_atomic_helper_copy_bridge_state(struct drm_bridge *bridge,
+					 const struct drm_bridge_state *old,
+					 struct drm_bridge_state *new)
+{
+	*new = *old;
+}
+EXPORT_SYMBOL(drm_atomic_helper_copy_bridge_state);
+
+/**
+ * drm_atomic_helper_duplicate_bridge_state() - Default duplicate state helper
+ * @bridge: bridge containing the state to duplicate
+ *
+ * Default implementation of &drm_bridge_funcs.atomic_duplicate().
+ *
+ * RETURNS:
+ * a valid state object or NULL if the allocation fails.
+ */
+struct drm_bridge_state *
+drm_atomic_helper_duplicate_bridge_state(struct drm_bridge *bridge)
+{
+	struct drm_bridge_state *old = NULL, *new;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	if (bridge->base.state) {
+		old = drm_priv_to_bridge_state(bridge->base.state);
+		drm_atomic_helper_copy_bridge_state(bridge, old, new);
+	} else {
+		drm_atomic_helper_init_bridge_state(bridge, new);
+	}
+
+	return new;
+}
+EXPORT_SYMBOL(drm_atomic_helper_duplicate_bridge_state);
+
+/**
+ * drm_atomic_helper_destroy_bridge_state() - Default destroy state helper
+ * @bridge: the bridge this state refers to
+ * @state: state object to destroy
+ *
+ * Just a simple kfree() for now.
+ */
+void drm_atomic_helper_destroy_bridge_state(struct drm_bridge *bridge,
+					    struct drm_bridge_state *state)
+{
+	kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_destroy_bridge_state);
+
 #ifdef CONFIG_OF
 /**
  * of_drm_find_bridge - find the bridge corresponding to the device node in
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 927e1205d7aa..5ee25fd51e80 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -660,6 +660,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
 	return plane->state;
 }
 
+int __must_check
+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
+                               struct drm_encoder *encoder);
 int __must_check
 drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
 				   struct drm_crtc *crtc);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index f40181274ed7..8ca25d266d0c 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -25,6 +25,7 @@
 
 #include <linux/list.h>
 #include <linux/ctype.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_mode_object.h>
 #include <drm/drm_modes.h>
 
@@ -32,6 +33,23 @@ struct drm_bridge;
 struct drm_bridge_timings;
 struct drm_panel;
 
+/**
+ * struct drm_bridge_state - Atomic bridge state object
+ * @base: inherit from &drm_private_state
+ * @bridge: the bridge this state refers to
+ */
+struct drm_bridge_state {
+	struct drm_private_state base;
+
+	struct drm_bridge *bridge;
+};
+
+static inline struct drm_bridge_state *
+drm_priv_to_bridge_state(struct drm_private_state *priv)
+{
+	return container_of(priv, struct drm_bridge_state, base);
+}
+
 /**
  * struct drm_bridge_funcs - drm_bridge control functions
  */
@@ -337,6 +355,30 @@ struct drm_bridge_funcs {
 	 */
 	void (*atomic_post_disable)(struct drm_bridge *bridge,
 				    struct drm_atomic_state *state);
+
+	/**
+	 * @atomic_duplicate_state:
+	 *
+	 * Duplicate the current bridge state object.
+	 *
+	 * Note that this function can be called when current bridge state is
+	 * NULL. In this case, implementations should either implement HW
+	 * readback or initialize the state with sensible default values.
+	 *
+	 * RETURNS:
+	 * A valid drm_bridge_state object or NULL if the allocation fails.
+	 */
+	struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge);
+
+	/**
+	 * @atomic_duplicate_state:
+	 *
+	 * Destroy a bridge state object previously allocated by
+	 * &drm_bridge_funcs.atomic_duplicate_state() or
+	 * &drm_bridge_funcs.atomic_get_initial_state().
+	 */
+	void (*atomic_destroy_state)(struct drm_bridge *bridge,
+				     struct drm_bridge_state *state);
 };
 
 /**
@@ -379,6 +421,8 @@ struct drm_bridge_timings {
  * struct drm_bridge - central DRM bridge control structure
  */
 struct drm_bridge {
+	/** @base: inherit from &drm_private_object */
+	struct drm_private_obj base;
 	/** @dev: DRM device this bridge belongs to */
 	struct drm_device *dev;
 	/** @encoder: encoder to which this bridge is connected */
@@ -403,6 +447,12 @@ struct drm_bridge {
 	void *driver_private;
 };
 
+static inline struct drm_bridge *
+drm_priv_to_bridge(struct drm_private_obj *priv)
+{
+	return container_of(priv, struct drm_bridge, base);
+}
+
 void drm_bridge_add(struct drm_bridge *bridge);
 void drm_bridge_remove(struct drm_bridge *bridge);
 struct drm_bridge *of_drm_find_bridge(struct device_node *np);
@@ -438,6 +488,55 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
 void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
 				    struct drm_atomic_state *state);
 
+void drm_atomic_helper_init_bridge_state(struct drm_bridge *bridge,
+					 struct drm_bridge_state *state);
+void drm_atomic_helper_copy_bridge_state(struct drm_bridge *bridge,
+					 const struct drm_bridge_state *old,
+					 struct drm_bridge_state *new);
+struct drm_bridge_state *
+drm_atomic_helper_duplicate_bridge_state(struct drm_bridge *bridge);
+void drm_atomic_helper_destroy_bridge_state(struct drm_bridge *bridge,
+					    struct drm_bridge_state *state);
+
+static inline struct drm_bridge_state *
+drm_atomic_get_bridge_state(struct drm_atomic_state *state,
+			    struct drm_bridge *bridge)
+{
+	struct drm_private_state *obj_state;
+
+	obj_state = drm_atomic_get_private_obj_state(state, &bridge->base);
+	if (!obj_state)
+		return NULL;
+
+	return drm_priv_to_bridge_state(obj_state);
+}
+
+static inline struct drm_bridge_state *
+drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
+				struct drm_bridge *bridge)
+{
+	struct drm_private_state *obj_state;
+
+	obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base);
+	if (!obj_state)
+		return NULL;
+
+	return drm_priv_to_bridge_state(obj_state);
+}
+
+static inline struct drm_bridge_state *
+drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
+				struct drm_bridge *bridge)
+{
+	struct drm_private_state *obj_state;
+
+	obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base);
+	if (!obj_state)
+		return NULL;
+
+	return drm_priv_to_bridge_state(obj_state);
+}
+
 #ifdef CONFIG_DRM_PANEL_BRIDGE
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
 					u32 connector_type);
-- 
2.21.0

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

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

* [PATCH RFC 11/19] drm/bridge: Patch atomic hooks to take a drm_bridge_state
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (9 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-22  0:02   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 12/19] drm/bridge: Add an ->atomic_check() hook Boris Brezillon
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Instead of a drm_atomic_state. The only driver implementing those hooks
is patched too.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 .../drm/bridge/analogix/analogix_dp_core.c    | 12 ++--
 drivers/gpu/drm/drm_bridge.c                  | 57 +++++++++++++++----
 include/drm/drm_bridge.h                      |  8 +--
 3 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index b096a7a75c14..02b9ee0e4f7a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1290,8 +1290,9 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
 }
 
 static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
-						 struct drm_atomic_state *state)
+						 struct drm_bridge_state *bstate)
 {
+	struct drm_atomic_state *state = bstate->base.state;
 	struct analogix_dp_device *dp = bridge->driver_private;
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *old_crtc_state;
@@ -1367,8 +1368,9 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
 }
 
 static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
-					     struct drm_atomic_state *state)
+					     struct drm_bridge_state *bstate)
 {
+	struct drm_atomic_state *state = bstate->base.state;
 	struct analogix_dp_device *dp = bridge->driver_private;
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *old_crtc_state;
@@ -1441,8 +1443,9 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 }
 
 static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
-					      struct drm_atomic_state *state)
+					      struct drm_bridge_state *bstate)
 {
+	struct drm_atomic_state *state = bstate->base.state;
 	struct analogix_dp_device *dp = bridge->driver_private;
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *new_crtc_state = NULL;
@@ -1465,8 +1468,9 @@ static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
 
 static
 void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
-					    struct drm_atomic_state *state)
+					    struct drm_bridge_state *bstate)
 {
+	struct drm_atomic_state *state = bstate->base.state;
 	struct analogix_dp_device *dp = bridge->driver_private;
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *new_crtc_state;
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0280da6be1e6..0528ca941855 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -467,10 +467,18 @@ void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
 
 	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
 				    chain_node) {
-		if (bridge->funcs->atomic_disable)
-			bridge->funcs->atomic_disable(bridge, state);
-		else if (bridge->funcs->disable)
+		if (bridge->funcs->atomic_disable) {
+			struct drm_bridge_state *bridge_state;
+
+			bridge_state = drm_atomic_get_old_bridge_state(state,
+								       bridge);
+			if (WARN_ON(!bridge_state))
+				return;
+
+			bridge->funcs->atomic_disable(bridge, bridge_state);
+		} else if (bridge->funcs->disable) {
 			bridge->funcs->disable(bridge);
+		}
 	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
@@ -492,10 +500,19 @@ void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
 	struct drm_bridge *bridge;
 
 	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
-		if (bridge->funcs->atomic_post_disable)
-			bridge->funcs->atomic_post_disable(bridge, state);
-		else if (bridge->funcs->post_disable)
+		if (bridge->funcs->atomic_post_disable) {
+			struct drm_bridge_state *bridge_state;
+
+			bridge_state = drm_atomic_get_old_bridge_state(state,
+								       bridge);
+			if (WARN_ON(!bridge_state))
+				return;
+
+			bridge->funcs->atomic_post_disable(bridge,
+							   bridge_state);
+		} else if (bridge->funcs->post_disable) {
 			bridge->funcs->post_disable(bridge);
+		}
 	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
@@ -518,10 +535,18 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
 
 	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
 				    chain_node) {
-		if (bridge->funcs->atomic_pre_enable)
-			bridge->funcs->atomic_pre_enable(bridge, state);
-		else if (bridge->funcs->pre_enable)
+		if (bridge->funcs->atomic_pre_enable) {
+			struct drm_bridge_state *bridge_state;
+
+			bridge_state = drm_atomic_get_new_bridge_state(state,
+								       bridge);
+			if (WARN_ON(!bridge_state))
+				return;
+
+			bridge->funcs->atomic_pre_enable(bridge, bridge_state);
+		} else if (bridge->funcs->pre_enable) {
 			bridge->funcs->pre_enable(bridge);
+		}
 	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
@@ -542,10 +567,18 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
 	struct drm_bridge *bridge;
 
 	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
-		if (bridge->funcs->atomic_enable)
-			bridge->funcs->atomic_enable(bridge, state);
-		else if (bridge->funcs->enable)
+		if (bridge->funcs->atomic_enable) {
+			struct drm_bridge_state *bridge_state;
+
+			bridge_state = drm_atomic_get_new_bridge_state(state,
+								       bridge);
+			if (WARN_ON(!bridge_state))
+				return;
+
+			bridge->funcs->atomic_enable(bridge, bridge_state);
+		} else if (bridge->funcs->enable) {
 			bridge->funcs->enable(bridge);
+		}
 	}
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 8ca25d266d0c..9383b4e4b853 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -280,7 +280,7 @@ struct drm_bridge_funcs {
 	 * The @atomic_pre_enable callback is optional.
 	 */
 	void (*atomic_pre_enable)(struct drm_bridge *bridge,
-				  struct drm_atomic_state *state);
+				  struct drm_bridge_state *state);
 
 	/**
 	 * @atomic_enable:
@@ -305,7 +305,7 @@ struct drm_bridge_funcs {
 	 * The enable callback is optional.
 	 */
 	void (*atomic_enable)(struct drm_bridge *bridge,
-			      struct drm_atomic_state *state);
+			      struct drm_bridge_state *state);
 	/**
 	 * @atomic_disable:
 	 *
@@ -328,7 +328,7 @@ struct drm_bridge_funcs {
 	 * The disable callback is optional.
 	 */
 	void (*atomic_disable)(struct drm_bridge *bridge,
-			       struct drm_atomic_state *state);
+			       struct drm_bridge_state *state);
 
 	/**
 	 * @atomic_post_disable:
@@ -354,7 +354,7 @@ struct drm_bridge_funcs {
 	 * The post_disable callback is optional.
 	 */
 	void (*atomic_post_disable)(struct drm_bridge *bridge,
-				    struct drm_atomic_state *state);
+				    struct drm_bridge_state *state);
 
 	/**
 	 * @atomic_duplicate_state:
-- 
2.21.0

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

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

* [PATCH RFC 12/19] drm/bridge: Add an ->atomic_check() hook
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (10 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 11/19] drm/bridge: Patch atomic hooks to take a drm_bridge_state Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-22  0:12   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 13/19] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper Boris Brezillon
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

So that bridge drivers have a way to check/reject an atomic operation.
The drm_atomic_bridge_chain_check() (which is just a wrapper around
the ->atomic_check() hook) is called in place of
drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented,
the core falls back to ->mode_fixup(), so the behavior should stay
the same for existing bridge drivers).

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 11 +++---
 drivers/gpu/drm/drm_bridge.c        | 59 +++++++++++++++++++++++++++++
 include/drm/drm_bridge.h            | 23 +++++++++++
 3 files changed, 87 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index e76ec9648b6f..3fadde38ead7 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -445,12 +445,11 @@ mode_fixup(struct drm_atomic_state *state)
 		encoder = new_conn_state->best_encoder;
 		funcs = encoder->helper_private;
 
-		ret = drm_bridge_chain_mode_fixup(encoder,
-					&new_crtc_state->mode,
-					&new_crtc_state->adjusted_mode);
-		if (!ret) {
-			DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
-			return -EINVAL;
+		ret = drm_atomic_bridge_chain_check(encoder, new_crtc_state,
+						    new_conn_state);
+		if (ret) {
+			DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
+			return ret;
 		}
 
 		if (funcs && funcs->atomic_check) {
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0528ca941855..dcad661daa74 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -583,6 +583,65 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
 
+static int drm_atomic_bridge_check(struct drm_bridge *bridge,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_connector_state *conn_state)
+{
+	if (bridge->funcs->atomic_check) {
+		struct drm_bridge_state *bridge_state;
+		int ret;
+
+		bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
+							       bridge);
+		if (WARN_ON(!bridge_state))
+			return -EINVAL;
+
+		ret = bridge->funcs->atomic_check(bridge, bridge_state,
+						  crtc_state, conn_state);
+		if (ret)
+			return ret;
+	} else if (bridge->funcs->mode_fixup) {
+		if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode,
+					       &crtc_state->adjusted_mode))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
+ * @encoder: encoder object
+ * @crtc_state: new CRTC state
+ * @conn_state: new connector state
+ *
+ * Calls &drm_bridge_funcs.atomic_check() (falls back on
+ * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
+ * starting from the last bridge to the first. These are called before calling
+ * &drm_encoder_helper_funcs.atomic_check()
+ *
+ * RETURNS:
+ * 0 on success, a negative error code on failure
+ */
+int drm_atomic_bridge_chain_check(struct drm_encoder *encoder,
+				  struct drm_crtc_state *crtc_state,
+				  struct drm_connector_state *conn_state)
+{
+	struct drm_bridge *bridge;
+
+	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
+				    chain_node) {
+		int ret;
+
+		ret = drm_atomic_bridge_check(bridge, crtc_state, conn_state);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_bridge_chain_check);
+
 /**
  * drm_atomic_helper_init_bridge_state() - Initializes a bridge state
  * @bridge this state is referring to
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 9383b4e4b853..5d8fe3709bde 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -379,6 +379,26 @@ struct drm_bridge_funcs {
 	 */
 	void (*atomic_destroy_state)(struct drm_bridge *bridge,
 				     struct drm_bridge_state *state);
+
+	/**
+	 * @atomic_check:
+	 *
+	 * This method is responsible for checking bridge state correctness.
+	 * It can also check the state of the surrounding components in chain
+	 * to make sure the whole pipeline can work properly.
+	 *
+	 * &drm_bridge_funcs.atomic_check() hooks are called in reverse
+	 * order (from the last to the first bridge).
+	 *
+	 * This method is optional.
+	 *
+	 * RETURNS:
+	 * zero if the check passed, a negative error code otherwise.
+	 */
+	int (*atomic_check)(struct drm_bridge *bridge,
+			    struct drm_bridge_state *bridge_state,
+			    struct drm_crtc_state *crtc_state,
+			    struct drm_connector_state *conn_state);
 };
 
 /**
@@ -479,6 +499,9 @@ void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
 void drm_bridge_chain_pre_enable(struct drm_encoder *encoder);
 void drm_bridge_chain_enable(struct drm_encoder *encoder);
 
+int drm_atomic_bridge_chain_check(struct drm_encoder *encoder,
+				  struct drm_crtc_state *crtc_state,
+				  struct drm_connector_state *conn_state);
 void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
 				     struct drm_atomic_state *state);
 void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
-- 
2.21.0

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

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

* [PATCH RFC 13/19] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (11 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 12/19] drm/bridge: Add an ->atomic_check() hook Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-22  0:17   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation Boris Brezillon
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Will be useful for bridge drivers that want to do bus format
negotiation with their neighbours.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_bridge.c | 19 +++++++++++++++++++
 include/drm/drm_bridge.h     |  2 ++
 2 files changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index dcad661daa74..9efb27087e70 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -271,6 +271,25 @@ drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
 
+/**
+ * drm_bridge_chain_get_prev_bridge() - Get the previous bridge in the chain
+ * @bridge: bridge object
+ *
+ * RETURNS:
+ * the previous bridge in the chain, or NULL if there's @bridge is the
+ * last.
+ */
+struct drm_bridge *
+drm_bridge_chain_get_prev_bridge(struct drm_bridge *bridge)
+{
+	if (!bridge || !bridge->encoder ||
+	    list_is_first(&bridge->encoder->bridge_chain, &bridge->chain_node))
+                return NULL;
+
+	return list_prev_entry(bridge, chain_node);
+}
+EXPORT_SYMBOL(drm_bridge_chain_get_prev_bridge);
+
 /**
  * DOC: bridge callbacks
  *
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 5d8fe3709bde..2f69adb7b0f3 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -485,6 +485,8 @@ struct drm_bridge *
 drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder);
 struct drm_bridge *
 drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge);
+struct drm_bridge *
+drm_bridge_chain_get_prev_bridge(struct drm_bridge *bridge);
 bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
 				 const struct drm_display_mode *mode,
 				 struct drm_display_mode *adjusted_mode);
-- 
2.21.0

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

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

* [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (12 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 13/19] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-14  7:51   ` Neil Armstrong
  2019-08-22  0:55   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 15/19] drm/imx: pd: Use bus format/flags provided by the bridge when available Boris Brezillon
                   ` (5 subsequent siblings)
  19 siblings, 2 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

This takes the form of various helpers, plus the addition of 2 new
structs:
* drm_bus_caps: describe the bus capabilities of a bridge/encoder. For
  bridges we have one for the input port and one for the output port.
  Encoders just have one output port.
* drm_bus_cfg: added to the drm_bridge_state. It's supposed to store
  bus configuration information. For now we just have format and flags
  but more fields might be added in the future. Again, each
  drm_bridge_state contains 2 drm_bus_cfg elements: one for the output
  port and one for the input port

Helpers can be used from bridge drivers' ->atomic_check() implementation
to negotiate the bus format to use. Negotiation happens in reserve order,
starting from the last element of the bridge chain (the one directly
connected to the display) to the first element of the chain (the one
connected to the encoder).

Negotiation usually takes place in 2 steps:
* make sure the input end of the next element in the chain picked a
  format that's supported by the output end of our bridge. That's done
  with drm_atomic_bridge_choose_output_bus_cfg().
* choose a format for the input end of our bridge based on what's
  supported by the previous bridge in the chain. This is achieved by
  calling drm_atomic_bridge_choose_input_bus_cfg()

Note that those helpers are a bit lax when it comes to unitialized
bus format validation. That's intentional. If we don't do that we'll
basically break things if we start adding support for bus format
negotiation to some elements of the pipeline leaving others on the
side, and that's likely to happen for all external bridges since we
can't necessarily tell where they are used.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/drm_bridge.c | 187 +++++++++++++++++++++++++++++++++++
 include/drm/drm_bridge.h     |  46 +++++++++
 include/drm/drm_encoder.h    |   6 ++
 3 files changed, 239 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 9efb27087e70..ef072df42422 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -602,6 +602,193 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
 
+int drm_find_best_bus_format(const struct drm_bus_caps *a,
+			     const struct drm_bus_caps *b,
+			     const struct drm_display_mode *mode,
+			     u32 *selected_bus_fmt)
+{
+	unsigned int i, j;
+
+	/*
+	 * Some drm_bridge/drm_encoder don't care about the input/output bus
+	 * format, let's set the format to zero in that case (this is only
+	 * valid if both side of the link don't care).
+	 */
+	if (!a->num_supported_fmts && !b->num_supported_fmts) {
+		*selected_bus_fmt = 0;
+		return 0;
+	} else if (b->num_supported_fmts > 1 && b->supported_fmts) {
+		*selected_bus_fmt = b->supported_fmts[0];
+		return 0;
+	} else if (a->num_supported_fmts > 1 && a->supported_fmts) {
+		*selected_bus_fmt = a->supported_fmts[0];
+		return 0;
+	} else if (!a->num_supported_fmts || !a->supported_fmts ||
+		   !b->num_supported_fmts || !b->supported_fmts) {
+		return -EINVAL;
+	}
+
+	/*
+	 * TODO:
+	 * Dummy algo picking the first match. We probably want something
+	 * smarter where the narrowest format (in term of bus width) that
+	 * does not incur data loss is picked, and if all possible formats
+	 * are lossy, pick the one that's less lossy among all the choices
+	 * we have. In order to do that we'd need to convert MEDIA_BUS_FMT_
+	 * modes into something like drm_format_info.
+	 */
+	for (i = 0; i < a->num_supported_fmts; i++) {
+		for (j = 0; j < b->num_supported_fmts; j++) {
+			if (a->supported_fmts[i] == b->supported_fmts[j]) {
+				*selected_bus_fmt = a->supported_fmts[i];
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(drm_find_best_bus_format);
+
+/**
+ * drm_atomic_bridge_choose_input_bus_cfg() - Choose bus config for the input
+ *					      end
+ * @bridge_state: bridge state
+ * @crtc_state: CRTC state
+ * @conn_state: connector state
+ *
+ * Choose a bus format for the input side of a bridge based on what the
+ * previous bridge in the chain and this bridge support. Can be called from
+ * bridge drivers' &drm_bridge_funcs.atomic_check() implementation.
+ *
+ * RETURNS:
+ * 0 if a matching format was found, a negative error code otherwise
+ */
+int
+drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
+				       struct drm_crtc_state *crtc_state,
+				       struct drm_connector_state *conn_state)
+{
+	struct drm_bridge *self = bridge_state->bridge;
+	struct drm_bus_caps *prev_output_bus_caps;
+	struct drm_bridge *prev;
+	int ret;
+
+	prev = drm_bridge_chain_get_prev_bridge(self);
+	if (!prev)
+		prev_output_bus_caps = &self->encoder->output_bus_caps;
+	else
+		prev_output_bus_caps = &prev->output_bus_caps;
+
+	ret = drm_find_best_bus_format(prev_output_bus_caps,
+				       &self->input_bus_caps, &crtc_state->mode,
+				       &bridge_state->input_bus_cfg.fmt);
+	if (ret)
+		return ret;
+
+	/*
+	 * TODO:
+	 * Should we fill/check the ->flag field too?
+	 */
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_bridge_choose_input_bus_cfg);
+
+/**
+ * drm_atomic_bridge_choose_output_bus_cfg() - Choose bus config for the output
+ *					       end
+ * @bridge_state: bridge state
+ * @crtc_state: CRTC state
+ * @conn_state: connector state
+ *
+ * Choose a bus format for the output side of a bridge based on what the next
+ * bridge in the chain and this bridge support. Can be called from bridge
+ * drivers' &drm_bridge_funcs.atomic_check() implementation.
+ *
+ * RETURNS:
+ * 0 if a matching format was found, a negative error code otherwise
+ */
+int
+drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	struct drm_atomic_state *state = crtc_state->state;
+	struct drm_bridge *self = bridge_state->bridge;
+	struct drm_bridge_state *next_bridge_state;
+	struct drm_bridge *next;
+	u32 fmt;
+
+	next = drm_bridge_chain_get_next_bridge(self);
+	if (!next) {
+		struct drm_connector *conn = conn_state->connector;
+		struct drm_display_info *di = &conn->display_info;
+
+		/*
+		 * FIXME:
+		 * We currently pick the first supported format
+		 * unconditionally. It seems to fit all current use cases but
+		 * might be too limited for panels/displays that can configure
+		 * the bus format dynamically.
+		 */
+		if (di->num_bus_formats && di->bus_formats)
+			bridge_state->output_bus_cfg.fmt = di->bus_formats[0];
+		else
+			bridge_state->output_bus_cfg.fmt = 0;
+
+		bridge_state->output_bus_cfg.flags = di->bus_flags;
+		return 0;
+	}
+
+	/*
+	 * We expect output_bus_caps to contain at least one format. Note
+	 * that don't care about bus format negotiation can simply not
+	 * call this helper.
+	 */
+	if (!self->output_bus_caps.num_supported_fmts ||!
+	    !self->output_bus_caps.supported_fmts)
+		return -EINVAL;
+
+	next_bridge_state = drm_atomic_get_new_bridge_state(state, next);
+
+	/*
+	 * The next bridge is expected to have called
+	 * &drm_atomic_bridge_choose_input_bus_cfg() as part of its
+	 * &drm_bridge_funcs.atomic_check() implementation, but this hook is
+	 * optional, and even if it's implemented, calling
+	 * &drm_atomic_bridge_choose_input_bus_cfg() is not mandated.
+	 * If fmt is zero, that means the next element in the chain doesn't
+	 * care about bus format negotiation (probably because there's only
+	 * one possible setting). In that case, we still have to select one
+	 * bus format for the output port of our bridge, and this is only
+	 * possible if the bridge supports only one format.
+	 */
+	fmt = next_bridge_state->input_bus_cfg.fmt;
+	if (fmt) {
+		unsigned int i;
+
+		for (i = 0; i < self->output_bus_caps.num_supported_fmts; i++) {
+			if (self->output_bus_caps.supported_fmts[i] == fmt)
+				break;
+		}
+
+		if (i == self->output_bus_caps.num_supported_fmts)
+			return -ENOTSUPP;
+	} else if (self->output_bus_caps.num_supported_fmts == 1) {
+		fmt = self->output_bus_caps.supported_fmts[0];
+	} else {
+		return -EINVAL;
+	}
+
+	/*
+	 * TODO:
+	 * Should we fill/check the ->flag field too?
+	 */
+	bridge_state->output_bus_cfg.fmt = fmt;
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_bridge_choose_output_bus_cfg);
+
 static int drm_atomic_bridge_check(struct drm_bridge *bridge,
 				   struct drm_crtc_state *crtc_state,
 				   struct drm_connector_state *conn_state)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 2f69adb7b0f3..c578800a05e0 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -33,15 +33,45 @@ struct drm_bridge;
 struct drm_bridge_timings;
 struct drm_panel;
 
+/**
+ * struct drm_bus_cfg - bus configuration
+ * @fmt: format used on this bus
+ * @flags: DRM_BUS_ flags used on this bus
+ *
+ * Encodes the bus format and bus flags used by one end of the bridge or
+ * by the encoder output.
+ */
+struct drm_bus_cfg {
+	u32 fmt;
+	u32 flags;
+};
+
+/**
+ * struct drm_bus_caps - bus capabilities
+ * @supported_fmts: array of MEDIA_BUS_FMT_ formats
+ * @num_supported_fmts: size of the supported_fmts array
+ *
+ * Used by the core to negotiate the bus format at runtime.
+ */
+struct drm_bus_caps {
+	const u32 *supported_fmts;
+	unsigned int num_supported_fmts;
+};
+
 /**
  * struct drm_bridge_state - Atomic bridge state object
  * @base: inherit from &drm_private_state
  * @bridge: the bridge this state refers to
+ * @input_bus_info: input bus information
+ * @output_bus_info: output bus information
  */
 struct drm_bridge_state {
 	struct drm_private_state base;
 
 	struct drm_bridge *bridge;
+
+	struct drm_bus_cfg input_bus_cfg;
+	struct drm_bus_cfg output_bus_cfg;
 };
 
 static inline struct drm_bridge_state *
@@ -465,6 +495,9 @@ struct drm_bridge {
 	const struct drm_bridge_funcs *funcs;
 	/** @driver_private: pointer to the bridge driver's internal context */
 	void *driver_private;
+
+	struct drm_bus_caps input_bus_caps;
+	struct drm_bus_caps output_bus_caps;
 };
 
 static inline struct drm_bridge *
@@ -479,6 +512,14 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
 int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 		      struct drm_bridge *previous);
 
+int
+drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
+				       struct drm_crtc_state *crtc_state,
+				       struct drm_connector_state *conn_state);
+int
+drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state);
 struct drm_bridge *
 drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder);
 struct drm_bridge *
@@ -562,6 +603,11 @@ drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
 	return drm_priv_to_bridge_state(obj_state);
 }
 
+int drm_find_best_bus_format(const struct drm_bus_caps *a,
+			     const struct drm_bus_caps *b,
+			     const struct drm_display_mode *mode,
+			     u32 *selected_bus_fmt);
+
 #ifdef CONFIG_DRM_PANEL_BRIDGE
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
 					u32 connector_type);
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 0899f7f34e3a..e891921b3aed 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -25,6 +25,7 @@
 
 #include <linux/list.h>
 #include <linux/ctype.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_mode.h>
 #include <drm/drm_mode_object.h>
@@ -184,6 +185,11 @@ struct drm_encoder {
 	 * functions as part of its encoder enable/disable handling.
 	 */
 	uint32_t custom_bridge_enable_disable_seq : 1;
+
+	/**
+	 * @output_bus_caps: Supported output bus caps
+	 */
+	struct drm_bus_caps output_bus_caps;
 };
 
 #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
-- 
2.21.0

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

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

* [PATCH RFC 15/19] drm/imx: pd: Use bus format/flags provided by the bridge when available
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (13 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 16/19] drm/bridge: lvds-encoder: Add a way to support custom ->atomic_check() implem Boris Brezillon
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Now that bridges can expose the bus format/flags they expect, we can
use those instead of the relying on the display_info provided by the
connector (which is only valid if the encoder is directly connected
to bridge element driving the panel/display).

We also explicitly expose the bus formats supported by our encoder by
filling encoder->output_bus_caps with proper info.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/imx/parallel-display.c | 28 +++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 35f20edab9fd..57fee48d6bb6 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -115,8 +115,18 @@ static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder,
 	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
 	struct drm_display_info *di = &conn_state->connector->display_info;
 	struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+	struct drm_bridge_state *bridge_state = NULL;
+	struct drm_bridge *bridge;
 
-	if (!imxpd->bus_format && di->num_bus_formats) {
+	bridge = drm_bridge_chain_get_first_bridge(encoder);
+	if (bridge)
+		bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
+							       bridge);
+
+	if (bridge_state && bridge_state->input_bus_cfg.fmt) {
+		imx_crtc_state->bus_format = bridge_state->input_bus_cfg.fmt;
+		imx_crtc_state->bus_flags = bridge_state->input_bus_cfg.flags;
+	} else if (!imxpd->bus_format && di->num_bus_formats) {
 		imx_crtc_state->bus_flags = di->bus_flags;
 		imx_crtc_state->bus_format = di->bus_formats[0];
 	} else {
@@ -152,10 +162,18 @@ static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
 	.atomic_check = imx_pd_encoder_atomic_check,
 };
 
+static const u32 imx_pd_bus_fmts[] = {
+	MEDIA_BUS_FMT_RGB888_1X24,
+	MEDIA_BUS_FMT_RGB565_1X16,
+	MEDIA_BUS_FMT_RGB666_1X18,
+	MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
+};
+
 static int imx_pd_register(struct drm_device *drm,
 	struct imx_parallel_display *imxpd)
 {
 	struct drm_encoder *encoder = &imxpd->encoder;
+	struct drm_bus_caps *bus_caps = &encoder->output_bus_caps;
 	int ret;
 
 	ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node);
@@ -173,6 +191,14 @@ static int imx_pd_register(struct drm_device *drm,
 	drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs,
 			 DRM_MODE_ENCODER_NONE, NULL);
 
+	if (imxpd->bus_format) {
+		bus_caps->supported_fmts = &imxpd->bus_format;
+		bus_caps->num_supported_fmts = 1;
+	} else {
+		bus_caps->supported_fmts = imx_pd_bus_fmts;
+		bus_caps->num_supported_fmts = ARRAY_SIZE(imx_pd_bus_fmts);
+	}
+
 	if (!imxpd->bridge) {
 		drm_connector_helper_add(&imxpd->connector,
 				&imx_pd_connector_helper_funcs);
-- 
2.21.0

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

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

* [PATCH RFC 16/19] drm/bridge: lvds-encoder: Add a way to support custom ->atomic_check() implem
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (14 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 15/19] drm/imx: pd: Use bus format/flags provided by the bridge when available Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-08 15:11 ` [PATCH RFC 17/19] drm/bridge: lvds-encoder: Implement bus format negotiation for sn75lvds83 Boris Brezillon
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Some LVDS drivers might want to negotiate the bus format with the
previous element in the encoder chain. Let's define a chip-specific ops
structure that contains an ->atomic_check() hook and plug that to the
drm_bridge->atomic_check() infra.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/bridge/lvds-encoder.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
index 2ab2c234f26c..da7013c5faf1 100644
--- a/drivers/gpu/drm/bridge/lvds-encoder.c
+++ b/drivers/gpu/drm/bridge/lvds-encoder.c
@@ -6,16 +6,25 @@
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 
 #include <drm/drm_bridge.h>
 #include <drm/drm_panel.h>
 
+struct lvds_encoder_ops {
+	int (*atomic_check)(struct drm_bridge *bridge,
+			    struct drm_bridge_state *bride_state,
+			    struct drm_crtc_state *crtc_state,
+			    struct drm_connector_state *conn_state);
+};
+
 struct lvds_encoder {
 	struct drm_bridge bridge;
 	struct drm_bridge *panel_bridge;
 	struct gpio_desc *powerdown_gpio;
+	const struct lvds_encoder_ops *ops;
 };
 
 static int lvds_encoder_attach(struct drm_bridge *bridge)
@@ -48,10 +57,27 @@ static void lvds_encoder_disable(struct drm_bridge *bridge)
 		gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1);
 }
 
+static int lvds_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)
+{
+	struct lvds_encoder *lvds_encoder = container_of(bridge,
+							 struct lvds_encoder,
+							 bridge);
+
+	if (!lvds_encoder->ops && !lvds_encoder->ops->atomic_check)
+		return 0;
+
+	return lvds_encoder->ops->atomic_check(bridge, bridge_state,
+					       crtc_state, conn_state);
+}
+
 static struct drm_bridge_funcs funcs = {
 	.attach = lvds_encoder_attach,
 	.enable = lvds_encoder_enable,
 	.disable = lvds_encoder_disable,
+	.atomic_check = lvds_encoder_atomic_check,
 };
 
 static int lvds_encoder_probe(struct platform_device *pdev)
@@ -67,6 +93,7 @@ static int lvds_encoder_probe(struct platform_device *pdev)
 	if (!lvds_encoder)
 		return -ENOMEM;
 
+	lvds_encoder->ops = of_device_get_match_data(&pdev->dev);
 	lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
 							       GPIOD_OUT_HIGH);
 	if (IS_ERR(lvds_encoder->powerdown_gpio)) {
-- 
2.21.0

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

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

* [PATCH RFC 17/19] drm/bridge: lvds-encoder: Implement bus format negotiation for sn75lvds83
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (15 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 16/19] drm/bridge: lvds-encoder: Add a way to support custom ->atomic_check() implem Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-22  0:32   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 18/19] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel Boris Brezillon
                   ` (2 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

The SN75LVDS83 bridge support several input formats except the input
format is directly related to the expected output format. Let's express
that constraint by setting the bridge_state->output_bus_cfg.fmt field
to the appropriate value.

The previous element in the chain might be able to use this information
to pick the appropriate output bus format.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 drivers/gpu/drm/bridge/lvds-encoder.c | 48 +++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
index da7013c5faf1..8d399d1828b0 100644
--- a/drivers/gpu/drm/bridge/lvds-encoder.c
+++ b/drivers/gpu/drm/bridge/lvds-encoder.c
@@ -159,9 +159,57 @@ static int lvds_encoder_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int sn75lvds83_atomic_check(struct drm_bridge *bridge,
+				   struct drm_bridge_state *bridge_state,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_connector_state *conn_state)
+{
+	int ret;
+
+	ret = drm_atomic_bridge_choose_output_bus_cfg(bridge_state, crtc_state,
+						      conn_state);
+	if (ret)
+		return ret;
+
+	/*
+	 * The output bus format has a direct impact on the expected input bus
+	 * format.
+	 */
+	switch (bridge_state->output_bus_cfg.fmt) {
+	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+		/*
+		 * JEIDA and SPWG variants theoretically require different pin
+		 * mapping, but MEDIA_BUS_FMT_ definitions do not allow
+		 * fined-grained pin placement definition, and this is
+		 * something we expect to be taken care of at board design
+		 * time, so let's ignore this for now.
+		 * If it becomes a problem, we can always add a way to override
+		 * the bus format with a FW property.
+		 */
+		bridge_state->input_bus_cfg.fmt = MEDIA_BUS_FMT_RGB888_1X24;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+		bridge_state->input_bus_cfg.fmt = MEDIA_BUS_FMT_RGB666_1X18;
+		break;
+	default:
+		bridge_state->input_bus_cfg.fmt = 0;
+		break;
+	}
+
+	/* Propagate the bus_flags. */
+	bridge_state->input_bus_cfg.flags = bridge_state->output_bus_cfg.flags;
+	return 0;
+}
+
+static const struct lvds_encoder_ops sn75lvds83_ops = {
+	.atomic_check = sn75lvds83_atomic_check,
+};
+
 static const struct of_device_id lvds_encoder_match[] = {
 	{ .compatible = "lvds-encoder" },
 	{ .compatible = "thine,thc63lvdm83d" },
+	{ .compatible = "ti,sn75lvds83", .data = &sn75lvds83_ops },
 	{},
 };
 MODULE_DEVICE_TABLE(of, lvds_encoder_match);
-- 
2.21.0

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

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

* [PATCH RFC 18/19] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (16 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 17/19] drm/bridge: lvds-encoder: Implement bus format negotiation for sn75lvds83 Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-22  0:36   ` Laurent Pinchart
  2019-08-08 15:11 ` [PATCH RFC 19/19] ARM: dts: imx: imx51-zii-rdu1: Fix the display pipeline definition Boris Brezillon
  2019-08-09  6:58 ` [PATCH RFC 00/19] drm: Add support for bus-format negotiation Neil Armstrong
  19 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

Add a new entry for the Toshiba LTA089AC29000 panel.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 .../display/panel/toshiba,lt089ac29000.txt    |  5 ++-
 drivers/gpu/drm/panel/panel-simple.c          | 36 +++++++++++++++++++
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
index 89826116628c..26ebfa098966 100644
--- a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
+++ b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
@@ -1,7 +1,10 @@
 Toshiba 8.9" WXGA (1280x768) TFT LCD panel
 
 Required properties:
-- compatible: should be "toshiba,lt089ac29000"
+- compatible: should be one of the following
+	      "toshiba,lt089ac29000"
+	      "toshiba,lta089ac29000"
+
 - power-supply: as specified in the base binding
 
 This binding is compatible with the simple-panel binding, which is specified
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index bff7578f84dd..4c1deed44ce2 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2857,6 +2857,39 @@ static const struct panel_desc toshiba_lt089ac29000 = {
 	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
 };
 
+static const struct drm_display_mode toshiba_lta089ac29000_mode = {
+	.clock = 79500,
+	.hdisplay = 1280,
+	.hsync_start = 1280 + 192,
+	.hsync_end = 1280 + 192 + 128,
+	.htotal = 1280 + 192 + 128 + 64,
+	.vdisplay = 768,
+	.vsync_start = 768 + 20,
+	.vsync_end = 768 + 20 + 7,
+	.vtotal = 768 + 20 + 7 + 3,
+	.vrefresh = 60,
+};
+
+static const struct panel_desc toshiba_lta089ac29000 = {
+	.modes = &toshiba_lta089ac29000_mode,
+	.num_modes = 1,
+	.size = {
+		.width = 194,
+		.height = 116,
+	},
+	/*
+	 * FIXME:
+	 * The panel supports 2 bus formats: jeida-24 and jeida-18. The
+	 * mode is selected through the 8b6b_SEL pin. If anyone ever needs
+	 * support for jeida-18 we should probably parse the 'data-mapping'
+	 * property.
+	 * In the unlikely event where 8b6b_SEL is connected to a GPIO, we'd
+	 * need a new infra to allow bus format negotiation at the panel level.
+	 */
+	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
+	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
+};
+
 static const struct drm_display_mode tpk_f07a_0102_mode = {
 	.clock = 33260,
 	.hdisplay = 800,
@@ -3305,6 +3338,9 @@ static const struct of_device_id platform_of_match[] = {
 	}, {
 		.compatible = "toshiba,lt089ac29000",
 		.data = &toshiba_lt089ac29000,
+	}, {
+		.compatible = "toshiba,lta089ac29000",
+		.data = &toshiba_lta089ac29000,
 	}, {
 		.compatible = "tpk,f07a-0102",
 		.data = &tpk_f07a_0102,
-- 
2.21.0

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

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

* [PATCH RFC 19/19] ARM: dts: imx: imx51-zii-rdu1: Fix the display pipeline definition
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (17 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 18/19] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel Boris Brezillon
@ 2019-08-08 15:11 ` Boris Brezillon
  2019-08-09  6:58 ` [PATCH RFC 00/19] drm: Add support for bus-format negotiation Neil Armstrong
  19 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 15:11 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	Boris Brezillon, kernel, Sam Ravnborg

The current definition does not represent the exact display pipeline we
have on the board: the LVDS panel is actually connected through a
parallel -> LVDS bridge. Let's fix that so the driver can select the
proper bus format on the CRTC end.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 arch/arm/boot/dts/imx51-zii-rdu1.dts | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/imx51-zii-rdu1.dts b/arch/arm/boot/dts/imx51-zii-rdu1.dts
index 3596060f52e7..db006a4d4250 100644
--- a/arch/arm/boot/dts/imx51-zii-rdu1.dts
+++ b/arch/arm/boot/dts/imx51-zii-rdu1.dts
@@ -95,11 +95,31 @@
 			reg = <1>;
 
 			display_out: endpoint {
-				remote-endpoint = <&panel_in>;
+				remote-endpoint = <&lvds_encoder_in>;
 			};
 		};
 	};
 
+        lvds-encoder {
+                compatible = "ti,sn75lvds83", "lvds-encoder";
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                        reg = <0>;
+                        lvds_encoder_in: endpoint {
+                                remote-endpoint = <&display_out>;
+                        };
+                };
+
+                port@1 {
+                        reg = <1>;
+                        lvds_encoder_out: endpoint {
+                                remote-endpoint = <&panel_in>;
+                        };
+                };
+        };
+
 	panel {
 		/* no compatible here, bootloader will patch in correct one */
 		pinctrl-names = "default";
@@ -110,7 +130,7 @@
 
 		port {
 			panel_in: endpoint {
-				remote-endpoint = <&display_out>;
+				remote-endpoint = <&lvds_encoder_out>;
 			};
 		};
 	};
-- 
2.21.0

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

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

* Re: [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h
  2019-08-08 15:11 ` [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h Boris Brezillon
@ 2019-08-08 18:05   ` Sam Ravnborg
  2019-08-20 18:53   ` Laurent Pinchart
  1 sibling, 0 replies; 58+ messages in thread
From: Sam Ravnborg @ 2019-08-08 18:05 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, dri-devel, Kyungmin Park, Thierry Reding,
	Chris Healy, kernel

Hi Boris.

Good to see that you kept the alphabetical order in the include files.
One nit below.
With this fixed:
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>

	Sam

> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> index 982865866a29..c681a9e22484 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> @@ -7,6 +7,8 @@
>  #ifndef __HDMI_CONNECTOR_H__
>  #define __HDMI_CONNECTOR_H__
>  
> +#include <drm/drm_bridge.h>
> +
>  #include <linux/i2c.h>
>  #include <linux/clk.h>
>  #include <linux/platform_device.h>

Please follow the same order of include blocks as we see in other files:

#include <linux/*.h>

#include <drm/*.h>

#include "*.h"

And with an empty line between the blocks, and sorted withint the
blocks.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 03/19] drm/vc4: Get rid of the dsi->bridge field
  2019-08-08 15:11 ` [PATCH RFC 03/19] drm/vc4: Get rid of the dsi->bridge field Boris Brezillon
@ 2019-08-08 20:31   ` Eric Anholt
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Anholt @ 2019-08-08 20:31 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Jonas Karlman, Neil Armstrong, Seung-Woo Kim,
	Kyungmin Park, Thierry Reding, Laurent Pinchart, Boris Brezillon,
	kernel, Sam Ravnborg, Chris Healy


[-- Attachment #1.1: Type: text/plain, Size: 283 bytes --]

Boris Brezillon <boris.brezillon@collabora.com> writes:

> Now that we have an official way to request custom encoder/bridge
> enable/disable sequences we can get rid of the extra ->bridge field
> and use the encoder one.

Patch 2, 3 are:

Reviewed-by: Eric Anholt <eric@anholt.net>

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

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next
  2019-08-08 15:11 ` [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next Boris Brezillon
@ 2019-08-08 21:04   ` Boris Brezillon
  2019-08-21 14:01   ` Laurent Pinchart
  1 sibling, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-08 21:04 UTC (permalink / raw)
  To: dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Neil Armstrong, Jonas Karlman,
	Seung-Woo Kim, Kyungmin Park, Thierry Reding, Chris Healy,
	kernel, Sam Ravnborg

On Thu,  8 Aug 2019 17:11:36 +0200
Boris Brezillon <boris.brezillon@collabora.com> wrote:

> bridge->next is only points to the new bridge if drm_bridge_attach()

		^/is//

> succeeds. No need to reset it manually here.
> 
> Note that this change is part of the attempt to make the bridge chain
> a double-linked list. In order to do that we must patch all drivers
> manipulating the bridge->next field.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/exynos/exynos_dp.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 1e6aa24bf45e..4785885c0f4f 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -110,7 +110,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>  		if (ret) {
>  			DRM_DEV_ERROR(dp->dev,
>  				      "Failed to attach bridge to drm\n");
> -			bridge->next = NULL;
>  			return ret;
>  		}
>  	}

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

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

* Re: [PATCH RFC 00/19] drm: Add support for bus-format negotiation
  2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
                   ` (18 preceding siblings ...)
  2019-08-08 15:11 ` [PATCH RFC 19/19] ARM: dts: imx: imx51-zii-rdu1: Fix the display pipeline definition Boris Brezillon
@ 2019-08-09  6:58 ` Neil Armstrong
  19 siblings, 0 replies; 58+ messages in thread
From: Neil Armstrong @ 2019-08-09  6:58 UTC (permalink / raw)
  To: Boris Brezillon, dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Jonas Karlman, Seung-Woo Kim,
	Kyungmin Park, Thierry Reding, Chris Healy, kernel, Sam Ravnborg

Hi Boris,

On 08/08/2019 17:11, Boris Brezillon wrote:
> Hello,
> 
> This patch series aims at adding support for runtime bus-format
> negotiation between all elements of the
> 'encoder -> bridges -> connector/display' section of the pipeline.

It was one of the big subject of the dw-hdmi support of 10/12/16bit and
YUV420 output, and the bridge states was plannes, and I'm happy you did it !

I'll ASAP to try implementing the dw-hdmi YUV420 and YUV444 output support with
this patchset, but overall with my limited knowledge, it looks globally sane !

Neil

> 
> In order to support that, we need drm bridges to fully take part in the
> atomic state validation process, which requires addition of a
> drm_bridge_state + a new drm_bridge_funcs.atomic_check() hook (patches
> 10 - 12).
> Once those basic building blocks are in place, we can add new helpers
> to facilitate bus-format negotiation between element of the encoder
> chain (patches 13 - 14).
> 
> Patches 1 to 9 are preparatory patches for patches 10 - 14. Patch 1 is
> needed to allow inclusion of drm_atomic.h from drm_bridge.h, which we
> need to make drm_bridge/drm_bridge_state inherit from
> drm_private_obj/drm_private_obj_state.
> Patches 2 to 9 are about transitioning the bridge chain to a
> double-linked list, which is needed to allow bridge elements to
> negotiate with the next and prev element in the pipeline.
> Most of those patches can be applied independently of the rest of the
> series, especially patches 2 - 7 which I think fix some misuses of the
> drm_bridge API.
> 
> To finish, patches 15 - 17 demonstrate how bus-format negotiation can
> be done, and patches 18 - 19 were needed for the use case I used to test
> whole solution.
> 
> As you've noticed, this is an RFC, so any kind of feedback is welcome
> (apart from checkpatch reports :P).
> 
> Thanks,
> 
> Boris
> 
> Boris Brezillon (19):
>   drm: Stop including drm_bridge.h from drm_crtc.h
>   drm: Support custom encoder/bridge enable/disable sequences officially
>   drm/vc4: Get rid of the dsi->bridge field
>   drm/exynos: Get rid of exynos_dsi->out_bridge
>   drm/exynos: Don't reset bridge->next
>   drm/bridge: Create drm_bridge_chain_xx() wrappers
>   drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder
>   drm/bridge: Introduce drm_bridge_chain_get_{first,last,next}_bridge()
>   drm/bridge: Make the bridge chain a double-linked list
>   drm/bridge: Add a drm_bridge_state object
>   drm/bridge: Patch atomic hooks to take a drm_bridge_state
>   drm/bridge: Add an ->atomic_check() hook
>   drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper
>   drm/bridge: Add the necessary bits to support bus format negotiation
>   drm/imx: pd: Use bus format/flags provided by the bridge when
>     available
>   drm/bridge: lvds-encoder: Add a way to support custom ->atomic_check()
>     implem
>   drm/bridge: lvds-encoder: Implement bus format negotiation for
>     sn75lvds83
>   drm/panel: simple: Add support for Toshiba LTA089AC29000 panel
>   ARM: dts: imx: imx51-zii-rdu1: Fix the display pipeline definition
> 
>  .../display/panel/toshiba,lt089ac29000.txt    |   5 +-
>  arch/arm/boot/dts/imx51-zii-rdu1.dts          |  24 +-
>  drivers/gpu/drm/arc/arcpgu_hdmi.c             |   1 +
>  drivers/gpu/drm/bridge/analogix-anx78xx.c     |   1 +
>  .../drm/bridge/analogix/analogix_dp_core.c    |  13 +-
>  drivers/gpu/drm/bridge/dumb-vga-dac.c         |   1 +
>  drivers/gpu/drm/bridge/lvds-encoder.c         |  75 ++
>  .../bridge/megachips-stdpxxxx-ge-b850v3-fw.c  |   1 +
>  drivers/gpu/drm/bridge/nxp-ptn3460.c          |   1 +
>  drivers/gpu/drm/bridge/panel.c                |   1 +
>  drivers/gpu/drm/bridge/parade-ps8622.c        |   1 +
>  drivers/gpu/drm/bridge/sii902x.c              |   1 +
>  drivers/gpu/drm/bridge/sii9234.c              |   1 +
>  drivers/gpu/drm/bridge/sil-sii8620.c          |   1 +
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c     |   1 +
>  drivers/gpu/drm/bridge/tc358764.c             |   1 +
>  drivers/gpu/drm/bridge/tc358767.c             |   1 +
>  drivers/gpu/drm/bridge/ti-sn65dsi86.c         |   1 +
>  drivers/gpu/drm/bridge/ti-tfp410.c            |   1 +
>  drivers/gpu/drm/drm_atomic.c                  |  40 +
>  drivers/gpu/drm/drm_atomic_helper.c           |  46 +-
>  drivers/gpu/drm/drm_bridge.c                  | 794 ++++++++++++++----
>  drivers/gpu/drm/drm_crtc_helper.c             |  46 +-
>  drivers/gpu/drm/drm_encoder.c                 |  16 +-
>  drivers/gpu/drm/drm_probe_helper.c            |   3 +-
>  drivers/gpu/drm/drm_simple_kms_helper.c       |   1 +
>  drivers/gpu/drm/exynos/exynos_dp.c            |   2 +-
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c       |  18 +-
>  drivers/gpu/drm/exynos/exynos_drm_mic.c       |   1 +
>  drivers/gpu/drm/exynos/exynos_hdmi.c          |   1 +
>  drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c     |   1 +
>  drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c  |   1 +
>  drivers/gpu/drm/i2c/tda998x_drv.c             |   1 +
>  drivers/gpu/drm/imx/imx-ldb.c                 |   1 +
>  drivers/gpu/drm/imx/parallel-display.c        |  29 +-
>  drivers/gpu/drm/ingenic/ingenic-drm.c         |   1 +
>  drivers/gpu/drm/mediatek/mtk_dpi.c            |   1 +
>  drivers/gpu/drm/mediatek/mtk_dsi.c            |   1 +
>  drivers/gpu/drm/mediatek/mtk_hdmi.c           |   7 +-
>  drivers/gpu/drm/msm/dsi/dsi.h                 |   1 +
>  drivers/gpu/drm/msm/edp/edp.c                 |   4 +-
>  drivers/gpu/drm/msm/edp/edp.h                 |   1 +
>  drivers/gpu/drm/msm/edp/edp_bridge.c          |   2 +-
>  drivers/gpu/drm/msm/hdmi/hdmi.c               |   4 +-
>  drivers/gpu/drm/msm/hdmi/hdmi.h               |   2 +
>  drivers/gpu/drm/omapdrm/dss/output.c          |   1 +
>  drivers/gpu/drm/omapdrm/omap_drv.c            |   8 +-
>  drivers/gpu/drm/omapdrm/omap_encoder.c        |   4 +-
>  drivers/gpu/drm/panel/panel-simple.c          |  36 +
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c        |  10 +-
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c     |   1 +
>  drivers/gpu/drm/rockchip/rockchip_lvds.c      |   1 +
>  drivers/gpu/drm/rockchip/rockchip_rgb.c       |   1 +
>  drivers/gpu/drm/sti/sti_dvo.c                 |   1 +
>  drivers/gpu/drm/sti/sti_hda.c                 |   1 +
>  drivers/gpu/drm/sti/sti_hdmi.c                |   1 +
>  drivers/gpu/drm/sun4i/sun4i_lvds.c            |   1 +
>  drivers/gpu/drm/sun4i/sun4i_rgb.c             |   1 +
>  drivers/gpu/drm/sun4i/sun4i_tcon.c            |   1 +
>  drivers/gpu/drm/tilcdc/tilcdc_external.c      |   1 +
>  drivers/gpu/drm/vc4/vc4_dsi.c                 |  38 +-
>  include/drm/drm_atomic.h                      |   3 +
>  include/drm/drm_bridge.h                      | 252 +++++-
>  include/drm/drm_crtc.h                        |   1 -
>  include/drm/drm_encoder.h                     |  19 +-
>  65 files changed, 1242 insertions(+), 297 deletions(-)
> 

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

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

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-08 15:11 ` [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation Boris Brezillon
@ 2019-08-14  7:51   ` Neil Armstrong
  2019-08-21 18:31     ` Boris Brezillon
  2019-08-22  0:55   ` Laurent Pinchart
  1 sibling, 1 reply; 58+ messages in thread
From: Neil Armstrong @ 2019-08-14  7:51 UTC (permalink / raw)
  To: Boris Brezillon, dri-devel
  Cc: Jernej Skrabec, Laurent Pinchart, Jonas Karlman, Seung-Woo Kim,
	Kyungmin Park, Thierry Reding, Chris Healy, kernel, Sam Ravnborg

On 08/08/2019 17:11, Boris Brezillon wrote:
> This takes the form of various helpers, plus the addition of 2 new
> structs:
> * drm_bus_caps: describe the bus capabilities of a bridge/encoder. For
>   bridges we have one for the input port and one for the output port.
>   Encoders just have one output port.
> * drm_bus_cfg: added to the drm_bridge_state. It's supposed to store
>   bus configuration information. For now we just have format and flags
>   but more fields might be added in the future. Again, each
>   drm_bridge_state contains 2 drm_bus_cfg elements: one for the output
>   port and one for the input port
> 
> Helpers can be used from bridge drivers' ->atomic_check() implementation
> to negotiate the bus format to use. Negotiation happens in reserve order,
> starting from the last element of the bridge chain (the one directly
> connected to the display) to the first element of the chain (the one
> connected to the encoder).
> 
> Negotiation usually takes place in 2 steps:
> * make sure the input end of the next element in the chain picked a
>   format that's supported by the output end of our bridge. That's done
>   with drm_atomic_bridge_choose_output_bus_cfg().
> * choose a format for the input end of our bridge based on what's
>   supported by the previous bridge in the chain. This is achieved by
>   calling drm_atomic_bridge_choose_input_bus_cfg()
> 
> Note that those helpers are a bit lax when it comes to unitialized
> bus format validation. That's intentional. If we don't do that we'll
> basically break things if we start adding support for bus format
> negotiation to some elements of the pipeline leaving others on the
> side, and that's likely to happen for all external bridges since we
> can't necessarily tell where they are used.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/drm_bridge.c | 187 +++++++++++++++++++++++++++++++++++
>  include/drm/drm_bridge.h     |  46 +++++++++
>  include/drm/drm_encoder.h    |   6 ++
>  3 files changed, 239 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 9efb27087e70..ef072df42422 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -602,6 +602,193 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
>  
> +int drm_find_best_bus_format(const struct drm_bus_caps *a,
> +			     const struct drm_bus_caps *b,
> +			     const struct drm_display_mode *mode,
> +			     u32 *selected_bus_fmt)
> +{
> +	unsigned int i, j;
> +
> +	/*
> +	 * Some drm_bridge/drm_encoder don't care about the input/output bus
> +	 * format, let's set the format to zero in that case (this is only
> +	 * valid if both side of the link don't care).
> +	 */
> +	if (!a->num_supported_fmts && !b->num_supported_fmts) {
> +		*selected_bus_fmt = 0;
> +		return 0;
> +	} else if (b->num_supported_fmts > 1 && b->supported_fmts) {
> +		*selected_bus_fmt = b->supported_fmts[0];
> +		return 0;

Here, `!a->num_supported_fmts &&` is missing otherwise this code will
select b->supported_fmts[0] whatever the supported formats of a.

> +	} else if (a->num_supported_fmts > 1 && a->supported_fmts) {
> +		*selected_bus_fmt = a->supported_fmts[0];
> +		return 0;

Here, `!b->num_supported_fmts &&` is missing otherwise this code will
select a->supported_fmts[0] whatever the supported formats of b.

> +	} else if (!a->num_supported_fmts || !a->supported_fmts ||
> +		   !b->num_supported_fmts || !b->supported_fmts) {
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * TODO:
> +	 * Dummy algo picking the first match. We probably want something
> +	 * smarter where the narrowest format (in term of bus width) that
> +	 * does not incur data loss is picked, and if all possible formats
> +	 * are lossy, pick the one that's less lossy among all the choices
> +	 * we have. In order to do that we'd need to convert MEDIA_BUS_FMT_
> +	 * modes into something like drm_format_info.
> +	 */
> +	for (i = 0; i < a->num_supported_fmts; i++) {
> +		for (j = 0; j < b->num_supported_fmts; j++) {
> +			if (a->supported_fmts[i] == b->supported_fmts[j]) {
> +				*selected_bus_fmt = a->supported_fmts[i];
> +				return 0;
> +			}
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL(drm_find_best_bus_format);

[...]

With that fixed, this works with basic negociation of the single MEDIA_BUS_FMT_YUV8_1X24
exposed by the meson hdmi encoder, otherwise it takes the first default MEDIA_BUS_FMT_RGB888_1X24
format exposed by dw-hdmi.

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

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

* Re: [PATCH RFC 07/19] drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder
  2019-08-08 15:11 ` [PATCH RFC 07/19] drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder Boris Brezillon
@ 2019-08-19 17:19   ` Sam Ravnborg
  2019-08-21 14:46     ` Laurent Pinchart
  0 siblings, 1 reply; 58+ messages in thread
From: Sam Ravnborg @ 2019-08-19 17:19 UTC (permalink / raw)
  To: Boris Brezillon, Sean Paul
  Cc: Jernej Skrabec, Jonas Karlman, Neil Armstrong, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Laurent Pinchart,
	kernel, Chris Healy

On Thu, Aug 08, 2019 at 05:11:38PM +0200, Boris Brezillon wrote:
> This is part of our attempt to make the bridge chain a double-linked
> list based on the generic list helpers. In order to do that, we must
> patch all drivers manipulating the encoder->bridge field directly.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>

Sean, this patch looks like a nice cleanup we can apply
outside the series.
It would be good that drivers do not poke direct in
the encoder data that this patch fixes.

	Sam

> ---
>  drivers/gpu/drm/msm/edp/edp.c   | 4 +++-
>  drivers/gpu/drm/msm/hdmi/hdmi.c | 4 +++-
>  2 files changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c
> index 0f312ac5b624..ad4e963ccd9b 100644
> --- a/drivers/gpu/drm/msm/edp/edp.c
> +++ b/drivers/gpu/drm/msm/edp/edp.c
> @@ -178,7 +178,9 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
>  		goto fail;
>  	}
>  
> -	encoder->bridge = edp->bridge;
> +	ret = drm_bridge_attach(encoder, edp->bridge, NULL);
> +	if (ret)
> +		goto fail;
>  
>  	priv->bridges[priv->num_bridges++]       = edp->bridge;
>  	priv->connectors[priv->num_connectors++] = edp->connector;
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> index 0e4217be3f00..55b9a8c8312b 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> @@ -327,7 +327,9 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
>  		goto fail;
>  	}
>  
> -	encoder->bridge = hdmi->bridge;
> +	ret = drm_bridge_attach(encoder, hdmi->bridge, NULL);
> +	if (ret)
> +		goto fail;
>  
>  	priv->bridges[priv->num_bridges++]       = hdmi->bridge;
>  	priv->connectors[priv->num_connectors++] = hdmi->connector;
> -- 
> 2.21.0
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h
  2019-08-08 15:11 ` [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h Boris Brezillon
  2019-08-08 18:05   ` Sam Ravnborg
@ 2019-08-20 18:53   ` Laurent Pinchart
  2019-08-21 15:44     ` Boris Brezillon
  1 sibling, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-20 18:53 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:32PM +0200, Boris Brezillon wrote:
> We are about to add a drm_bridge_state that inherits from
> drm_private_state which is defined in drm_atomic.h. Problem is,
> drm_atomic.h includes drm_crtc.h which in turn includes drm_bridge.h,
> leading to "drm_private_state has incomplete type" error.
> 
> Let's force all users of the drm_bridge API to explicitly include
> drm_bridge.h.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/arc/arcpgu_hdmi.c                        | 1 +
>  drivers/gpu/drm/bridge/analogix-anx78xx.c                | 1 +
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c       | 1 +
>  drivers/gpu/drm/bridge/dumb-vga-dac.c                    | 1 +
>  drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 1 +
>  drivers/gpu/drm/bridge/nxp-ptn3460.c                     | 1 +
>  drivers/gpu/drm/bridge/panel.c                           | 1 +
>  drivers/gpu/drm/bridge/parade-ps8622.c                   | 1 +
>  drivers/gpu/drm/bridge/sii902x.c                         | 1 +
>  drivers/gpu/drm/bridge/sii9234.c                         | 1 +
>  drivers/gpu/drm/bridge/sil-sii8620.c                     | 1 +
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c                | 1 +
>  drivers/gpu/drm/bridge/tc358764.c                        | 1 +
>  drivers/gpu/drm/bridge/tc358767.c                        | 1 +
>  drivers/gpu/drm/bridge/ti-sn65dsi86.c                    | 1 +
>  drivers/gpu/drm/bridge/ti-tfp410.c                       | 1 +
>  drivers/gpu/drm/drm_atomic_helper.c                      | 1 +
>  drivers/gpu/drm/drm_crtc_helper.c                        | 1 +
>  drivers/gpu/drm/drm_encoder.c                            | 1 +
>  drivers/gpu/drm/drm_probe_helper.c                       | 1 +
>  drivers/gpu/drm/drm_simple_kms_helper.c                  | 1 +
>  drivers/gpu/drm/exynos/exynos_dp.c                       | 1 +
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c                  | 1 +
>  drivers/gpu/drm/exynos/exynos_drm_mic.c                  | 1 +
>  drivers/gpu/drm/exynos/exynos_hdmi.c                     | 1 +
>  drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c                | 1 +
>  drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c             | 1 +
>  drivers/gpu/drm/i2c/tda998x_drv.c                        | 1 +
>  drivers/gpu/drm/imx/imx-ldb.c                            | 1 +
>  drivers/gpu/drm/imx/parallel-display.c                   | 1 +
>  drivers/gpu/drm/ingenic/ingenic-drm.c                    | 1 +
>  drivers/gpu/drm/mediatek/mtk_dpi.c                       | 1 +
>  drivers/gpu/drm/mediatek/mtk_dsi.c                       | 1 +
>  drivers/gpu/drm/mediatek/mtk_hdmi.c                      | 1 +
>  drivers/gpu/drm/msm/dsi/dsi.h                            | 1 +
>  drivers/gpu/drm/msm/edp/edp.h                            | 1 +
>  drivers/gpu/drm/msm/hdmi/hdmi.h                          | 2 ++
>  drivers/gpu/drm/omapdrm/dss/output.c                     | 1 +
>  drivers/gpu/drm/omapdrm/omap_drv.c                       | 1 +
>  drivers/gpu/drm/omapdrm/omap_encoder.c                   | 1 +
>  drivers/gpu/drm/rcar-du/rcar_du_encoder.c                | 1 +
>  drivers/gpu/drm/rockchip/rockchip_lvds.c                 | 1 +
>  drivers/gpu/drm/rockchip/rockchip_rgb.c                  | 1 +
>  drivers/gpu/drm/sti/sti_dvo.c                            | 1 +
>  drivers/gpu/drm/sti/sti_hda.c                            | 1 +
>  drivers/gpu/drm/sti/sti_hdmi.c                           | 1 +
>  drivers/gpu/drm/sun4i/sun4i_lvds.c                       | 1 +
>  drivers/gpu/drm/sun4i/sun4i_rgb.c                        | 1 +
>  drivers/gpu/drm/sun4i/sun4i_tcon.c                       | 1 +
>  drivers/gpu/drm/tilcdc/tilcdc_external.c                 | 1 +
>  drivers/gpu/drm/vc4/vc4_dsi.c                            | 1 +
>  include/drm/drm_crtc.h                                   | 1 -
>  52 files changed, 52 insertions(+), 1 deletion(-)

Overall this looks good to me. Before I ack the patch, how have you
tested this ? Have you compiled all the DRM/KMS drivers ?

If you wanted to go one step further you could also remove the forward
declaration of struct drm_bridge from drm_ctrc.h, as it's not needed
there.

> diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c
> index 98aac743cc26..8fd7094beece 100644
> --- a/drivers/gpu/drm/arc/arcpgu_hdmi.c
> +++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c
> @@ -5,6 +5,7 @@
>   * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
>   */
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_encoder.h>
>  #include <drm/drm_device.h>
> diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c
> index 3c7cc5af735c..e3f4fd2a5ad4 100644
> --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c
> +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c
> @@ -19,6 +19,7 @@
>  #include <linux/types.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_dp_helper.h>
>  #include <drm/drm_edid.h>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index f2f7f69d6cc3..b096a7a75c14 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -21,6 +21,7 @@
>  #include <drm/bridge/analogix_dp.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
> index 8ef6539ae78a..a974077913bf 100644
> --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
> +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
> @@ -12,6 +12,7 @@
>  #include <linux/regulator/consumer.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
> index 6e81e5db57f2..e8a49f6146c6 100644
> --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
> +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
> @@ -25,6 +25,7 @@
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
> index d4a1cc5052c3..57ff01339559 100644
> --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
> +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
> @@ -11,6 +11,7 @@
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_of.h>
> diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
> index b12ae3a4c5f1..6cffeb4a42f2 100644
> --- a/drivers/gpu/drm/bridge/panel.c
> +++ b/drivers/gpu/drm/bridge/panel.c
> @@ -5,6 +5,7 @@
>   */
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_connector.h>
>  #include <drm/drm_encoder.h>
>  #include <drm/drm_modeset_helper_vtables.h>
> diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
> index 93c68e2e9484..b7a72dfdcac3 100644
> --- a/drivers/gpu/drm/bridge/parade-ps8622.c
> +++ b/drivers/gpu/drm/bridge/parade-ps8622.c
> @@ -17,6 +17,7 @@
>  #include <linux/regulator/consumer.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
> index 38f75ac580df..b70e8c5cf2e1 100644
> --- a/drivers/gpu/drm/bridge/sii902x.c
> +++ b/drivers/gpu/drm/bridge/sii902x.c
> @@ -20,6 +20,7 @@
>  #include <linux/clk.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_drv.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_print.h>
> diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c
> index 25d4ad8c7ad6..ad00d841ed9e 100644
> --- a/drivers/gpu/drm/bridge/sii9234.c
> +++ b/drivers/gpu/drm/bridge/sii9234.c
> @@ -13,6 +13,7 @@
>   *    Dharam Kumar <dharam.kr@samsung.com>
>   */
>  #include <drm/bridge/mhl.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_edid.h>
>  
> diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
> index bd3165ee5354..14643923a721 100644
> --- a/drivers/gpu/drm/bridge/sil-sii8620.c
> +++ b/drivers/gpu/drm/bridge/sil-sii8620.c
> @@ -9,6 +9,7 @@
>  #include <asm/unaligned.h>
>  
>  #include <drm/bridge/mhl.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_encoder.h>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 83b94b66e464..b4901b174a90 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -26,6 +26,7 @@
>  
>  #include <drm/bridge/dw_hdmi.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_encoder_slave.h>
>  #include <drm/drm_of.h>
> diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
> index 170f162ffa55..db298f550a5a 100644
> --- a/drivers/gpu/drm/bridge/tc358764.c
> +++ b/drivers/gpu/drm/bridge/tc358764.c
> @@ -16,6 +16,7 @@
>  #include <video/mipi_display.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_mipi_dsi.h>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index 42f03a985ac0..02c172151165 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -26,6 +26,7 @@
>  #include <linux/slab.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_dp_helper.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_of.h>
> diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> index 0a580957c8cf..43abf01ebd4c 100644
> --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> @@ -17,6 +17,7 @@
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_dp_helper.h>
>  #include <drm/drm_mipi_dsi.h>
>  #include <drm/drm_of.h>
> diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
> index 61cc2354ef1b..aa3198dc9903 100644
> --- a/drivers/gpu/drm/bridge/ti-tfp410.c
> +++ b/drivers/gpu/drm/bridge/ti-tfp410.c
> @@ -14,6 +14,7 @@
>  #include <linux/platform_device.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index aa16ea17ff9b..4706439fb490 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -30,6 +30,7 @@
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_damage_helper.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_plane_helper.h>
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 6dd49a60deac..fa3694836c22 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -36,6 +36,7 @@
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_drv.h>
> diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
> index 7fb47b7b8b44..80d88a55302e 100644
> --- a/drivers/gpu/drm/drm_encoder.c
> +++ b/drivers/gpu/drm/drm_encoder.c
> @@ -22,6 +22,7 @@
>  
>  #include <linux/export.h>
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_drv.h>
>  #include <drm/drm_encoder.h>
> diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
> index ef2c468205a2..351cbc40f0f8 100644
> --- a/drivers/gpu/drm/drm_probe_helper.c
> +++ b/drivers/gpu/drm/drm_probe_helper.c
> @@ -32,6 +32,7 @@
>  #include <linux/export.h>
>  #include <linux/moduleparam.h>
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_client.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_edid.h>
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> index b11910f14c46..046055719245 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -8,6 +8,7 @@
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_probe_helper.h>
>  #include <drm/drm_simple_kms_helper.h>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 3a0f0ba8c63a..1e6aa24bf45e 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -19,6 +19,7 @@
>  
>  #include <drm/bridge/analogix_dp.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index 6926cee91b36..72726f2c7a9f 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -24,6 +24,7 @@
>  #include <video/videomode.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_mipi_dsi.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
> index b78e8c5ba553..f41d75923557 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
> @@ -21,6 +21,7 @@
>  #include <video/of_videomode.h>
>  #include <video/videomode.h>
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_encoder.h>
>  #include <drm/drm_print.h>
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index bc1565f1822a..2e3795c2c794 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -34,6 +34,7 @@
>  #include <media/cec-notifier.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index 279d83eaffc0..11ff06c81dd8 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -9,6 +9,7 @@
>  #include <linux/of_graph.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_probe_helper.h>
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 5bf8138941de..bdcf9c6ae9e9 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -18,6 +18,7 @@
>  #include <linux/platform_device.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_encoder_slave.h>
>  #include <drm/drm_mipi_dsi.h>
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
> index 61e042918a7f..b578189b908c 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -15,6 +15,7 @@
>  
>  #include <drm/drmP.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_probe_helper.h>
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index db461b6a257f..96e9f031b713 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -20,6 +20,7 @@
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> index 2e51b2fade75..35f20edab9fd 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -13,6 +13,7 @@
>  #include <video/of_display_timing.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.c b/drivers/gpu/drm/ingenic/ingenic-drm.c
> index ce1fae3a78a9..1daa1378fc36 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-drm.c
> +++ b/drivers/gpu/drm/ingenic/ingenic-drm.c
> @@ -13,6 +13,7 @@
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_drv.h>
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index be6d95c5ff25..01fa8b8d763d 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -17,6 +17,7 @@
>  #include <video/videomode.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_of.h>
>  
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 224afb666881..a413f5ff442d 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -16,6 +16,7 @@
>  #include <video/videomode.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_mipi_dsi.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index ce91b61364eb..c79b1f855d89 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -23,6 +23,7 @@
>  #include <sound/hdmi-codec.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_print.h>
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> index 0da8a4e428ad..eff1a4c61258 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> @@ -9,6 +9,7 @@
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_mipi_dsi.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/msm/edp/edp.h b/drivers/gpu/drm/msm/edp/edp.h
> index f2c17858a703..eb34243dad53 100644
> --- a/drivers/gpu/drm/msm/edp/edp.h
> +++ b/drivers/gpu/drm/msm/edp/edp.h
> @@ -10,6 +10,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/platform_device.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_dp_helper.h>
>  
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
> index 982865866a29..c681a9e22484 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi.h
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
> @@ -7,6 +7,8 @@
>  #ifndef __HDMI_CONNECTOR_H__
>  #define __HDMI_CONNECTOR_H__
>  
> +#include <drm/drm_bridge.h>
> +
>  #include <linux/i2c.h>
>  #include <linux/clk.h>
>  #include <linux/platform_device.h>
> diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
> index de0f882f0f7b..de500bb05bdc 100644
> --- a/drivers/gpu/drm/omapdrm/dss/output.c
> +++ b/drivers/gpu/drm/omapdrm/dss/output.c
> @@ -11,6 +11,7 @@
>  #include <linux/of.h>
>  #include <linux/of_graph.h>
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_panel.h>
>  
>  #include "dss.h"
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> index 9f652d2e7af1..224ec6fdc800 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> @@ -11,6 +11,7 @@
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_drv.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_file.h>
> diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
> index 6fe14111cd95..24bbe9f2a32e 100644
> --- a/drivers/gpu/drm/omapdrm/omap_encoder.c
> +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
> @@ -6,6 +6,7 @@
>  
>  #include <linux/list.h>
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_modeset_helper_vtables.h>
>  #include <drm/drm_edid.h>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> index 0f00bdfe2366..3a1139b725c0 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> @@ -9,6 +9,7 @@
>  
>  #include <linux/export.h>
>  
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_modeset_helper_vtables.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
> index 64aefa856896..8a4c9af0ba73 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
> @@ -16,6 +16,7 @@
>  #include <linux/regmap.h>
>  #include <linux/reset.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  
>  #include <drm/drm_dp_helper.h>
>  #include <drm/drm_of.h>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
> index 89e0bb0fe0ab..db1be1f3925c 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
> @@ -9,6 +9,7 @@
>  #include <linux/of_graph.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_dp_helper.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e55870190bf5..0a4f00253f39 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -12,6 +12,7 @@
>  #include <linux/platform_device.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index 94e404f13234..9d3fd6370a29 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -12,6 +12,7 @@
>  #include <linux/seq_file.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_file.h>
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 9862c322f0c4..84318d0832a0 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -14,6 +14,7 @@
>  #include <linux/reset.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_drv.h>
>  #include <drm/drm_edid.h>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c
> index 7fbf425acb55..25ab2ef6d545 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c
> @@ -7,6 +7,7 @@
>  #include <linux/clk.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index aac56983f208..e74b9eddca01 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -9,6 +9,7 @@
>  #include <linux/clk.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 690aeb822704..eb187da56aba 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -16,6 +16,7 @@
>  #include <linux/reset.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_connector.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_encoder.h>
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
> index 43d756b7810e..4fc10838de80 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
> @@ -8,6 +8,7 @@
>  #include <linux/of_graph.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_of.h>
>  
>  #include "tilcdc_drv.h"
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index c78fa8144776..3f63943e5472 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -31,6 +31,7 @@
>  #include <linux/pm_runtime.h>
>  
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_mipi_dsi.h>
>  #include <drm/drm_of.h>
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 7d14c11bdc0a..7e2963cad543 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -41,7 +41,6 @@
>  #include <drm/drm_connector.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_property.h>
> -#include <drm/drm_bridge.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_plane.h>
>  #include <drm/drm_blend.h>

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially
  2019-08-08 15:11 ` [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially Boris Brezillon
@ 2019-08-20 19:05   ` Laurent Pinchart
  2019-08-21  8:21     ` Daniel Vetter
  2019-08-21 15:30     ` Boris Brezillon
  0 siblings, 2 replies; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-20 19:05 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:33PM +0200, Boris Brezillon wrote:
> The VC4 and Exynos DSI encoder drivers need a custom enable/disable
> sequence and manually set encoder->bridge to NULL to prevent the core
> from calling the bridge hooks.
> 
> Let's provide a more official way to support custom bridge/encoder
> enable/disable sequences.

So, while I'm not opposed to this, I think it's a bit of a hack, and I'd
like to share my vision of how I'd like to see this being implemented in
the more distant future (and thus possibly on top of this change).

It has been established for quite some time now that exposing
drm_encoder to userspace was likely a mistake, and that it should have
stayed a kernel-only object. With the generalised usage of drm_bridge, I
would go one step further: drm_encoder shouldn't matter for DRM/KMS
drivers at all.

drm_bridge has been introduced to model chained encoders, where the
second (and subsequent) encoders couldn't easily be supported in a
standard and reusable way with just drm_encoder. A bridge (with the
exception of the panel bridge) is just an encoder. It shouldn't matter
whether encoders are internal to the display controller, separate IPs in
the SoC or external components, they could all be modelled as bridges.
We do have bridges for DSI encoder IPs, and DSI (and other) bridges
potentially need similar custom enable/disable sequences. I would thus
ideally like to see the VC4 and Exynos DSI encoders being implemented as
bridges, with support for custom enable/disable sequences in bridges,
and drop support for custom enable/disable sequences in drm_encoder.

Does this make sense to you ? While I would love to see this being
implemented right away, it may be too much work as a prerequisite for
this bus format negotiation series, so I don't want to reject this
patch. I would however like to already make sure we agree on the way
forward for the next steps.

> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 13 +++++++---
>  drivers/gpu/drm/drm_crtc_helper.c   | 38 ++++++++++++++++++-----------
>  include/drm/drm_encoder.h           |  9 +++++++
>  3 files changed, 42 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 4706439fb490..15ea61877122 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1030,7 +1030,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		 * Each encoder has at most one connector (since we always steal
>  		 * it away), so we won't call disable hooks twice.
>  		 */
> -		drm_atomic_bridge_disable(encoder->bridge, old_state);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_atomic_bridge_disable(encoder->bridge, old_state);
>  
>  		/* Right function depends upon target state. */
>  		if (funcs) {
> @@ -1044,7 +1045,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
>  		}
>  
> -		drm_atomic_bridge_post_disable(encoder->bridge, old_state);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_atomic_bridge_post_disable(encoder->bridge,
> +						       old_state);
>  	}
>  
>  	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
> @@ -1342,7 +1345,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>  		 * Each encoder has at most one connector (since we always steal
>  		 * it away), so we won't call enable hooks twice.
>  		 */
> -		drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
>  
>  		if (funcs) {
>  			if (funcs->atomic_enable)
> @@ -1353,7 +1357,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>  				funcs->commit(encoder);
>  		}
>  
> -		drm_atomic_bridge_enable(encoder->bridge, old_state);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_atomic_bridge_enable(encoder->bridge, old_state);
>  	}
>  
>  	drm_atomic_helper_commit_writebacks(dev, old_state);
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index fa3694836c22..87dae37fec12 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -160,14 +160,16 @@ drm_encoder_disable(struct drm_encoder *encoder)
>  	if (!encoder_funcs)
>  		return;
>  
> -	drm_bridge_disable(encoder->bridge);
> +	if (!encoder->custom_bridge_enable_disable_seq)
> +		drm_bridge_disable(encoder->bridge);
>  
>  	if (encoder_funcs->disable)
>  		(*encoder_funcs->disable)(encoder);
>  	else if (encoder_funcs->dpms)
>  		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
>  
> -	drm_bridge_post_disable(encoder->bridge);
> +	if (!encoder->custom_bridge_enable_disable_seq)
> +		drm_bridge_post_disable(encoder->bridge);
>  }
>  
>  static void __drm_helper_disable_unused_functions(struct drm_device *dev)
> @@ -365,13 +367,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>  		if (!encoder_funcs)
>  			continue;
>  
> -		drm_bridge_disable(encoder->bridge);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_bridge_disable(encoder->bridge);
>  
>  		/* Disable the encoders as the first thing we do. */
>  		if (encoder_funcs->prepare)
>  			encoder_funcs->prepare(encoder);
>  
> -		drm_bridge_post_disable(encoder->bridge);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_bridge_post_disable(encoder->bridge);
>  	}
>  
>  	drm_crtc_prepare_encoders(dev);
> @@ -414,12 +418,14 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>  		if (!encoder_funcs)
>  			continue;
>  
> -		drm_bridge_pre_enable(encoder->bridge);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_bridge_pre_enable(encoder->bridge);
>  
>  		if (encoder_funcs->commit)
>  			encoder_funcs->commit(encoder);
>  
> -		drm_bridge_enable(encoder->bridge);
> +		if (!encoder->custom_bridge_enable_disable_seq)
> +			drm_bridge_enable(encoder->bridge);
>  	}
>  
>  	/* Calculate and store various constants which
> @@ -825,18 +831,22 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
>  	if (!encoder_funcs)
>  		return;
>  
> -	if (mode == DRM_MODE_DPMS_ON)
> -		drm_bridge_pre_enable(bridge);
> -	else
> -		drm_bridge_disable(bridge);
> +	if (!encoder->custom_bridge_enable_disable_seq) {
> +		if (mode == DRM_MODE_DPMS_ON)
> +			drm_bridge_pre_enable(bridge);
> +		else
> +			drm_bridge_disable(bridge);
> +	}
>  
>  	if (encoder_funcs->dpms)
>  		encoder_funcs->dpms(encoder, mode);
>  
> -	if (mode == DRM_MODE_DPMS_ON)
> -		drm_bridge_enable(bridge);
> -	else
> -		drm_bridge_post_disable(bridge);
> +	if (!encoder->custom_bridge_enable_disable_seq) {
> +		if (mode == DRM_MODE_DPMS_ON)
> +			drm_bridge_enable(bridge);
> +		else
> +			drm_bridge_post_disable(bridge);
> +	}
>  }
>  
>  static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
> diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
> index 70cfca03d812..d986ff1197ce 100644
> --- a/include/drm/drm_encoder.h
> +++ b/include/drm/drm_encoder.h
> @@ -175,6 +175,15 @@ struct drm_encoder {
>  	struct drm_bridge *bridge;
>  	const struct drm_encoder_funcs *funcs;
>  	const struct drm_encoder_helper_funcs *helper_private;
> +
> +	/**
> +	 * @custom_bridge_enable_disable_seq: Set to true if the encoder needs
> +	 * a custom bridge/encoder enable/disable sequence. In that case the
> +	 * driver is responsible for calling the
> +	 * drm[_atomic]_bridge_{pre_enable,enable,disable,post_disable}()
> +	 * functions as part of its encoder enable/disable handling.
> +	 */
> +	uint32_t custom_bridge_enable_disable_seq : 1;
>  };
>  
>  #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially
  2019-08-20 19:05   ` Laurent Pinchart
@ 2019-08-21  8:21     ` Daniel Vetter
  2019-08-21 13:57       ` Laurent Pinchart
  2019-08-21 15:39       ` Boris Brezillon
  2019-08-21 15:30     ` Boris Brezillon
  1 sibling, 2 replies; 58+ messages in thread
From: Daniel Vetter @ 2019-08-21  8:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Boris Brezillon, Thierry Reding,
	Chris Healy, kernel, Sam Ravnborg

On Tue, Aug 20, 2019 at 10:05:05PM +0300, Laurent Pinchart wrote:
> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:33PM +0200, Boris Brezillon wrote:
> > The VC4 and Exynos DSI encoder drivers need a custom enable/disable
> > sequence and manually set encoder->bridge to NULL to prevent the core
> > from calling the bridge hooks.
> > 
> > Let's provide a more official way to support custom bridge/encoder
> > enable/disable sequences.
> 
> So, while I'm not opposed to this, I think it's a bit of a hack, and I'd
> like to share my vision of how I'd like to see this being implemented in
> the more distant future (and thus possibly on top of this change).

I think it's also counter to how the atomic helpers are meant to be used.
I mean you're adding a pile new hooks here all for essentially not having
to type a few lines of helper code. If you look around at big drivers
(i915, amdgpu, nouveau) _none_ of them use the modesets_enables/disables
helpers. Exactly for reasons like this where you need a custom sequence.

So proper recommendation is to just type your own, you'll be happier.

> It has been established for quite some time now that exposing
> drm_encoder to userspace was likely a mistake, and that it should have
> stayed a kernel-only object. With the generalised usage of drm_bridge, I
> would go one step further: drm_encoder shouldn't matter for DRM/KMS
> drivers at all.
> 
> drm_bridge has been introduced to model chained encoders, where the
> second (and subsequent) encoders couldn't easily be supported in a
> standard and reusable way with just drm_encoder. A bridge (with the
> exception of the panel bridge) is just an encoder. It shouldn't matter
> whether encoders are internal to the display controller, separate IPs in
> the SoC or external components, they could all be modelled as bridges.
> We do have bridges for DSI encoder IPs, and DSI (and other) bridges
> potentially need similar custom enable/disable sequences. I would thus
> ideally like to see the VC4 and Exynos DSI encoders being implemented as
> bridges, with support for custom enable/disable sequences in bridges,
> and drop support for custom enable/disable sequences in drm_encoder.
> 
> Does this make sense to you ? While I would love to see this being
> implemented right away, it may be too much work as a prerequisite for
> this bus format negotiation series, so I don't want to reject this
> patch. I would however like to already make sure we agree on the way
> forward for the next steps.

Yeah the other bit is that bridges are supposed to be some kind of
standard. I do wonder (I haven't looked at the series) whether the problem
here is that encoders don't have their own full set of pre/post enable
hooks like bridges (essentially that's what you're adding here), or
whether the idea behind pre/post enable/disable hooks is not good enough.

Anyway, this here is imo not the right thing to do. If setting
encoder->bridge to NULL doesn't work for you then just type your own
enable/disable implementations. There's explicitly no requirement to use
all parts of atomic helpers, au contraire, it's explicitly discouraged.

Cheers, Daniel

> 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > ---
> >  drivers/gpu/drm/drm_atomic_helper.c | 13 +++++++---
> >  drivers/gpu/drm/drm_crtc_helper.c   | 38 ++++++++++++++++++-----------
> >  include/drm/drm_encoder.h           |  9 +++++++
> >  3 files changed, 42 insertions(+), 18 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 4706439fb490..15ea61877122 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -1030,7 +1030,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> >  		 * Each encoder has at most one connector (since we always steal
> >  		 * it away), so we won't call disable hooks twice.
> >  		 */
> > -		drm_atomic_bridge_disable(encoder->bridge, old_state);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_atomic_bridge_disable(encoder->bridge, old_state);
> >  
> >  		/* Right function depends upon target state. */
> >  		if (funcs) {
> > @@ -1044,7 +1045,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> >  				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
> >  		}
> >  
> > -		drm_atomic_bridge_post_disable(encoder->bridge, old_state);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_atomic_bridge_post_disable(encoder->bridge,
> > +						       old_state);
> >  	}
> >  
> >  	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
> > @@ -1342,7 +1345,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
> >  		 * Each encoder has at most one connector (since we always steal
> >  		 * it away), so we won't call enable hooks twice.
> >  		 */
> > -		drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
> >  
> >  		if (funcs) {
> >  			if (funcs->atomic_enable)
> > @@ -1353,7 +1357,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
> >  				funcs->commit(encoder);
> >  		}
> >  
> > -		drm_atomic_bridge_enable(encoder->bridge, old_state);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_atomic_bridge_enable(encoder->bridge, old_state);
> >  	}
> >  
> >  	drm_atomic_helper_commit_writebacks(dev, old_state);
> > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> > index fa3694836c22..87dae37fec12 100644
> > --- a/drivers/gpu/drm/drm_crtc_helper.c
> > +++ b/drivers/gpu/drm/drm_crtc_helper.c
> > @@ -160,14 +160,16 @@ drm_encoder_disable(struct drm_encoder *encoder)
> >  	if (!encoder_funcs)
> >  		return;
> >  
> > -	drm_bridge_disable(encoder->bridge);
> > +	if (!encoder->custom_bridge_enable_disable_seq)
> > +		drm_bridge_disable(encoder->bridge);
> >  
> >  	if (encoder_funcs->disable)
> >  		(*encoder_funcs->disable)(encoder);
> >  	else if (encoder_funcs->dpms)
> >  		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
> >  
> > -	drm_bridge_post_disable(encoder->bridge);
> > +	if (!encoder->custom_bridge_enable_disable_seq)
> > +		drm_bridge_post_disable(encoder->bridge);
> >  }
> >  
> >  static void __drm_helper_disable_unused_functions(struct drm_device *dev)
> > @@ -365,13 +367,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
> >  		if (!encoder_funcs)
> >  			continue;
> >  
> > -		drm_bridge_disable(encoder->bridge);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_bridge_disable(encoder->bridge);
> >  
> >  		/* Disable the encoders as the first thing we do. */
> >  		if (encoder_funcs->prepare)
> >  			encoder_funcs->prepare(encoder);
> >  
> > -		drm_bridge_post_disable(encoder->bridge);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_bridge_post_disable(encoder->bridge);
> >  	}
> >  
> >  	drm_crtc_prepare_encoders(dev);
> > @@ -414,12 +418,14 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
> >  		if (!encoder_funcs)
> >  			continue;
> >  
> > -		drm_bridge_pre_enable(encoder->bridge);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_bridge_pre_enable(encoder->bridge);
> >  
> >  		if (encoder_funcs->commit)
> >  			encoder_funcs->commit(encoder);
> >  
> > -		drm_bridge_enable(encoder->bridge);
> > +		if (!encoder->custom_bridge_enable_disable_seq)
> > +			drm_bridge_enable(encoder->bridge);
> >  	}
> >  
> >  	/* Calculate and store various constants which
> > @@ -825,18 +831,22 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
> >  	if (!encoder_funcs)
> >  		return;
> >  
> > -	if (mode == DRM_MODE_DPMS_ON)
> > -		drm_bridge_pre_enable(bridge);
> > -	else
> > -		drm_bridge_disable(bridge);
> > +	if (!encoder->custom_bridge_enable_disable_seq) {
> > +		if (mode == DRM_MODE_DPMS_ON)
> > +			drm_bridge_pre_enable(bridge);
> > +		else
> > +			drm_bridge_disable(bridge);
> > +	}
> >  
> >  	if (encoder_funcs->dpms)
> >  		encoder_funcs->dpms(encoder, mode);
> >  
> > -	if (mode == DRM_MODE_DPMS_ON)
> > -		drm_bridge_enable(bridge);
> > -	else
> > -		drm_bridge_post_disable(bridge);
> > +	if (!encoder->custom_bridge_enable_disable_seq) {
> > +		if (mode == DRM_MODE_DPMS_ON)
> > +			drm_bridge_enable(bridge);
> > +		else
> > +			drm_bridge_post_disable(bridge);
> > +	}
> >  }
> >  
> >  static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
> > diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
> > index 70cfca03d812..d986ff1197ce 100644
> > --- a/include/drm/drm_encoder.h
> > +++ b/include/drm/drm_encoder.h
> > @@ -175,6 +175,15 @@ struct drm_encoder {
> >  	struct drm_bridge *bridge;
> >  	const struct drm_encoder_funcs *funcs;
> >  	const struct drm_encoder_helper_funcs *helper_private;
> > +
> > +	/**
> > +	 * @custom_bridge_enable_disable_seq: Set to true if the encoder needs
> > +	 * a custom bridge/encoder enable/disable sequence. In that case the
> > +	 * driver is responsible for calling the
> > +	 * drm[_atomic]_bridge_{pre_enable,enable,disable,post_disable}()
> > +	 * functions as part of its encoder enable/disable handling.
> > +	 */
> > +	uint32_t custom_bridge_enable_disable_seq : 1;
> >  };
> >  
> >  #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially
  2019-08-21  8:21     ` Daniel Vetter
@ 2019-08-21 13:57       ` Laurent Pinchart
  2019-08-21 15:39       ` Boris Brezillon
  1 sibling, 0 replies; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-21 13:57 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Boris Brezillon, Thierry Reding,
	Chris Healy, kernel, Sam Ravnborg

Hi Daniel,

On Wed, Aug 21, 2019 at 10:21:07AM +0200, Daniel Vetter wrote:
> On Tue, Aug 20, 2019 at 10:05:05PM +0300, Laurent Pinchart wrote:
> > On Thu, Aug 08, 2019 at 05:11:33PM +0200, Boris Brezillon wrote:
> > > The VC4 and Exynos DSI encoder drivers need a custom enable/disable
> > > sequence and manually set encoder->bridge to NULL to prevent the core
> > > from calling the bridge hooks.
> > > 
> > > Let's provide a more official way to support custom bridge/encoder
> > > enable/disable sequences.
> > 
> > So, while I'm not opposed to this, I think it's a bit of a hack, and I'd
> > like to share my vision of how I'd like to see this being implemented in
> > the more distant future (and thus possibly on top of this change).
> 
> I think it's also counter to how the atomic helpers are meant to be used.
> I mean you're adding a pile new hooks here all for essentially not having
> to type a few lines of helper code. If you look around at big drivers
> (i915, amdgpu, nouveau) _none_ of them use the modesets_enables/disables
> helpers. Exactly for reasons like this where you need a custom sequence.
> 
> So proper recommendation is to just type your own, you'll be happier.
> 
> > It has been established for quite some time now that exposing
> > drm_encoder to userspace was likely a mistake, and that it should have
> > stayed a kernel-only object. With the generalised usage of drm_bridge, I
> > would go one step further: drm_encoder shouldn't matter for DRM/KMS
> > drivers at all.
> > 
> > drm_bridge has been introduced to model chained encoders, where the
> > second (and subsequent) encoders couldn't easily be supported in a
> > standard and reusable way with just drm_encoder. A bridge (with the
> > exception of the panel bridge) is just an encoder. It shouldn't matter
> > whether encoders are internal to the display controller, separate IPs in
> > the SoC or external components, they could all be modelled as bridges.
> > We do have bridges for DSI encoder IPs, and DSI (and other) bridges
> > potentially need similar custom enable/disable sequences. I would thus
> > ideally like to see the VC4 and Exynos DSI encoders being implemented as
> > bridges, with support for custom enable/disable sequences in bridges,
> > and drop support for custom enable/disable sequences in drm_encoder.
> > 
> > Does this make sense to you ? While I would love to see this being
> > implemented right away, it may be too much work as a prerequisite for
> > this bus format negotiation series, so I don't want to reject this
> > patch. I would however like to already make sure we agree on the way
> > forward for the next steps.
> 
> Yeah the other bit is that bridges are supposed to be some kind of
> standard. I do wonder (I haven't looked at the series) whether the problem
> here is that encoders don't have their own full set of pre/post enable
> hooks like bridges (essentially that's what you're adding here), or
> whether the idea behind pre/post enable/disable hooks is not good enough.

It's a mostly-good idea :-) DSI is a bit more troublesome as it often
requires enable/disable sequences that are a bit more entangled between
the source and the sink. That's why the omapdrm driver originally
controlled enabling from sink to source, it would locate the bridge (or
the omapdrm internal equivalent of bridge to be more accurate) at the
end of the chain, and enable it. The bridge would then be responsible
for forwarding the enable call to its source, broken in several
fine-grained calls for DSI. That allowed a DSI sink to implement
completely custom enable/disable sequences, and enable the source
accordingly (usually by first enabling clocks, then enabling data
transmission but without actual display data, and finally enabling
transfer of display data). The cost was a more complex enable/disable
implementation for each bridge.

I think the pre/post enable/disable operations we have now are mostly
good, but for some links they need to be manually controlled. Of course
I can't rule out a new display bus in the future that will shatter this
down to pieces by requiring more complex enable/disable sequences.

> Anyway, this here is imo not the right thing to do. If setting
> encoder->bridge to NULL doesn't work for you then just type your own
> enable/disable implementations. There's explicitly no requirement to use
> all parts of atomic helpers, au contraire, it's explicitly discouraged.
> 
> > > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > > ---
> > >  drivers/gpu/drm/drm_atomic_helper.c | 13 +++++++---
> > >  drivers/gpu/drm/drm_crtc_helper.c   | 38 ++++++++++++++++++-----------
> > >  include/drm/drm_encoder.h           |  9 +++++++
> > >  3 files changed, 42 insertions(+), 18 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > index 4706439fb490..15ea61877122 100644
> > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > @@ -1030,7 +1030,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> > >  		 * Each encoder has at most one connector (since we always steal
> > >  		 * it away), so we won't call disable hooks twice.
> > >  		 */
> > > -		drm_atomic_bridge_disable(encoder->bridge, old_state);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_atomic_bridge_disable(encoder->bridge, old_state);
> > >  
> > >  		/* Right function depends upon target state. */
> > >  		if (funcs) {
> > > @@ -1044,7 +1045,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
> > >  				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
> > >  		}
> > >  
> > > -		drm_atomic_bridge_post_disable(encoder->bridge, old_state);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_atomic_bridge_post_disable(encoder->bridge,
> > > +						       old_state);
> > >  	}
> > >  
> > >  	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
> > > @@ -1342,7 +1345,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
> > >  		 * Each encoder has at most one connector (since we always steal
> > >  		 * it away), so we won't call enable hooks twice.
> > >  		 */
> > > -		drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
> > >  
> > >  		if (funcs) {
> > >  			if (funcs->atomic_enable)
> > > @@ -1353,7 +1357,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
> > >  				funcs->commit(encoder);
> > >  		}
> > >  
> > > -		drm_atomic_bridge_enable(encoder->bridge, old_state);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_atomic_bridge_enable(encoder->bridge, old_state);
> > >  	}
> > >  
> > >  	drm_atomic_helper_commit_writebacks(dev, old_state);
> > > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> > > index fa3694836c22..87dae37fec12 100644
> > > --- a/drivers/gpu/drm/drm_crtc_helper.c
> > > +++ b/drivers/gpu/drm/drm_crtc_helper.c
> > > @@ -160,14 +160,16 @@ drm_encoder_disable(struct drm_encoder *encoder)
> > >  	if (!encoder_funcs)
> > >  		return;
> > >  
> > > -	drm_bridge_disable(encoder->bridge);
> > > +	if (!encoder->custom_bridge_enable_disable_seq)
> > > +		drm_bridge_disable(encoder->bridge);
> > >  
> > >  	if (encoder_funcs->disable)
> > >  		(*encoder_funcs->disable)(encoder);
> > >  	else if (encoder_funcs->dpms)
> > >  		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
> > >  
> > > -	drm_bridge_post_disable(encoder->bridge);
> > > +	if (!encoder->custom_bridge_enable_disable_seq)
> > > +		drm_bridge_post_disable(encoder->bridge);
> > >  }
> > >  
> > >  static void __drm_helper_disable_unused_functions(struct drm_device *dev)
> > > @@ -365,13 +367,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
> > >  		if (!encoder_funcs)
> > >  			continue;
> > >  
> > > -		drm_bridge_disable(encoder->bridge);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_bridge_disable(encoder->bridge);
> > >  
> > >  		/* Disable the encoders as the first thing we do. */
> > >  		if (encoder_funcs->prepare)
> > >  			encoder_funcs->prepare(encoder);
> > >  
> > > -		drm_bridge_post_disable(encoder->bridge);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_bridge_post_disable(encoder->bridge);
> > >  	}
> > >  
> > >  	drm_crtc_prepare_encoders(dev);
> > > @@ -414,12 +418,14 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
> > >  		if (!encoder_funcs)
> > >  			continue;
> > >  
> > > -		drm_bridge_pre_enable(encoder->bridge);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_bridge_pre_enable(encoder->bridge);
> > >  
> > >  		if (encoder_funcs->commit)
> > >  			encoder_funcs->commit(encoder);
> > >  
> > > -		drm_bridge_enable(encoder->bridge);
> > > +		if (!encoder->custom_bridge_enable_disable_seq)
> > > +			drm_bridge_enable(encoder->bridge);
> > >  	}
> > >  
> > >  	/* Calculate and store various constants which
> > > @@ -825,18 +831,22 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
> > >  	if (!encoder_funcs)
> > >  		return;
> > >  
> > > -	if (mode == DRM_MODE_DPMS_ON)
> > > -		drm_bridge_pre_enable(bridge);
> > > -	else
> > > -		drm_bridge_disable(bridge);
> > > +	if (!encoder->custom_bridge_enable_disable_seq) {
> > > +		if (mode == DRM_MODE_DPMS_ON)
> > > +			drm_bridge_pre_enable(bridge);
> > > +		else
> > > +			drm_bridge_disable(bridge);
> > > +	}
> > >  
> > >  	if (encoder_funcs->dpms)
> > >  		encoder_funcs->dpms(encoder, mode);
> > >  
> > > -	if (mode == DRM_MODE_DPMS_ON)
> > > -		drm_bridge_enable(bridge);
> > > -	else
> > > -		drm_bridge_post_disable(bridge);
> > > +	if (!encoder->custom_bridge_enable_disable_seq) {
> > > +		if (mode == DRM_MODE_DPMS_ON)
> > > +			drm_bridge_enable(bridge);
> > > +		else
> > > +			drm_bridge_post_disable(bridge);
> > > +	}
> > >  }
> > >  
> > >  static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
> > > diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
> > > index 70cfca03d812..d986ff1197ce 100644
> > > --- a/include/drm/drm_encoder.h
> > > +++ b/include/drm/drm_encoder.h
> > > @@ -175,6 +175,15 @@ struct drm_encoder {
> > >  	struct drm_bridge *bridge;
> > >  	const struct drm_encoder_funcs *funcs;
> > >  	const struct drm_encoder_helper_funcs *helper_private;
> > > +
> > > +	/**
> > > +	 * @custom_bridge_enable_disable_seq: Set to true if the encoder needs
> > > +	 * a custom bridge/encoder enable/disable sequence. In that case the
> > > +	 * driver is responsible for calling the
> > > +	 * drm[_atomic]_bridge_{pre_enable,enable,disable,post_disable}()
> > > +	 * functions as part of its encoder enable/disable handling.
> > > +	 */
> > > +	uint32_t custom_bridge_enable_disable_seq : 1;
> > >  };
> > >  
> > >  #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next
  2019-08-08 15:11 ` [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next Boris Brezillon
  2019-08-08 21:04   ` Boris Brezillon
@ 2019-08-21 14:01   ` Laurent Pinchart
  1 sibling, 0 replies; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-21 14:01 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

On Thu, Aug 08, 2019 at 05:11:36PM +0200, Boris Brezillon wrote:
> bridge->next is only points to the new bridge if drm_bridge_attach()
> succeeds. No need to reset it manually here.
> 
> Note that this change is part of the attempt to make the bridge chain
> a double-linked list. In order to do that we must patch all drivers
> manipulating the bridge->next field.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>

This looks good to me as a cleanup, and I think you can already push it
without waiting for the whole series to be ready.

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

> ---
>  drivers/gpu/drm/exynos/exynos_dp.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 1e6aa24bf45e..4785885c0f4f 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -110,7 +110,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>  		if (ret) {
>  			DRM_DEV_ERROR(dp->dev,
>  				      "Failed to attach bridge to drm\n");
> -			bridge->next = NULL;
>  			return ret;
>  		}
>  	}

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 06/19] drm/bridge: Create drm_bridge_chain_xx() wrappers
  2019-08-08 15:11 ` [PATCH RFC 06/19] drm/bridge: Create drm_bridge_chain_xx() wrappers Boris Brezillon
@ 2019-08-21 14:45   ` Laurent Pinchart
  2019-08-21 15:53     ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-21 14:45 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:37PM +0200, Boris Brezillon wrote:
> DRM bridges should not be operated independently. Let's rename the
> drm_bridge_xxx() helpers that take the first bridge of the chain and
> iterate over the whole chain into drm_bridge_chain_xx(). We also pass
> it the encoder containing the bridge chain instead of the dereferencing
> encoder->bridge.

I'm not sure about this. I do agree that the helpers operate on a chain,
but I think they're use for calling them on any bridge, especially in
conjunction with your work. The way I see it is that when a bridge in
the chain needs a custom enable/disable sequence (flagged by some kind
of flag in the bridge structure), the helpers will not automatically
propagate the calls down the chain, and let the bridge call the pre/post
enable/disable operations on the downstream bridge. This means that
those bridges with special needs will have to call the helpers on the
next bridge down the chain, and thus require keeping the ability to do
so.

We could of course propose two sets of helpers, one taking a bridge
pointer, and another one taking an encoder pointer, but I think it's a
bit overkill. Especially if you consider my comments earlier in this
series where I propose moving the custom sequence feature to bridges
instead of encoders, I don't think this patch will be needed.

> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c     |  19 +-
>  drivers/gpu/drm/drm_bridge.c            | 365 +++++++++++++-----------
>  drivers/gpu/drm/drm_crtc_helper.c       |  27 +-
>  drivers/gpu/drm/drm_probe_helper.c      |   2 +-
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c |   8 +-
>  drivers/gpu/drm/mediatek/mtk_hdmi.c     |   4 +-
>  drivers/gpu/drm/vc4/vc4_dsi.c           |   8 +-
>  include/drm/drm_bridge.h                |  64 +++--
>  8 files changed, 273 insertions(+), 224 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 15ea61877122..0deb54099570 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -445,8 +445,9 @@ mode_fixup(struct drm_atomic_state *state)
>  		encoder = new_conn_state->best_encoder;
>  		funcs = encoder->helper_private;
>  
> -		ret = drm_bridge_mode_fixup(encoder->bridge, &new_crtc_state->mode,
> -				&new_crtc_state->adjusted_mode);
> +		ret = drm_bridge_chain_mode_fixup(encoder,
> +					&new_crtc_state->mode,
> +					&new_crtc_state->adjusted_mode);
>  		if (!ret) {
>  			DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
>  			return -EINVAL;
> @@ -511,7 +512,7 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector,
>  		return ret;
>  	}
>  
> -	ret = drm_bridge_mode_valid(encoder->bridge, mode);
> +	ret = drm_bridge_chain_mode_valid(encoder, mode);
>  	if (ret != MODE_OK) {
>  		DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n");
>  		return ret;
> @@ -1031,7 +1032,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		 * it away), so we won't call disable hooks twice.
>  		 */
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_atomic_bridge_disable(encoder->bridge, old_state);
> +			drm_atomic_bridge_chain_disable(encoder, old_state);
>  
>  		/* Right function depends upon target state. */
>  		if (funcs) {
> @@ -1046,8 +1047,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		}
>  
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_atomic_bridge_post_disable(encoder->bridge,
> -						       old_state);
> +			drm_atomic_bridge_chain_post_disable(encoder,
> +							     old_state);
>  	}
>  
>  	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
> @@ -1228,7 +1229,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
>  			funcs->mode_set(encoder, mode, adjusted_mode);
>  		}
>  
> -		drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
> +		drm_bridge_chain_mode_set(encoder, mode, adjusted_mode);
>  	}
>  }
>  
> @@ -1346,7 +1347,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>  		 * it away), so we won't call enable hooks twice.
>  		 */
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
> +			drm_atomic_bridge_chain_pre_enable(encoder, old_state);
>  
>  		if (funcs) {
>  			if (funcs->atomic_enable)
> @@ -1358,7 +1359,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>  		}
>  
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_atomic_bridge_enable(encoder->bridge, old_state);
> +			drm_atomic_bridge_chain_enable(encoder, old_state);
>  	}
>  
>  	drm_atomic_helper_commit_writebacks(dev, old_state);
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index cba537c99e43..2bf9a19e11bf 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -171,24 +171,9 @@ void drm_bridge_detach(struct drm_bridge *bridge)
>   * For detailed specification of the bridge callbacks see &drm_bridge_funcs.
>   */
>  
> -/**
> - * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the
> - *			   encoder chain
> - * @bridge: bridge control structure
> - * @mode: desired mode to be set for the bridge
> - * @adjusted_mode: updated mode that works for this bridge
> - *
> - * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the
> - * encoder chain, starting from the first bridge to the last.
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - *
> - * RETURNS:
> - * true on success, false on failure
> - */
> -bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> -			const struct drm_display_mode *mode,
> -			struct drm_display_mode *adjusted_mode)
> +static bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> +				  const struct drm_display_mode *mode,
> +				  struct drm_display_mode *adjusted_mode)
>  {
>  	bool ret = true;
>  
> @@ -202,25 +187,10 @@ bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
>  
>  	return ret;
>  }
> -EXPORT_SYMBOL(drm_bridge_mode_fixup);
>  
> -/**
> - * drm_bridge_mode_valid - validate the mode against all bridges in the
> - * 			   encoder chain.
> - * @bridge: bridge control structure
> - * @mode: desired mode to be validated
> - *
> - * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
> - * chain, starting from the first bridge to the last. If at least one bridge
> - * does not accept the mode the function returns the error code.
> - *
> - * Note: the bridge passed should be the one closest to the encoder.
> - *
> - * RETURNS:
> - * MODE_OK on success, drm_mode_status Enum error code on failure
> - */
> -enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
> -					   const struct drm_display_mode *mode)
> +static enum drm_mode_status
> +drm_bridge_mode_valid(struct drm_bridge *bridge,
> +		      const struct drm_display_mode *mode)
>  {
>  	enum drm_mode_status ret = MODE_OK;
>  
> @@ -235,19 +205,8 @@ enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
>  
>  	return drm_bridge_mode_valid(bridge->next, mode);
>  }
> -EXPORT_SYMBOL(drm_bridge_mode_valid);
>  
> -/**
> - * drm_bridge_disable - disables all bridges in the encoder chain
> - * @bridge: bridge control structure
> - *
> - * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
> - * chain, starting from the last bridge to the first. These are called before
> - * calling the encoder's prepare op.
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - */
> -void drm_bridge_disable(struct drm_bridge *bridge)
> +static void drm_bridge_disable(struct drm_bridge *bridge)
>  {
>  	if (!bridge)
>  		return;
> @@ -257,19 +216,8 @@ void drm_bridge_disable(struct drm_bridge *bridge)
>  	if (bridge->funcs->disable)
>  		bridge->funcs->disable(bridge);
>  }
> -EXPORT_SYMBOL(drm_bridge_disable);
>  
> -/**
> - * drm_bridge_post_disable - cleans up after disabling all bridges in the encoder chain
> - * @bridge: bridge control structure
> - *
> - * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
> - * encoder chain, starting from the first bridge to the last. These are called
> - * after completing the encoder's prepare op.
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - */
> -void drm_bridge_post_disable(struct drm_bridge *bridge)
> +static void drm_bridge_post_disable(struct drm_bridge *bridge)
>  {
>  	if (!bridge)
>  		return;
> @@ -279,23 +227,10 @@ void drm_bridge_post_disable(struct drm_bridge *bridge)
>  
>  	drm_bridge_post_disable(bridge->next);
>  }
> -EXPORT_SYMBOL(drm_bridge_post_disable);
>  
> -/**
> - * drm_bridge_mode_set - set proposed mode for all bridges in the
> - *			 encoder chain
> - * @bridge: bridge control structure
> - * @mode: desired mode to be set for the bridge
> - * @adjusted_mode: updated mode that works for this bridge
> - *
> - * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
> - * encoder chain, starting from the first bridge to the last.
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - */
> -void drm_bridge_mode_set(struct drm_bridge *bridge,
> -			 const struct drm_display_mode *mode,
> -			 const struct drm_display_mode *adjusted_mode)
> +static void drm_bridge_mode_set(struct drm_bridge *bridge,
> +				const struct drm_display_mode *mode,
> +				const struct drm_display_mode *adjusted_mode)
>  {
>  	if (!bridge)
>  		return;
> @@ -305,20 +240,8 @@ void drm_bridge_mode_set(struct drm_bridge *bridge,
>  
>  	drm_bridge_mode_set(bridge->next, mode, adjusted_mode);
>  }
> -EXPORT_SYMBOL(drm_bridge_mode_set);
>  
> -/**
> - * drm_bridge_pre_enable - prepares for enabling all
> - *			   bridges in the encoder chain
> - * @bridge: bridge control structure
> - *
> - * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
> - * chain, starting from the last bridge to the first. These are called
> - * before calling the encoder's commit op.
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - */
> -void drm_bridge_pre_enable(struct drm_bridge *bridge)
> +static void drm_bridge_pre_enable(struct drm_bridge *bridge)
>  {
>  	if (!bridge)
>  		return;
> @@ -328,19 +251,8 @@ void drm_bridge_pre_enable(struct drm_bridge *bridge)
>  	if (bridge->funcs->pre_enable)
>  		bridge->funcs->pre_enable(bridge);
>  }
> -EXPORT_SYMBOL(drm_bridge_pre_enable);
>  
> -/**
> - * drm_bridge_enable - enables all bridges in the encoder chain
> - * @bridge: bridge control structure
> - *
> - * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
> - * chain, starting from the first bridge to the last. These are called
> - * after completing the encoder's commit op.
> - *
> - * Note that the bridge passed should be the one closest to the encoder
> - */
> -void drm_bridge_enable(struct drm_bridge *bridge)
> +static void drm_bridge_enable(struct drm_bridge *bridge)
>  {
>  	if (!bridge)
>  		return;
> @@ -350,22 +262,127 @@ void drm_bridge_enable(struct drm_bridge *bridge)
>  
>  	drm_bridge_enable(bridge->next);
>  }
> -EXPORT_SYMBOL(drm_bridge_enable);
>  
>  /**
> - * drm_atomic_bridge_disable - disables all bridges in the encoder chain
> - * @bridge: bridge control structure
> - * @state: atomic state being committed
> + * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the
> + *				 encoder chain
> + * @encoder: encoder object
> + * @mode: desired mode to be set for the bridge
> + * @adjusted_mode: updated mode that works for this bridge
>   *
> - * Calls &drm_bridge_funcs.atomic_disable (falls back on
> - * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
> - * starting from the last bridge to the first. These are called before calling
> - * &drm_encoder_helper_funcs.atomic_disable
> + * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the
> + * encoder chain, starting from the first bridge to the last.
>   *
> - * Note: the bridge passed should be the one closest to the encoder
> + * RETURNS:
> + * true on success, false on failure
>   */
> -void drm_atomic_bridge_disable(struct drm_bridge *bridge,
> -			       struct drm_atomic_state *state)
> +bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
> +				 const struct drm_display_mode *mode,
> +				 struct drm_display_mode *adjusted_mode)
> +{
> +	return drm_bridge_mode_fixup(encoder->bridge, mode, adjusted_mode);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_mode_fixup);
> +
> +/**
> + * drm_bridge_chain_mode_valid - validate the mode against all bridges in the
> + *				 encoder chain.
> + * @encoder: encoder object
> + * @mode: desired mode to be validated
> + *
> + * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
> + * chain, starting from the first bridge to the last. If at least one bridge
> + * does not accept the mode the function returns the error code.
> + *
> + * RETURNS:
> + * MODE_OK on success, drm_mode_status Enum error code on failure
> + */
> +enum drm_mode_status
> +drm_bridge_chain_mode_valid(struct drm_encoder *encoder,
> +			    const struct drm_display_mode *mode)
> +{
> +	return drm_bridge_mode_valid(encoder->bridge, mode);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
> +
> +/**
> + * drm_bridge_chain_disable - disables all bridges in the encoder chain
> + * @encoder: encoder object
> + *
> + * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
> + * chain, starting from the last bridge to the first. These are called before
> + * calling the encoder's prepare op.
> + */
> +void drm_bridge_chain_disable(struct drm_encoder *encoder)
> +{
> +	drm_bridge_disable(encoder->bridge);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_disable);
> +
> +/**
> + * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
> + *				   encoder chain
> + * @encoder: encoder object
> + *
> + * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
> + * encoder chain, starting from the first bridge to the last. These are called
> + * after completing the encoder's prepare op.
> + */
> +void drm_bridge_chain_post_disable(struct drm_encoder *encoder)
> +{
> +	drm_bridge_post_disable(encoder->bridge);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_post_disable);
> +
> +/**
> + * drm_bridge_chain_mode_set - set proposed mode for all bridges in the
> + *			       encoder chain
> + * @encoder: encoder object
> + * @mode: desired mode to be set for the encoder chain
> + * @adjusted_mode: updated mode that works for this encoder chain
> + *
> + * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
> + * encoder chain, starting from the first bridge to the last.
> + */
> +void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
> +			       const struct drm_display_mode *mode,
> +			       const struct drm_display_mode *adjusted_mode)
> +{
> +	drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_mode_set);
> +
> +/**
> + * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
> + *				 encoder chain
> + * @encoder: encoder object
> + *
> + * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
> + * chain, starting from the last bridge to the first. These are called
> + * before calling the encoder's commit op.
> + */
> +void drm_bridge_chain_pre_enable(struct drm_encoder *encoder)
> +{
> +	drm_bridge_pre_enable(encoder->bridge);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
> +
> +/**
> + * drm_bridge_chain_enable - enables all bridges in the encoder chain
> + * @encoder: encoder object
> + *
> + * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
> + * chain, starting from the first bridge to the last. These are called
> + * after completing the encoder's commit op.
> + */
> +void drm_bridge_chain_enable(struct drm_encoder *encoder)
> +{
> +	drm_bridge_enable(encoder->bridge);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_enable);
> +
> +static void drm_atomic_bridge_disable(struct drm_bridge *bridge,
> +				      struct drm_atomic_state *state)
>  {
>  	if (!bridge)
>  		return;
> @@ -377,23 +394,9 @@ void drm_atomic_bridge_disable(struct drm_bridge *bridge,
>  	else if (bridge->funcs->disable)
>  		bridge->funcs->disable(bridge);
>  }
> -EXPORT_SYMBOL(drm_atomic_bridge_disable);
>  
> -/**
> - * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the
> - *				    encoder chain
> - * @bridge: bridge control structure
> - * @state: atomic state being committed
> - *
> - * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
> - * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
> - * starting from the first bridge to the last. These are called after completing
> - * &drm_encoder_helper_funcs.atomic_disable
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - */
> -void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
> -				    struct drm_atomic_state *state)
> +static void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
> +					   struct drm_atomic_state *state)
>  {
>  	if (!bridge)
>  		return;
> @@ -405,23 +408,9 @@ void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
>  
>  	drm_atomic_bridge_post_disable(bridge->next, state);
>  }
> -EXPORT_SYMBOL(drm_atomic_bridge_post_disable);
>  
> -/**
> - * drm_atomic_bridge_pre_enable - prepares for enabling all bridges in the
> - *				  encoder chain
> - * @bridge: bridge control structure
> - * @state: atomic state being committed
> - *
> - * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
> - * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
> - * starting from the last bridge to the first. These are called before calling
> - * &drm_encoder_helper_funcs.atomic_enable
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - */
> -void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
> -				  struct drm_atomic_state *state)
> +static void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
> +					 struct drm_atomic_state *state)
>  {
>  	if (!bridge)
>  		return;
> @@ -433,22 +422,9 @@ void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
>  	else if (bridge->funcs->pre_enable)
>  		bridge->funcs->pre_enable(bridge);
>  }
> -EXPORT_SYMBOL(drm_atomic_bridge_pre_enable);
>  
> -/**
> - * drm_atomic_bridge_enable - enables all bridges in the encoder chain
> - * @bridge: bridge control structure
> - * @state: atomic state being committed
> - *
> - * Calls &drm_bridge_funcs.atomic_enable (falls back on
> - * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
> - * starting from the first bridge to the last. These are called after completing
> - * &drm_encoder_helper_funcs.atomic_enable
> - *
> - * Note: the bridge passed should be the one closest to the encoder
> - */
> -void drm_atomic_bridge_enable(struct drm_bridge *bridge,
> -			      struct drm_atomic_state *state)
> +static void drm_atomic_bridge_enable(struct drm_bridge *bridge,
> +				     struct drm_atomic_state *state)
>  {
>  	if (!bridge)
>  		return;
> @@ -460,7 +436,76 @@ void drm_atomic_bridge_enable(struct drm_bridge *bridge,
>  
>  	drm_atomic_bridge_enable(bridge->next, state);
>  }
> -EXPORT_SYMBOL(drm_atomic_bridge_enable);
> +
> +/**
> + * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
> + * @encoder: encoder object
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.atomic_disable (falls back on
> + * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
> + * starting from the last bridge to the first. These are called before calling
> + * &drm_encoder_helper_funcs.atomic_disable
> + */
> +void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
> +				     struct drm_atomic_state *state)
> +{
> +	drm_atomic_bridge_disable(encoder->bridge, state);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
> +
> +/**
> + * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
> + *					  in the encoder chain
> + * @encoder: encoder object
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
> + * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
> + * starting from the first bridge to the last. These are called after completing
> + * &drm_encoder_helper_funcs.atomic_disable
> + */
> +void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
> +					  struct drm_atomic_state *state)
> +{
> +	drm_atomic_bridge_post_disable(encoder->bridge, state);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
> +
> +/**
> + * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
> + *					the encoder chain
> + * @encoder: encoder object
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
> + * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
> + * starting from the last bridge to the first. These are called before calling
> + * &drm_encoder_helper_funcs.atomic_enable
> + */
> +void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
> +					struct drm_atomic_state *state)
> +{
> +	drm_atomic_bridge_pre_enable(encoder->bridge, state);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
> +
> +/**
> + * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain
> + * @encoder: encoder object
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.atomic_enable (falls back on
> + * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
> + * starting from the first bridge to the last. These are called after completing
> + * &drm_encoder_helper_funcs.atomic_enable
> + */
> +void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
> +				    struct drm_atomic_state *state)
> +{
> +	drm_atomic_bridge_enable(encoder->bridge, state);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
>  
>  #ifdef CONFIG_OF
>  /**
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 87dae37fec12..f8a361d396df 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -161,7 +161,7 @@ drm_encoder_disable(struct drm_encoder *encoder)
>  		return;
>  
>  	if (!encoder->custom_bridge_enable_disable_seq)
> -		drm_bridge_disable(encoder->bridge);
> +		drm_bridge_chain_disable(encoder);
>  
>  	if (encoder_funcs->disable)
>  		(*encoder_funcs->disable)(encoder);
> @@ -169,7 +169,7 @@ drm_encoder_disable(struct drm_encoder *encoder)
>  		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
>  
>  	if (!encoder->custom_bridge_enable_disable_seq)
> -		drm_bridge_post_disable(encoder->bridge);
> +		drm_bridge_chain_post_disable(encoder);
>  }
>  
>  static void __drm_helper_disable_unused_functions(struct drm_device *dev)
> @@ -329,8 +329,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>  		if (!encoder_funcs)
>  			continue;
>  
> -		ret = drm_bridge_mode_fixup(encoder->bridge,
> -			mode, adjusted_mode);
> +		ret = drm_bridge_chain_mode_fixup(encoder, mode,
> +						  adjusted_mode);
>  		if (!ret) {
>  			DRM_DEBUG_KMS("Bridge fixup failed\n");
>  			goto done;
> @@ -368,14 +368,14 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>  			continue;
>  
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_bridge_disable(encoder->bridge);
> +			drm_bridge_chain_disable(encoder);
>  
>  		/* Disable the encoders as the first thing we do. */
>  		if (encoder_funcs->prepare)
>  			encoder_funcs->prepare(encoder);
>  
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_bridge_post_disable(encoder->bridge);
> +			drm_bridge_chain_post_disable(encoder);
>  	}
>  
>  	drm_crtc_prepare_encoders(dev);
> @@ -403,7 +403,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>  		if (encoder_funcs->mode_set)
>  			encoder_funcs->mode_set(encoder, mode, adjusted_mode);
>  
> -		drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
> +		drm_bridge_chain_mode_set(encoder, mode, adjusted_mode);
>  	}
>  
>  	/* Now enable the clocks, plane, pipe, and connectors that we set up. */
> @@ -419,13 +419,13 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>  			continue;
>  
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_bridge_pre_enable(encoder->bridge);
> +			drm_bridge_chain_pre_enable(encoder);
>  
>  		if (encoder_funcs->commit)
>  			encoder_funcs->commit(encoder);
>  
>  		if (!encoder->custom_bridge_enable_disable_seq)
> -			drm_bridge_enable(encoder->bridge);
> +			drm_bridge_chain_enable(encoder);
>  	}
>  
>  	/* Calculate and store various constants which
> @@ -824,7 +824,6 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
>  /* Helper which handles bridge ordering around encoder dpms */
>  static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
>  {
> -	struct drm_bridge *bridge = encoder->bridge;
>  	const struct drm_encoder_helper_funcs *encoder_funcs;
>  
>  	encoder_funcs = encoder->helper_private;
> @@ -833,9 +832,9 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
>  
>  	if (!encoder->custom_bridge_enable_disable_seq) {
>  		if (mode == DRM_MODE_DPMS_ON)
> -			drm_bridge_pre_enable(bridge);
> +			drm_bridge_chain_pre_enable(encoder);
>  		else
> -			drm_bridge_disable(bridge);
> +			drm_bridge_chain_disable(encoder);
>  	}
>  
>  	if (encoder_funcs->dpms)
> @@ -843,9 +842,9 @@ static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
>  
>  	if (!encoder->custom_bridge_enable_disable_seq) {
>  		if (mode == DRM_MODE_DPMS_ON)
> -			drm_bridge_enable(bridge);
> +			drm_bridge_chain_enable(encoder);
>  		else
> -			drm_bridge_post_disable(bridge);
> +			drm_bridge_chain_post_disable(encoder);
>  	}
>  }
>  
> diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
> index 351cbc40f0f8..461199bc28c0 100644
> --- a/drivers/gpu/drm/drm_probe_helper.c
> +++ b/drivers/gpu/drm/drm_probe_helper.c
> @@ -113,7 +113,7 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode,
>  			continue;
>  		}
>  
> -		ret = drm_bridge_mode_valid(encoder->bridge, mode);
> +		ret = drm_bridge_chain_mode_valid(encoder, mode);
>  		if (ret != MODE_OK) {
>  			/* There is also no point in continuing for crtc check
>  			 * here. */
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index 8593c87bdf96..9a96bc48b81f 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1389,7 +1389,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
>  		if (ret < 0)
>  			goto err_put_sync;
>  	} else {
> -		drm_bridge_pre_enable(encoder->bridge);
> +		drm_bridge_chain_pre_enable(encoder);
>  	}
>  
>  	exynos_dsi_set_display_mode(dsi);
> @@ -1400,7 +1400,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
>  		if (ret < 0)
>  			goto err_display_disable;
>  	} else {
> -		drm_bridge_enable(encoder->bridge);
> +		drm_bridge_chain_enable(encoder);
>  	}
>  
>  	dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
> @@ -1425,10 +1425,10 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
>  	dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
>  
>  	drm_panel_disable(dsi->panel);
> -	drm_bridge_disable(encoder->bridge);
> +	drm_bridge_chain_disable(encoder);
>  	exynos_dsi_set_display_enable(dsi, false);
>  	drm_panel_unprepare(dsi->panel);
> -	drm_bridge_post_disable(encoder->bridge);
> +	drm_bridge_chain_post_disable(encoder);
>  	dsi->state &= ~DSIM_STATE_ENABLED;
>  	pm_runtime_put_sync(dsi->dev);
>  }
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index c79b1f855d89..6ec3d2584539 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -1247,8 +1247,8 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn,
>  		struct drm_display_mode adjusted_mode;
>  
>  		drm_mode_copy(&adjusted_mode, mode);
> -		if (!drm_bridge_mode_fixup(hdmi->bridge.next, mode,
> -					   &adjusted_mode))
> +		if (!drm_bridge_chain_mode_fixup(hdmi->bridge.encoder, mode,
> +						 &adjusted_mode))
>  			return MODE_BAD;
>  	}
>  
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index b670ca473786..d7cd720c4efa 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -752,9 +752,9 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
>  	struct vc4_dsi *dsi = vc4_encoder->dsi;
>  	struct device *dev = &dsi->pdev->dev;
>  
> -	drm_bridge_disable(encoder->bridge);
> +	drm_bridge_chain_disable(encoder);
>  	vc4_dsi_ulps(dsi, true);
> -	drm_bridge_post_disable(encoder->bridge);
> +	drm_bridge_chain_post_disable(encoder);
>  
>  	clk_disable_unprepare(dsi->pll_phy_clock);
>  	clk_disable_unprepare(dsi->escape_clock);
> @@ -1054,7 +1054,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
>  
>  	vc4_dsi_ulps(dsi, false);
>  
> -	drm_bridge_pre_enable(encoder->bridge);
> +	drm_bridge_chain_pre_enable(encoder);
>  
>  	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
>  		DSI_PORT_WRITE(DISP0_CTRL,
> @@ -1071,7 +1071,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
>  			       DSI_DISP0_ENABLE);
>  	}
>  
> -	drm_bridge_enable(encoder->bridge);
> +	drm_bridge_chain_enable(encoder);
>  
>  	if (debug_dump_regs) {
>  		struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 7616f6562fe4..3057e2153f62 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -254,9 +254,10 @@ struct drm_bridge_funcs {
>  	 * there is one) when this callback is called.
>  	 *
>  	 * Note that this function will only be invoked in the context of an
> -	 * atomic commit. It will not be invoked from &drm_bridge_pre_enable. It
> -	 * would be prudent to also provide an implementation of @pre_enable if
> -	 * you are expecting driver calls into &drm_bridge_pre_enable.
> +	 * atomic commit. It will not be invoked from
> +	 * &drm_bridge_chain_pre_enable. It would be prudent to also provide an
> +	 * implementation of @pre_enable if you are expecting driver calls into
> +	 * &drm_bridge_chain_pre_enable.
>  	 *
>  	 * The @atomic_pre_enable callback is optional.
>  	 */
> @@ -279,9 +280,9 @@ struct drm_bridge_funcs {
>  	 * chain if there is one.
>  	 *
>  	 * Note that this function will only be invoked in the context of an
> -	 * atomic commit. It will not be invoked from &drm_bridge_enable. It
> -	 * would be prudent to also provide an implementation of @enable if
> -	 * you are expecting driver calls into &drm_bridge_enable.
> +	 * atomic commit. It will not be invoked from &drm_bridge_chain_enable.
> +	 * It would be prudent to also provide an implementation of @enable if
> +	 * you are expecting driver calls into &drm_bridge_chain_enable.
>  	 *
>  	 * The enable callback is optional.
>  	 */
> @@ -301,9 +302,10 @@ struct drm_bridge_funcs {
>  	 * signals) feeding it is still running when this callback is called.
>  	 *
>  	 * Note that this function will only be invoked in the context of an
> -	 * atomic commit. It will not be invoked from &drm_bridge_disable. It
> -	 * would be prudent to also provide an implementation of @disable if
> -	 * you are expecting driver calls into &drm_bridge_disable.
> +	 * atomic commit. It will not be invoked from
> +	 * &drm_bridge_chain_disable. It would be prudent to also provide an
> +	 * implementation of @disable if you are expecting driver calls into
> +	 * &drm_bridge_chain_disable.
>  	 *
>  	 * The disable callback is optional.
>  	 */
> @@ -325,10 +327,11 @@ struct drm_bridge_funcs {
>  	 * called.
>  	 *
>  	 * Note that this function will only be invoked in the context of an
> -	 * atomic commit. It will not be invoked from &drm_bridge_post_disable.
> +	 * atomic commit. It will not be invoked from
> +	 * &drm_bridge_chain_post_disable.
>  	 * It would be prudent to also provide an implementation of
>  	 * @post_disable if you are expecting driver calls into
> -	 * &drm_bridge_post_disable.
> +	 * &drm_bridge_chain_post_disable.
>  	 *
>  	 * The post_disable callback is optional.
>  	 */
> @@ -406,27 +409,28 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
>  int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
>  		      struct drm_bridge *previous);
>  
> -bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> -			   const struct drm_display_mode *mode,
> -			   struct drm_display_mode *adjusted_mode);
> -enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
> -					   const struct drm_display_mode *mode);
> -void drm_bridge_disable(struct drm_bridge *bridge);
> -void drm_bridge_post_disable(struct drm_bridge *bridge);
> -void drm_bridge_mode_set(struct drm_bridge *bridge,
> -			 const struct drm_display_mode *mode,
> -			 const struct drm_display_mode *adjusted_mode);
> -void drm_bridge_pre_enable(struct drm_bridge *bridge);
> -void drm_bridge_enable(struct drm_bridge *bridge);
> +bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
> +				 const struct drm_display_mode *mode,
> +				 struct drm_display_mode *adjusted_mode);
> +enum drm_mode_status
> +drm_bridge_chain_mode_valid(struct drm_encoder *encoder,
> +			    const struct drm_display_mode *mode);
> +void drm_bridge_chain_disable(struct drm_encoder *encoder);
> +void drm_bridge_chain_post_disable(struct drm_encoder *encoder);
> +void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
> +			       const struct drm_display_mode *mode,
> +			       const struct drm_display_mode *adjusted_mode);
> +void drm_bridge_chain_pre_enable(struct drm_encoder *encoder);
> +void drm_bridge_chain_enable(struct drm_encoder *encoder);
>  
> -void drm_atomic_bridge_disable(struct drm_bridge *bridge,
> -			       struct drm_atomic_state *state);
> -void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
> +void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
> +				     struct drm_atomic_state *state);
> +void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
> +					  struct drm_atomic_state *state);
> +void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
> +					struct drm_atomic_state *state);
> +void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>  				    struct drm_atomic_state *state);
> -void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
> -				  struct drm_atomic_state *state);
> -void drm_atomic_bridge_enable(struct drm_bridge *bridge,
> -			      struct drm_atomic_state *state);
>  
>  #ifdef CONFIG_DRM_PANEL_BRIDGE
>  struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
> -- 
> 2.21.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] 58+ messages in thread

* Re: [PATCH RFC 07/19] drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder
  2019-08-19 17:19   ` Sam Ravnborg
@ 2019-08-21 14:46     ` Laurent Pinchart
  0 siblings, 0 replies; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-21 14:46 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Jernej Skrabec, Jonas Karlman, Neil Armstrong, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Boris Brezillon, Thierry Reding,
	Chris Healy, kernel, Sean Paul

On Mon, Aug 19, 2019 at 07:19:39PM +0200, Sam Ravnborg wrote:
> On Thu, Aug 08, 2019 at 05:11:38PM +0200, Boris Brezillon wrote:
> > This is part of our attempt to make the bridge chain a double-linked
> > list based on the generic list helpers. In order to do that, we must
> > patch all drivers manipulating the encoder->bridge field directly.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
> 
> Sean, this patch looks like a nice cleanup we can apply
> outside the series.
> It would be good that drivers do not poke direct in
> the encoder data that this patch fixes.

Agreed, and

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

> > ---
> >  drivers/gpu/drm/msm/edp/edp.c   | 4 +++-
> >  drivers/gpu/drm/msm/hdmi/hdmi.c | 4 +++-
> >  2 files changed, 6 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c
> > index 0f312ac5b624..ad4e963ccd9b 100644
> > --- a/drivers/gpu/drm/msm/edp/edp.c
> > +++ b/drivers/gpu/drm/msm/edp/edp.c
> > @@ -178,7 +178,9 @@ int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
> >  		goto fail;
> >  	}
> >  
> > -	encoder->bridge = edp->bridge;
> > +	ret = drm_bridge_attach(encoder, edp->bridge, NULL);
> > +	if (ret)
> > +		goto fail;
> >  
> >  	priv->bridges[priv->num_bridges++]       = edp->bridge;
> >  	priv->connectors[priv->num_connectors++] = edp->connector;
> > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > index 0e4217be3f00..55b9a8c8312b 100644
> > --- a/drivers/gpu/drm/msm/hdmi/hdmi.c
> > +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
> > @@ -327,7 +327,9 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
> >  		goto fail;
> >  	}
> >  
> > -	encoder->bridge = hdmi->bridge;
> > +	ret = drm_bridge_attach(encoder, hdmi->bridge, NULL);
> > +	if (ret)
> > +		goto fail;
> >  
> >  	priv->bridges[priv->num_bridges++]       = hdmi->bridge;
> >  	priv->connectors[priv->num_connectors++] = hdmi->connector;

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially
  2019-08-20 19:05   ` Laurent Pinchart
  2019-08-21  8:21     ` Daniel Vetter
@ 2019-08-21 15:30     ` Boris Brezillon
  1 sibling, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-21 15:30 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Tue, 20 Aug 2019 22:05:05 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:33PM +0200, Boris Brezillon wrote:
> > The VC4 and Exynos DSI encoder drivers need a custom enable/disable
> > sequence and manually set encoder->bridge to NULL to prevent the core
> > from calling the bridge hooks.
> > 
> > Let's provide a more official way to support custom bridge/encoder
> > enable/disable sequences.  
> 
> So, while I'm not opposed to this, I think it's a bit of a hack, and I'd
> like to share my vision of how I'd like to see this being implemented in
> the more distant future (and thus possibly on top of this change).

I agree, it definitely looks like a hack, but I find it less hack-ish
than letting drivers re-initialize the encoder->bridge field to NULL
just after calling bridge_attach() :P.

> 
> It has been established for quite some time now that exposing
> drm_encoder to userspace was likely a mistake, and that it should have
> stayed a kernel-only object. With the generalised usage of drm_bridge, I
> would go one step further: drm_encoder shouldn't matter for DRM/KMS
> drivers at all.

I couldn't agree more.

> 
> drm_bridge has been introduced to model chained encoders, where the
> second (and subsequent) encoders couldn't easily be supported in a
> standard and reusable way with just drm_encoder. A bridge (with the
> exception of the panel bridge) is just an encoder. It shouldn't matter
> whether encoders are internal to the display controller, separate IPs in
> the SoC or external components, they could all be modelled as bridges.
> We do have bridges for DSI encoder IPs, and DSI (and other) bridges
> potentially need similar custom enable/disable sequences. I would thus
> ideally like to see the VC4 and Exynos DSI encoders being implemented as
> bridges, with support for custom enable/disable sequences in bridges,
> and drop support for custom enable/disable sequences in drm_encoder.

Looks like we're on the same page.

> 
> Does this make sense to you ?

Definitely.

> While I would love to see this being
> implemented right away, it may be too much work as a prerequisite for
> this bus format negotiation series, so I don't want to reject this
> patch. I would however like to already make sure we agree on the way
> forward for the next steps.

Actually, I think I have something [1] that implements what you're
proposing here (which is not surprising since we discussed it on
IRC ;)). I'll send a v2 so you can comment on the new approach.

[1]https://github.com/bbrezillon/linux-0day/commits/drm-bridge-busfmt-2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially
  2019-08-21  8:21     ` Daniel Vetter
  2019-08-21 13:57       ` Laurent Pinchart
@ 2019-08-21 15:39       ` Boris Brezillon
  1 sibling, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-21 15:39 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg, Laurent Pinchart

On Wed, 21 Aug 2019 10:21:07 +0200
Daniel Vetter <daniel@ffwll.ch> wrote:

> On Tue, Aug 20, 2019 at 10:05:05PM +0300, Laurent Pinchart wrote:
> > Hi Boris,
> > 
> > Thank you for the patch.
> > 
> > On Thu, Aug 08, 2019 at 05:11:33PM +0200, Boris Brezillon wrote:  
> > > The VC4 and Exynos DSI encoder drivers need a custom enable/disable
> > > sequence and manually set encoder->bridge to NULL to prevent the core
> > > from calling the bridge hooks.
> > > 
> > > Let's provide a more official way to support custom bridge/encoder
> > > enable/disable sequences.  
> > 
> > So, while I'm not opposed to this, I think it's a bit of a hack, and I'd
> > like to share my vision of how I'd like to see this being implemented in
> > the more distant future (and thus possibly on top of this change).  
> 
> I think it's also counter to how the atomic helpers are meant to be used.
> I mean you're adding a pile new hooks here all for essentially not having
> to type a few lines of helper code. If you look around at big drivers
> (i915, amdgpu, nouveau) _none_ of them use the modesets_enables/disables
> helpers. Exactly for reasons like this where you need a custom sequence.
> 
> So proper recommendation is to just type your own, you'll be happier.
> 
> > It has been established for quite some time now that exposing
> > drm_encoder to userspace was likely a mistake, and that it should have
> > stayed a kernel-only object. With the generalised usage of drm_bridge, I
> > would go one step further: drm_encoder shouldn't matter for DRM/KMS
> > drivers at all.
> > 
> > drm_bridge has been introduced to model chained encoders, where the
> > second (and subsequent) encoders couldn't easily be supported in a
> > standard and reusable way with just drm_encoder. A bridge (with the
> > exception of the panel bridge) is just an encoder. It shouldn't matter
> > whether encoders are internal to the display controller, separate IPs in
> > the SoC or external components, they could all be modelled as bridges.
> > We do have bridges for DSI encoder IPs, and DSI (and other) bridges
> > potentially need similar custom enable/disable sequences. I would thus
> > ideally like to see the VC4 and Exynos DSI encoders being implemented as
> > bridges, with support for custom enable/disable sequences in bridges,
> > and drop support for custom enable/disable sequences in drm_encoder.
> > 
> > Does this make sense to you ? While I would love to see this being
> > implemented right away, it may be too much work as a prerequisite for
> > this bus format negotiation series, so I don't want to reject this
> > patch. I would however like to already make sure we agree on the way
> > forward for the next steps.  
> 
> Yeah the other bit is that bridges are supposed to be some kind of
> standard. I do wonder (I haven't looked at the series) whether the problem
> here is that encoders don't have their own full set of pre/post enable
> hooks like bridges (essentially that's what you're adding here), or
> whether the idea behind pre/post enable/disable hooks is not good enough.

It's just that we lack the pre/post enable hooks at the encoder level.
But I'm addressing this limitation slightly differently in the v2 I'm
working on.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h
  2019-08-20 18:53   ` Laurent Pinchart
@ 2019-08-21 15:44     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-21 15:44 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Tue, 20 Aug 2019 21:53:15 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:32PM +0200, Boris Brezillon wrote:
> > We are about to add a drm_bridge_state that inherits from
> > drm_private_state which is defined in drm_atomic.h. Problem is,
> > drm_atomic.h includes drm_crtc.h which in turn includes drm_bridge.h,
> > leading to "drm_private_state has incomplete type" error.
> > 
> > Let's force all users of the drm_bridge API to explicitly include
> > drm_bridge.h.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > ---
> >  drivers/gpu/drm/arc/arcpgu_hdmi.c                        | 1 +
> >  drivers/gpu/drm/bridge/analogix-anx78xx.c                | 1 +
> >  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c       | 1 +
> >  drivers/gpu/drm/bridge/dumb-vga-dac.c                    | 1 +
> >  drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 1 +
> >  drivers/gpu/drm/bridge/nxp-ptn3460.c                     | 1 +
> >  drivers/gpu/drm/bridge/panel.c                           | 1 +
> >  drivers/gpu/drm/bridge/parade-ps8622.c                   | 1 +
> >  drivers/gpu/drm/bridge/sii902x.c                         | 1 +
> >  drivers/gpu/drm/bridge/sii9234.c                         | 1 +
> >  drivers/gpu/drm/bridge/sil-sii8620.c                     | 1 +
> >  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c                | 1 +
> >  drivers/gpu/drm/bridge/tc358764.c                        | 1 +
> >  drivers/gpu/drm/bridge/tc358767.c                        | 1 +
> >  drivers/gpu/drm/bridge/ti-sn65dsi86.c                    | 1 +
> >  drivers/gpu/drm/bridge/ti-tfp410.c                       | 1 +
> >  drivers/gpu/drm/drm_atomic_helper.c                      | 1 +
> >  drivers/gpu/drm/drm_crtc_helper.c                        | 1 +
> >  drivers/gpu/drm/drm_encoder.c                            | 1 +
> >  drivers/gpu/drm/drm_probe_helper.c                       | 1 +
> >  drivers/gpu/drm/drm_simple_kms_helper.c                  | 1 +
> >  drivers/gpu/drm/exynos/exynos_dp.c                       | 1 +
> >  drivers/gpu/drm/exynos/exynos_drm_dsi.c                  | 1 +
> >  drivers/gpu/drm/exynos/exynos_drm_mic.c                  | 1 +
> >  drivers/gpu/drm/exynos/exynos_hdmi.c                     | 1 +
> >  drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c                | 1 +
> >  drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c             | 1 +
> >  drivers/gpu/drm/i2c/tda998x_drv.c                        | 1 +
> >  drivers/gpu/drm/imx/imx-ldb.c                            | 1 +
> >  drivers/gpu/drm/imx/parallel-display.c                   | 1 +
> >  drivers/gpu/drm/ingenic/ingenic-drm.c                    | 1 +
> >  drivers/gpu/drm/mediatek/mtk_dpi.c                       | 1 +
> >  drivers/gpu/drm/mediatek/mtk_dsi.c                       | 1 +
> >  drivers/gpu/drm/mediatek/mtk_hdmi.c                      | 1 +
> >  drivers/gpu/drm/msm/dsi/dsi.h                            | 1 +
> >  drivers/gpu/drm/msm/edp/edp.h                            | 1 +
> >  drivers/gpu/drm/msm/hdmi/hdmi.h                          | 2 ++
> >  drivers/gpu/drm/omapdrm/dss/output.c                     | 1 +
> >  drivers/gpu/drm/omapdrm/omap_drv.c                       | 1 +
> >  drivers/gpu/drm/omapdrm/omap_encoder.c                   | 1 +
> >  drivers/gpu/drm/rcar-du/rcar_du_encoder.c                | 1 +
> >  drivers/gpu/drm/rockchip/rockchip_lvds.c                 | 1 +
> >  drivers/gpu/drm/rockchip/rockchip_rgb.c                  | 1 +
> >  drivers/gpu/drm/sti/sti_dvo.c                            | 1 +
> >  drivers/gpu/drm/sti/sti_hda.c                            | 1 +
> >  drivers/gpu/drm/sti/sti_hdmi.c                           | 1 +
> >  drivers/gpu/drm/sun4i/sun4i_lvds.c                       | 1 +
> >  drivers/gpu/drm/sun4i/sun4i_rgb.c                        | 1 +
> >  drivers/gpu/drm/sun4i/sun4i_tcon.c                       | 1 +
> >  drivers/gpu/drm/tilcdc/tilcdc_external.c                 | 1 +
> >  drivers/gpu/drm/vc4/vc4_dsi.c                            | 1 +
> >  include/drm/drm_crtc.h                                   | 1 -
> >  52 files changed, 52 insertions(+), 1 deletion(-)  
> 
> Overall this looks good to me. Before I ack the patch, how have you
> tested this ? Have you compiled all the DRM/KMS drivers ?

git grep to find all drm_bridge users that were not including
drm_bridge.h directly and then I compiled all impacted drivers. Also
pushed to a tree monitored by kbuild bots to make sure I didn't
forget one of them.

> 
> If you wanted to go one step further you could also remove the forward
> declaration of struct drm_bridge from drm_ctrc.h, as it's not needed
> there.
> 

I'll add a patch doing that.

Thanks,

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

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

* Re: [PATCH RFC 06/19] drm/bridge: Create drm_bridge_chain_xx() wrappers
  2019-08-21 14:45   ` Laurent Pinchart
@ 2019-08-21 15:53     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-21 15:53 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Wed, 21 Aug 2019 17:45:04 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:37PM +0200, Boris Brezillon wrote:
> > DRM bridges should not be operated independently. Let's rename the
> > drm_bridge_xxx() helpers that take the first bridge of the chain and
> > iterate over the whole chain into drm_bridge_chain_xx(). We also pass
> > it the encoder containing the bridge chain instead of the dereferencing
> > encoder->bridge.  
> 
> I'm not sure about this. I do agree that the helpers operate on a chain,
> but I think they're use for calling them on any bridge, especially in
> conjunction with your work. The way I see it is that when a bridge in
> the chain needs a custom enable/disable sequence (flagged by some kind
> of flag in the bridge structure), the helpers will not automatically
> propagate the calls down the chain, and let the bridge call the pre/post
> enable/disable operations on the downstream bridge. This means that
> those bridges with special needs will have to call the helpers on the
> next bridge down the chain, and thus require keeping the ability to do
> so.

Also changed my mind on this one after the discussion we had. I
kept the rename part but dropper the s/bridge/encoder/ change. This way,
bridges that need to control the enable/disable sequence can use those
helpers on a sub-chain (the chain starting at the bridge element just
after them).

> 
> We could of course propose two sets of helpers, one taking a bridge
> pointer, and another one taking an encoder pointer, but I think it's a
> bit overkill. Especially if you consider my comments earlier in this
> series where I propose moving the custom sequence feature to bridges
> instead of encoders, I don't think this patch will be needed.

Agreed. As said above, I kept the rename part of this patch because I
think it better reflects the fact that those helpers are acting on a
bridge chain, and not a single bridge element.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-14  7:51   ` Neil Armstrong
@ 2019-08-21 18:31     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-21 18:31 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Jernej Skrabec, Laurent Pinchart, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Wed, 14 Aug 2019 09:51:07 +0200
Neil Armstrong <narmstrong@baylibre.com> wrote:

> On 08/08/2019 17:11, Boris Brezillon wrote:
> > This takes the form of various helpers, plus the addition of 2 new
> > structs:
> > * drm_bus_caps: describe the bus capabilities of a bridge/encoder. For
> >   bridges we have one for the input port and one for the output port.
> >   Encoders just have one output port.
> > * drm_bus_cfg: added to the drm_bridge_state. It's supposed to store
> >   bus configuration information. For now we just have format and flags
> >   but more fields might be added in the future. Again, each
> >   drm_bridge_state contains 2 drm_bus_cfg elements: one for the output
> >   port and one for the input port
> > 
> > Helpers can be used from bridge drivers' ->atomic_check() implementation
> > to negotiate the bus format to use. Negotiation happens in reserve order,
> > starting from the last element of the bridge chain (the one directly
> > connected to the display) to the first element of the chain (the one
> > connected to the encoder).
> > 
> > Negotiation usually takes place in 2 steps:
> > * make sure the input end of the next element in the chain picked a
> >   format that's supported by the output end of our bridge. That's done
> >   with drm_atomic_bridge_choose_output_bus_cfg().
> > * choose a format for the input end of our bridge based on what's
> >   supported by the previous bridge in the chain. This is achieved by
> >   calling drm_atomic_bridge_choose_input_bus_cfg()
> > 
> > Note that those helpers are a bit lax when it comes to unitialized
> > bus format validation. That's intentional. If we don't do that we'll
> > basically break things if we start adding support for bus format
> > negotiation to some elements of the pipeline leaving others on the
> > side, and that's likely to happen for all external bridges since we
> > can't necessarily tell where they are used.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > ---
> >  drivers/gpu/drm/drm_bridge.c | 187 +++++++++++++++++++++++++++++++++++
> >  include/drm/drm_bridge.h     |  46 +++++++++
> >  include/drm/drm_encoder.h    |   6 ++
> >  3 files changed, 239 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 9efb27087e70..ef072df42422 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -602,6 +602,193 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
> >  }
> >  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
> >  
> > +int drm_find_best_bus_format(const struct drm_bus_caps *a,
> > +			     const struct drm_bus_caps *b,
> > +			     const struct drm_display_mode *mode,
> > +			     u32 *selected_bus_fmt)
> > +{
> > +	unsigned int i, j;
> > +
> > +	/*
> > +	 * Some drm_bridge/drm_encoder don't care about the input/output bus
> > +	 * format, let's set the format to zero in that case (this is only
> > +	 * valid if both side of the link don't care).
> > +	 */
> > +	if (!a->num_supported_fmts && !b->num_supported_fmts) {
> > +		*selected_bus_fmt = 0;
> > +		return 0;
> > +	} else if (b->num_supported_fmts > 1 && b->supported_fmts) {
> > +		*selected_bus_fmt = b->supported_fmts[0];
> > +		return 0;  
> 
> Here, `!a->num_supported_fmts &&` is missing otherwise this code will
> select b->supported_fmts[0] whatever the supported formats of a.
> 
> > +	} else if (a->num_supported_fmts > 1 && a->supported_fmts) {
> > +		*selected_bus_fmt = a->supported_fmts[0];
> > +		return 0;  
> 
> Here, `!b->num_supported_fmts &&` is missing otherwise this code will
> select a->supported_fmts[0] whatever the supported formats of b.
> 
> > +	} else if (!a->num_supported_fmts || !a->supported_fmts ||
> > +		   !b->num_supported_fmts || !b->supported_fmts) {
> > +		return -EINVAL;
> > +	}
> > +
> > +	/*
> > +	 * TODO:
> > +	 * Dummy algo picking the first match. We probably want something
> > +	 * smarter where the narrowest format (in term of bus width) that
> > +	 * does not incur data loss is picked, and if all possible formats
> > +	 * are lossy, pick the one that's less lossy among all the choices
> > +	 * we have. In order to do that we'd need to convert MEDIA_BUS_FMT_
> > +	 * modes into something like drm_format_info.
> > +	 */
> > +	for (i = 0; i < a->num_supported_fmts; i++) {
> > +		for (j = 0; j < b->num_supported_fmts; j++) {
> > +			if (a->supported_fmts[i] == b->supported_fmts[j]) {
> > +				*selected_bus_fmt = a->supported_fmts[i];
> > +				return 0;
> > +			}
> > +		}
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +EXPORT_SYMBOL(drm_find_best_bus_format);  
> 
> [...]
> 
> With that fixed, this works with basic negociation of the single MEDIA_BUS_FMT_YUV8_1X24
> exposed by the meson hdmi encoder, otherwise it takes the first default MEDIA_BUS_FMT_RGB888_1X24
> format exposed by dw-hdmi.

Thanks for the report. Will be fixed in v2.

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

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

* Re: [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object
  2019-08-08 15:11 ` [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object Boris Brezillon
@ 2019-08-21 20:14   ` Laurent Pinchart
  2019-08-22  9:00     ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-21 20:14 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:41PM +0200, Boris Brezillon wrote:
> One of the last remaining object to not have its atomic state.
> 
> This is being motivated by our attempt to support runtime bus-format
> negotiation between elements of the bridge chain.
> This patch just paves the road for such a feature by adding a new
> drm_bridge_state object inheriting from drm_private_obj so we can
> re-use some of the state initialization/tracking logic.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/drm_atomic.c        |  40 ++++++++
>  drivers/gpu/drm/drm_atomic_helper.c |  18 ++++
>  drivers/gpu/drm/drm_bridge.c        | 141 +++++++++++++++++++++++++++-
>  include/drm/drm_atomic.h            |   3 +
>  include/drm/drm_bridge.h            |  99 +++++++++++++++++++
>  5 files changed, 296 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 419381abbdd1..ed6fd3e31b56 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -30,6 +30,7 @@
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_drv.h>
> @@ -1010,6 +1011,45 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
>  		connector->funcs->atomic_print_state(p, state);
>  }
>  
> +/**
> + * drm_atomic_add_encoder_bridges - add bridges attached to an encoder
> + * @state: atomic state
> + * @encoder: DRM encoder
> + *
> + * This function adds all bridges attached to @encoder. This is needed to add
> + * bridge states to @state and make them available when
> + * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are
> + * called
> + *
> + * Returns:
> + * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
> + * then the w/w mutex code has detected a deadlock and the entire atomic
> + * sequence must be restarted. All other errors are fatal.
> + */
> +int
> +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
> +			       struct drm_encoder *encoder)
> +{
> +	struct drm_bridge_state *bridge_state;
> +	struct drm_bridge *bridge;
> +
> +	if (!encoder)
> +		return 0;
> +
> +	DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n",
> +			 encoder->base.id, encoder->name, state);
> +
> +	for (bridge = drm_bridge_chain_get_first_bridge(encoder); bridge;
> +	     bridge = drm_bridge_chain_get_next_bridge(bridge)) {

Would a for_each_bridge() macro make sense ? I'd implement it on top of
list_for_each_entry() to make it simple.

> +		bridge_state = drm_atomic_get_bridge_state(state, bridge);
> +		if (IS_ERR(bridge_state))
> +			return PTR_ERR(bridge_state);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
> +
>  /**
>   * drm_atomic_add_affected_connectors - add connectors for crtc
>   * @state: atomic state
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 0deb54099570..e76ec9648b6f 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -736,6 +736,24 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
>  			return ret;
>  	}
>  
> +	/*
> +	 * Iterate over all connectors again, and add all affected bridges to
> +	 * the state.
> +	 */
> +	for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
> +		struct drm_encoder *encoder;
> +
> +		encoder = old_connector_state->best_encoder;
> +		ret = drm_atomic_add_encoder_bridges(state, encoder);
> +		if (ret)
> +			return ret;
> +
> +		encoder = new_connector_state->best_encoder;
> +		ret = drm_atomic_add_encoder_bridges(state, encoder);
> +		if (ret)
> +			return ret;
> +	}
> +
>  	ret = mode_valid(state);
>  	if (ret)
>  		return ret;
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index ed2410f49581..0280da6be1e6 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -89,6 +89,38 @@ void drm_bridge_remove(struct drm_bridge *bridge)
>  }
>  EXPORT_SYMBOL(drm_bridge_remove);
>  
> +static struct drm_private_state *
> +drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
> +{
> +	struct drm_bridge *bridge = drm_priv_to_bridge(obj);
> +	struct drm_bridge_state *state;
> +
> +	if (bridge->funcs->atomic_duplicate_state)
> +		state = bridge->funcs->atomic_duplicate_state(bridge);
> +	else
> +		state = drm_atomic_helper_duplicate_bridge_state(bridge);
> +
> +	return &state->base;
> +}
> +
> +static void
> +drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
> +                                     struct drm_private_state *s)
> +{
> +	struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
> +	struct drm_bridge *bridge = drm_priv_to_bridge(obj);
> +
> +	if (bridge->funcs->atomic_destroy_state)
> +		bridge->funcs->atomic_destroy_state(bridge, state);
> +	else
> +		drm_atomic_helper_destroy_bridge_state(bridge, state);
> +}
> +
> +static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
> +	.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
> +	.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
> +};
> +
>  /**
>   * drm_bridge_attach - attach the bridge to an encoder's chain
>   *
> @@ -114,6 +146,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
>  int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
>  		      struct drm_bridge *previous)
>  {
> +	struct drm_bridge_state *state;
>  	LIST_HEAD(tmp_list);
>  	int ret;
>  
> @@ -132,19 +165,39 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
>  
>  	if (bridge->funcs->attach) {
>  		ret = bridge->funcs->attach(bridge);
> -		if (ret < 0) {
> -			bridge->dev = NULL;
> -			bridge->encoder = NULL;
> -			return ret;
> -		}
> +		if (ret < 0)
> +			goto err_reset_bridge;
>  	}
>  
> +	if (bridge->funcs->atomic_duplicate_state)
> +		state = bridge->funcs->atomic_duplicate_state(bridge);
> +	else
> +		state = drm_atomic_helper_duplicate_bridge_state(bridge);
> +
> +	if (!state) {
> +		ret = -ENOMEM;
> +		goto err_detach_bridge;
> +	}
> +
> +	drm_atomic_private_obj_init(bridge->dev, &bridge->base,
> +				    &state->base,
> +				    &drm_bridge_priv_state_funcs);
> +
>  	if (previous)
>  		list_splice(&tmp_list, &previous->chain_node);
>  	else
>  		list_splice(&tmp_list, &encoder->bridge_chain);
>  
>  	return 0;
> +
> +err_detach_bridge:
> +	if (bridge->funcs->detach)
> +		bridge->funcs->detach(bridge);
> +
> +err_reset_bridge:
> +	bridge->dev = NULL;
> +	bridge->encoder = NULL;
> +	return ret;
>  }
>  EXPORT_SYMBOL(drm_bridge_attach);
>  
> @@ -156,6 +209,8 @@ void drm_bridge_detach(struct drm_bridge *bridge)
>  	if (WARN_ON(!bridge->dev))
>  		return;
>  
> +	drm_atomic_private_obj_fini(&bridge->base);
> +
>  	if (bridge->funcs->detach)
>  		bridge->funcs->detach(bridge);
>  
> @@ -495,6 +550,82 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
>  
> +/**
> + * drm_atomic_helper_init_bridge_state() - Initializes a bridge state

s/Initializes/Initialize/

> + * @bridge this state is referring to

Did you mean

 * @bridge: the bridge this state is referring to ?

> + * @state: bridge state to initialize
> + *
> + * For now it's just a memset(0) plus a state->bridge assignment. Might
> + * be extended in the future.
> + */
> +void drm_atomic_helper_init_bridge_state(struct drm_bridge *bridge,
> +					 struct drm_bridge_state *state)
> +{
> +	memset(state, 0, sizeof(*state));
> +	state->bridge = bridge;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_init_bridge_state);

Other objects don't export a state init function helper, but state reset
and state duplicate helpers. Is there a reason to depart from that model
? Same for the copy helper below.

> +
> +/**
> + * drm_atomic_helper_copy_bridge_state() - Copy the content of a bridge state
> + * @bridge: bridge the old and new state are referring to
> + * @old: previous bridge state to copy from
> + * @new: new bridge state to copy to
> + *
> + * Should be used by custom &drm_bridge_funcs.atomic_duplicate() implementation
> + * to copy the previous state into the new object.
> + */
> +void drm_atomic_helper_copy_bridge_state(struct drm_bridge *bridge,
> +					 const struct drm_bridge_state *old,
> +					 struct drm_bridge_state *new)
> +{
> +	*new = *old;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_copy_bridge_state);
> +
> +/**
> + * drm_atomic_helper_duplicate_bridge_state() - Default duplicate state helper
> + * @bridge: bridge containing the state to duplicate
> + *
> + * Default implementation of &drm_bridge_funcs.atomic_duplicate().
> + *
> + * RETURNS:
> + * a valid state object or NULL if the allocation fails.
> + */
> +struct drm_bridge_state *
> +drm_atomic_helper_duplicate_bridge_state(struct drm_bridge *bridge)
> +{
> +	struct drm_bridge_state *old = NULL, *new;
> +
> +	new = kzalloc(sizeof(*new), GFP_KERNEL);
> +	if (!new)
> +		return NULL;
> +
> +	if (bridge->base.state) {
> +		old = drm_priv_to_bridge_state(bridge->base.state);
> +		drm_atomic_helper_copy_bridge_state(bridge, old, new);
> +	} else {
> +		drm_atomic_helper_init_bridge_state(bridge, new);
> +	}
> +
> +	return new;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_duplicate_bridge_state);
> +
> +/**
> + * drm_atomic_helper_destroy_bridge_state() - Default destroy state helper
> + * @bridge: the bridge this state refers to
> + * @state: state object to destroy
> + *
> + * Just a simple kfree() for now.
> + */
> +void drm_atomic_helper_destroy_bridge_state(struct drm_bridge *bridge,
> +					    struct drm_bridge_state *state)
> +{
> +	kfree(state);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_destroy_bridge_state);
> +
>  #ifdef CONFIG_OF
>  /**
>   * of_drm_find_bridge - find the bridge corresponding to the device node in
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 927e1205d7aa..5ee25fd51e80 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -660,6 +660,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
>  	return plane->state;
>  }
>  
> +int __must_check
> +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
> +                               struct drm_encoder *encoder);
>  int __must_check
>  drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
>  				   struct drm_crtc *crtc);
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index f40181274ed7..8ca25d266d0c 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -25,6 +25,7 @@
>  
>  #include <linux/list.h>
>  #include <linux/ctype.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_mode_object.h>
>  #include <drm/drm_modes.h>
>  
> @@ -32,6 +33,23 @@ struct drm_bridge;
>  struct drm_bridge_timings;
>  struct drm_panel;
>  
> +/**
> + * struct drm_bridge_state - Atomic bridge state object
> + * @base: inherit from &drm_private_state
> + * @bridge: the bridge this state refers to
> + */
> +struct drm_bridge_state {
> +	struct drm_private_state base;
> +
> +	struct drm_bridge *bridge;
> +};
> +
> +static inline struct drm_bridge_state *
> +drm_priv_to_bridge_state(struct drm_private_state *priv)
> +{
> +	return container_of(priv, struct drm_bridge_state, base);
> +}
> +
>  /**
>   * struct drm_bridge_funcs - drm_bridge control functions
>   */
> @@ -337,6 +355,30 @@ struct drm_bridge_funcs {
>  	 */
>  	void (*atomic_post_disable)(struct drm_bridge *bridge,
>  				    struct drm_atomic_state *state);
> +
> +	/**
> +	 * @atomic_duplicate_state:
> +	 *
> +	 * Duplicate the current bridge state object.
> +	 *
> +	 * Note that this function can be called when current bridge state is
> +	 * NULL. In this case, implementations should either implement HW
> +	 * readback or initialize the state with sensible default values.

Related to the question above, shouldn't we have a reset state operation
instead ?

> +	 *
> +	 * RETURNS:
> +	 * A valid drm_bridge_state object or NULL if the allocation fails.
> +	 */
> +	struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge);
> +
> +	/**
> +	 * @atomic_duplicate_state:
> +	 *
> +	 * Destroy a bridge state object previously allocated by
> +	 * &drm_bridge_funcs.atomic_duplicate_state() or
> +	 * &drm_bridge_funcs.atomic_get_initial_state().
> +	 */
> +	void (*atomic_destroy_state)(struct drm_bridge *bridge,
> +				     struct drm_bridge_state *state);
>  };
>  
>  /**
> @@ -379,6 +421,8 @@ struct drm_bridge_timings {
>   * struct drm_bridge - central DRM bridge control structure
>   */
>  struct drm_bridge {
> +	/** @base: inherit from &drm_private_object */
> +	struct drm_private_obj base;
>  	/** @dev: DRM device this bridge belongs to */
>  	struct drm_device *dev;
>  	/** @encoder: encoder to which this bridge is connected */
> @@ -403,6 +447,12 @@ struct drm_bridge {
>  	void *driver_private;
>  };
>  
> +static inline struct drm_bridge *
> +drm_priv_to_bridge(struct drm_private_obj *priv)
> +{
> +	return container_of(priv, struct drm_bridge, base);
> +}
> +
>  void drm_bridge_add(struct drm_bridge *bridge);
>  void drm_bridge_remove(struct drm_bridge *bridge);
>  struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> @@ -438,6 +488,55 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
>  void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>  				    struct drm_atomic_state *state);
>  
> +void drm_atomic_helper_init_bridge_state(struct drm_bridge *bridge,
> +					 struct drm_bridge_state *state);
> +void drm_atomic_helper_copy_bridge_state(struct drm_bridge *bridge,
> +					 const struct drm_bridge_state *old,
> +					 struct drm_bridge_state *new);
> +struct drm_bridge_state *
> +drm_atomic_helper_duplicate_bridge_state(struct drm_bridge *bridge);
> +void drm_atomic_helper_destroy_bridge_state(struct drm_bridge *bridge,
> +					    struct drm_bridge_state *state);
> +
> +static inline struct drm_bridge_state *
> +drm_atomic_get_bridge_state(struct drm_atomic_state *state,
> +			    struct drm_bridge *bridge)
> +{
> +	struct drm_private_state *obj_state;
> +
> +	obj_state = drm_atomic_get_private_obj_state(state, &bridge->base);
> +	if (!obj_state)
> +		return NULL;
> +
> +	return drm_priv_to_bridge_state(obj_state);
> +}
> +
> +static inline struct drm_bridge_state *
> +drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
> +				struct drm_bridge *bridge)
> +{
> +	struct drm_private_state *obj_state;
> +
> +	obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base);
> +	if (!obj_state)
> +		return NULL;
> +
> +	return drm_priv_to_bridge_state(obj_state);
> +}
> +
> +static inline struct drm_bridge_state *
> +drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
> +				struct drm_bridge *bridge)
> +{
> +	struct drm_private_state *obj_state;
> +
> +	obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base);
> +	if (!obj_state)
> +		return NULL;
> +
> +	return drm_priv_to_bridge_state(obj_state);
> +}
> +
>  #ifdef CONFIG_DRM_PANEL_BRIDGE
>  struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
>  					u32 connector_type);

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 11/19] drm/bridge: Patch atomic hooks to take a drm_bridge_state
  2019-08-08 15:11 ` [PATCH RFC 11/19] drm/bridge: Patch atomic hooks to take a drm_bridge_state Boris Brezillon
@ 2019-08-22  0:02   ` Laurent Pinchart
  2019-08-22  8:25     ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-22  0:02 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:42PM +0200, Boris Brezillon wrote:
> Instead of a drm_atomic_state. The only driver implementing those hooks
> is patched too.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  .../drm/bridge/analogix/analogix_dp_core.c    | 12 ++--
>  drivers/gpu/drm/drm_bridge.c                  | 57 +++++++++++++++----
>  include/drm/drm_bridge.h                      |  8 +--
>  3 files changed, 57 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index b096a7a75c14..02b9ee0e4f7a 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1290,8 +1290,9 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
>  }
>  
>  static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
> -						 struct drm_atomic_state *state)
> +						 struct drm_bridge_state *bstate)
>  {
> +	struct drm_atomic_state *state = bstate->base.state;
>  	struct analogix_dp_device *dp = bridge->driver_private;
>  	struct drm_crtc *crtc;
>  	struct drm_crtc_state *old_crtc_state;
> @@ -1367,8 +1368,9 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
>  }
>  
>  static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
> -					     struct drm_atomic_state *state)
> +					     struct drm_bridge_state *bstate)
>  {
> +	struct drm_atomic_state *state = bstate->base.state;
>  	struct analogix_dp_device *dp = bridge->driver_private;
>  	struct drm_crtc *crtc;
>  	struct drm_crtc_state *old_crtc_state;
> @@ -1441,8 +1443,9 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
>  }
>  
>  static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
> -					      struct drm_atomic_state *state)
> +					      struct drm_bridge_state *bstate)
>  {
> +	struct drm_atomic_state *state = bstate->base.state;
>  	struct analogix_dp_device *dp = bridge->driver_private;
>  	struct drm_crtc *crtc;
>  	struct drm_crtc_state *new_crtc_state = NULL;
> @@ -1465,8 +1468,9 @@ static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
>  
>  static
>  void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
> -					    struct drm_atomic_state *state)
> +					    struct drm_bridge_state *bstate)
>  {
> +	struct drm_atomic_state *state = bstate->base.state;
>  	struct analogix_dp_device *dp = bridge->driver_private;
>  	struct drm_crtc *crtc;
>  	struct drm_crtc_state *new_crtc_state;
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0280da6be1e6..0528ca941855 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -467,10 +467,18 @@ void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
>  
>  	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
>  				    chain_node) {
> -		if (bridge->funcs->atomic_disable)
> -			bridge->funcs->atomic_disable(bridge, state);
> -		else if (bridge->funcs->disable)
> +		if (bridge->funcs->atomic_disable) {
> +			struct drm_bridge_state *bridge_state;
> +
> +			bridge_state = drm_atomic_get_old_bridge_state(state,
> +								       bridge);
> +			if (WARN_ON(!bridge_state))
> +				return;
> +
> +			bridge->funcs->atomic_disable(bridge, bridge_state);
> +		} else if (bridge->funcs->disable) {
>  			bridge->funcs->disable(bridge);
> +		}
>  	}
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
> @@ -492,10 +500,19 @@ void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,
>  	struct drm_bridge *bridge;
>  
>  	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
> -		if (bridge->funcs->atomic_post_disable)
> -			bridge->funcs->atomic_post_disable(bridge, state);
> -		else if (bridge->funcs->post_disable)
> +		if (bridge->funcs->atomic_post_disable) {
> +			struct drm_bridge_state *bridge_state;
> +
> +			bridge_state = drm_atomic_get_old_bridge_state(state,
> +								       bridge);
> +			if (WARN_ON(!bridge_state))
> +				return;
> +
> +			bridge->funcs->atomic_post_disable(bridge,
> +							   bridge_state);
> +		} else if (bridge->funcs->post_disable) {
>  			bridge->funcs->post_disable(bridge);
> +		}
>  	}
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
> @@ -518,10 +535,18 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
>  
>  	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
>  				    chain_node) {
> -		if (bridge->funcs->atomic_pre_enable)
> -			bridge->funcs->atomic_pre_enable(bridge, state);
> -		else if (bridge->funcs->pre_enable)
> +		if (bridge->funcs->atomic_pre_enable) {
> +			struct drm_bridge_state *bridge_state;
> +
> +			bridge_state = drm_atomic_get_new_bridge_state(state,
> +								       bridge);

Shouldn't you get the old state here ? The new state in commit-related
operations is supposed to be obtained from the object itself, and the
old state is passed to the function. See how the CRTC and encoder
.atomic_enable() are called in drm_atomic_helper_commit_modeset_enables
(drm_atomic_helper.c) for instance.

You should update the documentation of the bridge atomic operations to
makes this explicit. The documentation of the bridge helpers
(drm_atomic_bridge_enable() & co.) is also misleading, they get passed
the old state, while the documentation states "atomic state being
committed". I think you should rename all those state parameters to
old_state to make this clearer.

Last but not least, the implementation in the analogix bridge driver
seems to expect the new state, so I think it's buggy.

> +			if (WARN_ON(!bridge_state))
> +				return;
> +
> +			bridge->funcs->atomic_pre_enable(bridge, bridge_state);
> +		} else if (bridge->funcs->pre_enable) {
>  			bridge->funcs->pre_enable(bridge);
> +		}
>  	}
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
> @@ -542,10 +567,18 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>  	struct drm_bridge *bridge;
>  
>  	list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
> -		if (bridge->funcs->atomic_enable)
> -			bridge->funcs->atomic_enable(bridge, state);
> -		else if (bridge->funcs->enable)
> +		if (bridge->funcs->atomic_enable) {
> +			struct drm_bridge_state *bridge_state;
> +
> +			bridge_state = drm_atomic_get_new_bridge_state(state,
> +								       bridge);
> +			if (WARN_ON(!bridge_state))
> +				return;
> +
> +			bridge->funcs->atomic_enable(bridge, bridge_state);
> +		} else if (bridge->funcs->enable) {
>  			bridge->funcs->enable(bridge);
> +		}
>  	}
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 8ca25d266d0c..9383b4e4b853 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -280,7 +280,7 @@ struct drm_bridge_funcs {
>  	 * The @atomic_pre_enable callback is optional.
>  	 */
>  	void (*atomic_pre_enable)(struct drm_bridge *bridge,
> -				  struct drm_atomic_state *state);
> +				  struct drm_bridge_state *state);
>  
>  	/**
>  	 * @atomic_enable:
> @@ -305,7 +305,7 @@ struct drm_bridge_funcs {
>  	 * The enable callback is optional.
>  	 */
>  	void (*atomic_enable)(struct drm_bridge *bridge,
> -			      struct drm_atomic_state *state);
> +			      struct drm_bridge_state *state);
>  	/**
>  	 * @atomic_disable:
>  	 *
> @@ -328,7 +328,7 @@ struct drm_bridge_funcs {
>  	 * The disable callback is optional.
>  	 */
>  	void (*atomic_disable)(struct drm_bridge *bridge,
> -			       struct drm_atomic_state *state);
> +			       struct drm_bridge_state *state);
>  
>  	/**
>  	 * @atomic_post_disable:
> @@ -354,7 +354,7 @@ struct drm_bridge_funcs {
>  	 * The post_disable callback is optional.
>  	 */
>  	void (*atomic_post_disable)(struct drm_bridge *bridge,
> -				    struct drm_atomic_state *state);
> +				    struct drm_bridge_state *state);
>  
>  	/**
>  	 * @atomic_duplicate_state:

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 12/19] drm/bridge: Add an ->atomic_check() hook
  2019-08-08 15:11 ` [PATCH RFC 12/19] drm/bridge: Add an ->atomic_check() hook Boris Brezillon
@ 2019-08-22  0:12   ` Laurent Pinchart
  2019-08-22  7:58     ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-22  0:12 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:43PM +0200, Boris Brezillon wrote:
> So that bridge drivers have a way to check/reject an atomic operation.
> The drm_atomic_bridge_chain_check() (which is just a wrapper around
> the ->atomic_check() hook) is called in place of
> drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented,
> the core falls back to ->mode_fixup(), so the behavior should stay
> the same for existing bridge drivers).
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 11 +++---
>  drivers/gpu/drm/drm_bridge.c        | 59 +++++++++++++++++++++++++++++
>  include/drm/drm_bridge.h            | 23 +++++++++++
>  3 files changed, 87 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index e76ec9648b6f..3fadde38ead7 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -445,12 +445,11 @@ mode_fixup(struct drm_atomic_state *state)
>  		encoder = new_conn_state->best_encoder;
>  		funcs = encoder->helper_private;
>  
> -		ret = drm_bridge_chain_mode_fixup(encoder,
> -					&new_crtc_state->mode,
> -					&new_crtc_state->adjusted_mode);
> -		if (!ret) {
> -			DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
> -			return -EINVAL;
> +		ret = drm_atomic_bridge_chain_check(encoder, new_crtc_state,
> +						    new_conn_state);
> +		if (ret) {
> +			DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
> +			return ret;
>  		}
>  
>  		if (funcs && funcs->atomic_check) {
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0528ca941855..dcad661daa74 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -583,6 +583,65 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
>  
> +static int drm_atomic_bridge_check(struct drm_bridge *bridge,
> +				   struct drm_crtc_state *crtc_state,
> +				   struct drm_connector_state *conn_state)
> +{
> +	if (bridge->funcs->atomic_check) {
> +		struct drm_bridge_state *bridge_state;
> +		int ret;
> +
> +		bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
> +							       bridge);
> +		if (WARN_ON(!bridge_state))
> +			return -EINVAL;
> +
> +		ret = bridge->funcs->atomic_check(bridge, bridge_state,
> +						  crtc_state, conn_state);
> +		if (ret)
> +			return ret;
> +	} else if (bridge->funcs->mode_fixup) {
> +		if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode,
> +					       &crtc_state->adjusted_mode))
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
> + * @encoder: encoder object
> + * @crtc_state: new CRTC state
> + * @conn_state: new connector state
> + *
> + * Calls &drm_bridge_funcs.atomic_check() (falls back on
> + * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
> + * starting from the last bridge to the first. These are called before calling
> + * &drm_encoder_helper_funcs.atomic_check()
> + *
> + * RETURNS:
> + * 0 on success, a negative error code on failure
> + */
> +int drm_atomic_bridge_chain_check(struct drm_encoder *encoder,
> +				  struct drm_crtc_state *crtc_state,
> +				  struct drm_connector_state *conn_state)
> +{
> +	struct drm_bridge *bridge;
> +
> +	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
> +				    chain_node) {
> +		int ret;
> +
> +		ret = drm_atomic_bridge_check(bridge, crtc_state, conn_state);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_chain_check);
> +
>  /**
>   * drm_atomic_helper_init_bridge_state() - Initializes a bridge state
>   * @bridge this state is referring to
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 9383b4e4b853..5d8fe3709bde 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -379,6 +379,26 @@ struct drm_bridge_funcs {
>  	 */
>  	void (*atomic_destroy_state)(struct drm_bridge *bridge,
>  				     struct drm_bridge_state *state);
> +
> +	/**
> +	 * @atomic_check:
> +	 *
> +	 * This method is responsible for checking bridge state correctness.
> +	 * It can also check the state of the surrounding components in chain
> +	 * to make sure the whole pipeline can work properly.

As this is meant to replace .mode_fixup() you should document that here
and in the .mode_fixup() operation.

There's also the additional question of what parameters can be modified.
Is a bridge .atomic_check() allowed to modify the CRTC or connector
state ? Of so, what are the restrictions on how those can be modified ?
For instance .mode_fixup() can change the pixel clock but isn't allowed
to modify the h/v active values. Those restrictions were not clearly
documented for .mode_fixup() and have led to grey areas. I don't want to
repeat the same mistake for bridges, we need to be very explicit here.

In the list of open questions, what if a bridge changes the pixel clock
to a value it supports (as .mode_fixup() does), and then the previous
bridge in the chain (the next one in traversal order for the
drm_atomic_bridge_chain_check() function) also changes the pixel clock,
to a value that the current bridge doesn't support ? I think we really
need to think about the semantic of this operation.

As the goal of your series is to implement configuration of bus formats
between bridges, shouldn't a bridge .atomic_check() also receive the
state of the next bridge in the chain ?

> +	 *
> +	 * &drm_bridge_funcs.atomic_check() hooks are called in reverse
> +	 * order (from the last to the first bridge).
> +	 *
> +	 * This method is optional.
> +	 *
> +	 * RETURNS:
> +	 * zero if the check passed, a negative error code otherwise.
> +	 */
> +	int (*atomic_check)(struct drm_bridge *bridge,
> +			    struct drm_bridge_state *bridge_state,
> +			    struct drm_crtc_state *crtc_state,
> +			    struct drm_connector_state *conn_state);
>  };
>  
>  /**
> @@ -479,6 +499,9 @@ void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
>  void drm_bridge_chain_pre_enable(struct drm_encoder *encoder);
>  void drm_bridge_chain_enable(struct drm_encoder *encoder);
>  
> +int drm_atomic_bridge_chain_check(struct drm_encoder *encoder,
> +				  struct drm_crtc_state *crtc_state,
> +				  struct drm_connector_state *conn_state);
>  void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
>  				     struct drm_atomic_state *state);
>  void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 13/19] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper
  2019-08-08 15:11 ` [PATCH RFC 13/19] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper Boris Brezillon
@ 2019-08-22  0:17   ` Laurent Pinchart
  2019-08-22  8:04     ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-22  0:17 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:44PM +0200, Boris Brezillon wrote:
> Will be useful for bridge drivers that want to do bus format
> negotiation with their neighbours.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/drm_bridge.c | 19 +++++++++++++++++++
>  include/drm/drm_bridge.h     |  2 ++
>  2 files changed, 21 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index dcad661daa74..9efb27087e70 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -271,6 +271,25 @@ drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge)
>  }
>  EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
>  
> +/**
> + * drm_bridge_chain_get_prev_bridge() - Get the previous bridge in the chain
> + * @bridge: bridge object
> + *
> + * RETURNS:
> + * the previous bridge in the chain, or NULL if there's @bridge is the
> + * last.

Did you mean "if the @bridge is the first" ?

> + */
> +struct drm_bridge *
> +drm_bridge_chain_get_prev_bridge(struct drm_bridge *bridge)
> +{
> +	if (!bridge || !bridge->encoder ||

Do we really need to protect against !bridge and !bridge->encoder, can
that happen ? Especially !bridge, are there use cases for potentially
calling this function (and the other list traversal helpers in your
previous patches) with a NULL bridge ?

> +	    list_is_first(&bridge->encoder->bridge_chain, &bridge->chain_node))
> +                return NULL;
> +
> +	return list_prev_entry(bridge, chain_node);
> +}
> +EXPORT_SYMBOL(drm_bridge_chain_get_prev_bridge);
> +
>  /**
>   * DOC: bridge callbacks
>   *
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 5d8fe3709bde..2f69adb7b0f3 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -485,6 +485,8 @@ struct drm_bridge *
>  drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder);
>  struct drm_bridge *
>  drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge);
> +struct drm_bridge *
> +drm_bridge_chain_get_prev_bridge(struct drm_bridge *bridge);
>  bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
>  				 const struct drm_display_mode *mode,
>  				 struct drm_display_mode *adjusted_mode);

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 17/19] drm/bridge: lvds-encoder: Implement bus format negotiation for sn75lvds83
  2019-08-08 15:11 ` [PATCH RFC 17/19] drm/bridge: lvds-encoder: Implement bus format negotiation for sn75lvds83 Boris Brezillon
@ 2019-08-22  0:32   ` Laurent Pinchart
  2019-08-22  8:12     ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-22  0:32 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:48PM +0200, Boris Brezillon wrote:
> The SN75LVDS83 bridge support several input formats except the input
> format is directly related to the expected output format. Let's express
> that constraint by setting the bridge_state->output_bus_cfg.fmt field
> to the appropriate value.
> 
> The previous element in the chain might be able to use this information
> to pick the appropriate output bus format.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>

This driver is supposed to only support LVDS encoders that require no
special configuration, and thus not contain device-specific code. I'm
not sure I like departing from this :-S

Would there be a way to make this more generic ? Do you think the code
below could be generalized, or is it really device-specific ?

> ---
>  drivers/gpu/drm/bridge/lvds-encoder.c | 48 +++++++++++++++++++++++++++
>  1 file changed, 48 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
> index da7013c5faf1..8d399d1828b0 100644
> --- a/drivers/gpu/drm/bridge/lvds-encoder.c
> +++ b/drivers/gpu/drm/bridge/lvds-encoder.c
> @@ -159,9 +159,57 @@ static int lvds_encoder_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static int sn75lvds83_atomic_check(struct drm_bridge *bridge,
> +				   struct drm_bridge_state *bridge_state,
> +				   struct drm_crtc_state *crtc_state,
> +				   struct drm_connector_state *conn_state)
> +{
> +	int ret;
> +
> +	ret = drm_atomic_bridge_choose_output_bus_cfg(bridge_state, crtc_state,
> +						      conn_state);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * The output bus format has a direct impact on the expected input bus
> +	 * format.
> +	 */
> +	switch (bridge_state->output_bus_cfg.fmt) {
> +	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
> +	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
> +		/*
> +		 * JEIDA and SPWG variants theoretically require different pin
> +		 * mapping, but MEDIA_BUS_FMT_ definitions do not allow
> +		 * fined-grained pin placement definition, and this is
> +		 * something we expect to be taken care of at board design
> +		 * time, so let's ignore this for now.
> +		 * If it becomes a problem, we can always add a way to override
> +		 * the bus format with a FW property.
> +		 */
> +		bridge_state->input_bus_cfg.fmt = MEDIA_BUS_FMT_RGB888_1X24;
> +		break;
> +	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
> +		bridge_state->input_bus_cfg.fmt = MEDIA_BUS_FMT_RGB666_1X18;
> +		break;
> +	default:
> +		bridge_state->input_bus_cfg.fmt = 0;
> +		break;
> +	}

These seems a bit fragile. The SN75LVDS83 has a 28-bit input data bus,
and maps those bits to 3x8 RGB data + 1x4 control signals. It serialises
the data and outputs them on 4 LVDS pairs. When a panel uses
MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA or MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, the
4 LVDS pairs are used, and MEDIA_BUS_FMT_RGB888_1X24 is required. When
outputting MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, the fourth LVDS pair is
ignored, but the 3x8 RGB input bus can still receive
MEDIA_BUS_FMT_RGB888_1X24, the 2 LSBs of each component will just be
discarded. The source can thus ignore those 3x2 LSBs, but it still has
to map the 3x6 MSBs to the high order bits of the 3x8 signals.
*However*, if the hardware designs wires the 3x6 MSBs of the SN75LVDS83
to the 3x6 LSBs of the source, then the source will have to produce
MEDIA_BUS_FMT_RGB666_1X18. Hardcoding the mapping as done here thus
seems to be system-specific. I think you need to check how signals are
connected (through DT properties, bus-width and data-shift come to
mind).

> +
> +	/* Propagate the bus_flags. */
> +	bridge_state->input_bus_cfg.flags = bridge_state->output_bus_cfg.flags;
> +	return 0;
> +}
> +
> +static const struct lvds_encoder_ops sn75lvds83_ops = {
> +	.atomic_check = sn75lvds83_atomic_check,
> +};
> +
>  static const struct of_device_id lvds_encoder_match[] = {
>  	{ .compatible = "lvds-encoder" },
>  	{ .compatible = "thine,thc63lvdm83d" },
> +	{ .compatible = "ti,sn75lvds83", .data = &sn75lvds83_ops },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, lvds_encoder_match);

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 18/19] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel
  2019-08-08 15:11 ` [PATCH RFC 18/19] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel Boris Brezillon
@ 2019-08-22  0:36   ` Laurent Pinchart
  2019-08-22  8:15     ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-22  0:36 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:49PM +0200, Boris Brezillon wrote:
> Add a new entry for the Toshiba LTA089AC29000 panel.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  .../display/panel/toshiba,lt089ac29000.txt    |  5 ++-
>  drivers/gpu/drm/panel/panel-simple.c          | 36 +++++++++++++++++++
>  2 files changed, 40 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
> index 89826116628c..26ebfa098966 100644
> --- a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
> +++ b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
> @@ -1,7 +1,10 @@
>  Toshiba 8.9" WXGA (1280x768) TFT LCD panel
>  
>  Required properties:
> -- compatible: should be "toshiba,lt089ac29000"
> +- compatible: should be one of the following
> +	      "toshiba,lt089ac29000"
> +	      "toshiba,lta089ac29000"
> +
>  - power-supply: as specified in the base binding
>  
>  This binding is compatible with the simple-panel binding, which is specified

While at it, any change to convert this binding to .yaml ? For panels
it's fairly easy.

> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
> index bff7578f84dd..4c1deed44ce2 100644
> --- a/drivers/gpu/drm/panel/panel-simple.c
> +++ b/drivers/gpu/drm/panel/panel-simple.c
> @@ -2857,6 +2857,39 @@ static const struct panel_desc toshiba_lt089ac29000 = {
>  	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
>  };
>  
> +static const struct drm_display_mode toshiba_lta089ac29000_mode = {
> +	.clock = 79500,
> +	.hdisplay = 1280,
> +	.hsync_start = 1280 + 192,
> +	.hsync_end = 1280 + 192 + 128,
> +	.htotal = 1280 + 192 + 128 + 64,
> +	.vdisplay = 768,
> +	.vsync_start = 768 + 20,
> +	.vsync_end = 768 + 20 + 7,
> +	.vtotal = 768 + 20 + 7 + 3,
> +	.vrefresh = 60,
> +};
> +
> +static const struct panel_desc toshiba_lta089ac29000 = {
> +	.modes = &toshiba_lta089ac29000_mode,
> +	.num_modes = 1,
> +	.size = {
> +		.width = 194,
> +		.height = 116,
> +	},
> +	/*
> +	 * FIXME:
> +	 * The panel supports 2 bus formats: jeida-24 and jeida-18. The
> +	 * mode is selected through the 8b6b_SEL pin. If anyone ever needs
> +	 * support for jeida-18 we should probably parse the 'data-mapping'
> +	 * property.
> +	 * In the unlikely event where 8b6b_SEL is connected to a GPIO, we'd
> +	 * need a new infra to allow bus format negotiation at the panel level.

I would also leave the GPIO case for later, but it would be nice to already
implement reading the data-mapping property, in order to validate the DT
(you should add the data-mapping property to the bindings by the way).
Bonus points if it can be done in a way that is also usable by other
panels.

> +	 */
> +	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
> +	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
> +};
> +
>  static const struct drm_display_mode tpk_f07a_0102_mode = {
>  	.clock = 33260,
>  	.hdisplay = 800,
> @@ -3305,6 +3338,9 @@ static const struct of_device_id platform_of_match[] = {
>  	}, {
>  		.compatible = "toshiba,lt089ac29000",
>  		.data = &toshiba_lt089ac29000,
> +	}, {
> +		.compatible = "toshiba,lta089ac29000",
> +		.data = &toshiba_lta089ac29000,
>  	}, {
>  		.compatible = "tpk,f07a-0102",
>  		.data = &tpk_f07a_0102,

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-08 15:11 ` [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation Boris Brezillon
  2019-08-14  7:51   ` Neil Armstrong
@ 2019-08-22  0:55   ` Laurent Pinchart
  2019-08-22  7:48     ` Boris Brezillon
  1 sibling, 1 reply; 58+ messages in thread
From: Laurent Pinchart @ 2019-08-22  0:55 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

Thank you for the patch.

On Thu, Aug 08, 2019 at 05:11:45PM +0200, Boris Brezillon wrote:
> This takes the form of various helpers, plus the addition of 2 new
> structs:
> * drm_bus_caps: describe the bus capabilities of a bridge/encoder. For
>   bridges we have one for the input port and one for the output port.
>   Encoders just have one output port.
> * drm_bus_cfg: added to the drm_bridge_state. It's supposed to store
>   bus configuration information. For now we just have format and flags
>   but more fields might be added in the future. Again, each
>   drm_bridge_state contains 2 drm_bus_cfg elements: one for the output
>   port and one for the input port
> 
> Helpers can be used from bridge drivers' ->atomic_check() implementation
> to negotiate the bus format to use. Negotiation happens in reserve order,

s/reserve/reverse/

> starting from the last element of the bridge chain (the one directly
> connected to the display) to the first element of the chain (the one
> connected to the encoder).
> 
> Negotiation usually takes place in 2 steps:
> * make sure the input end of the next element in the chain picked a
>   format that's supported by the output end of our bridge. That's done
>   with drm_atomic_bridge_choose_output_bus_cfg().
> * choose a format for the input end of our bridge based on what's
>   supported by the previous bridge in the chain. This is achieved by
>   calling drm_atomic_bridge_choose_input_bus_cfg()
> 
> Note that those helpers are a bit lax when it comes to unitialized
> bus format validation. That's intentional. If we don't do that we'll
> basically break things if we start adding support for bus format
> negotiation to some elements of the pipeline leaving others on the
> side, and that's likely to happen for all external bridges since we
> can't necessarily tell where they are used.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
>  drivers/gpu/drm/drm_bridge.c | 187 +++++++++++++++++++++++++++++++++++
>  include/drm/drm_bridge.h     |  46 +++++++++
>  include/drm/drm_encoder.h    |   6 ++
>  3 files changed, 239 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 9efb27087e70..ef072df42422 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -602,6 +602,193 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>  }
>  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
>  
> +int drm_find_best_bus_format(const struct drm_bus_caps *a,
> +			     const struct drm_bus_caps *b,
> +			     const struct drm_display_mode *mode,
> +			     u32 *selected_bus_fmt)
> +{
> +	unsigned int i, j;
> +
> +	/*
> +	 * Some drm_bridge/drm_encoder don't care about the input/output bus
> +	 * format, let's set the format to zero in that case (this is only
> +	 * valid if both side of the link don't care).
> +	 */
> +	if (!a->num_supported_fmts && !b->num_supported_fmts) {
> +		*selected_bus_fmt = 0;
> +		return 0;
> +	} else if (b->num_supported_fmts > 1 && b->supported_fmts) {
> +		*selected_bus_fmt = b->supported_fmts[0];
> +		return 0;
> +	} else if (a->num_supported_fmts > 1 && a->supported_fmts) {
> +		*selected_bus_fmt = a->supported_fmts[0];
> +		return 0;
> +	} else if (!a->num_supported_fmts || !a->supported_fmts ||
> +		   !b->num_supported_fmts || !b->supported_fmts) {
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * TODO:
> +	 * Dummy algo picking the first match. We probably want something
> +	 * smarter where the narrowest format (in term of bus width) that
> +	 * does not incur data loss is picked, and if all possible formats
> +	 * are lossy, pick the one that's less lossy among all the choices
> +	 * we have. In order to do that we'd need to convert MEDIA_BUS_FMT_
> +	 * modes into something like drm_format_info.
> +	 */
> +	for (i = 0; i < a->num_supported_fmts; i++) {
> +		for (j = 0; j < b->num_supported_fmts; j++) {
> +			if (a->supported_fmts[i] == b->supported_fmts[j]) {
> +				*selected_bus_fmt = a->supported_fmts[i];
> +				return 0;
> +			}
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL(drm_find_best_bus_format);
> +
> +/**
> + * drm_atomic_bridge_choose_input_bus_cfg() - Choose bus config for the input
> + *					      end
> + * @bridge_state: bridge state
> + * @crtc_state: CRTC state
> + * @conn_state: connector state
> + *
> + * Choose a bus format for the input side of a bridge based on what the
> + * previous bridge in the chain and this bridge support. Can be called from
> + * bridge drivers' &drm_bridge_funcs.atomic_check() implementation.
> + *
> + * RETURNS:
> + * 0 if a matching format was found, a negative error code otherwise
> + */
> +int
> +drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
> +				       struct drm_crtc_state *crtc_state,
> +				       struct drm_connector_state *conn_state)
> +{
> +	struct drm_bridge *self = bridge_state->bridge;
> +	struct drm_bus_caps *prev_output_bus_caps;
> +	struct drm_bridge *prev;
> +	int ret;
> +
> +	prev = drm_bridge_chain_get_prev_bridge(self);
> +	if (!prev)
> +		prev_output_bus_caps = &self->encoder->output_bus_caps;
> +	else
> +		prev_output_bus_caps = &prev->output_bus_caps;
> +
> +	ret = drm_find_best_bus_format(prev_output_bus_caps,
> +				       &self->input_bus_caps, &crtc_state->mode,
> +				       &bridge_state->input_bus_cfg.fmt);
> +	if (ret)
> +		return ret;

I think most bridges that support multiple input and output formats will
not necessarily be able to transcode, meaning that for a particular
output format a particular corresponding input format will need to be
picked (or possibly one of a subset of input formats). I'm thus not sure
how useful this helper will be in practice.

I also fear that this negotiation mechanism is too simple and will lock
is with support for very simple systems only :-S Let's assume a system
with a display device (D), two bridges (B0 and B1) and a connector (C).
Let's further assume that the bus format required by the connector is
fixed. With this patch series, B1 will pick an output format identical
to the format on the connector, and will then pick an input format among
the ones supported by both B0 and B1. Let's assume there are multiple
options, Fa and Fb, and drm_find_best_bus_format() will pick one of
them, say Fa. Then B0 will configure its output with that format, and
will proceed with finding an input format supported by D. It could be
that the output format Fa for B0 requires an input format that is not
supported by D, while Fb would have produced a working pipeline.

I don't think this example is really far-fetched, and while we don't
need to support it immediately, we need an API that makes it possible to
support it, as changing the API later would require reworking all the
drivers that use it.

> +
> +	/*
> +	 * TODO:
> +	 * Should we fill/check the ->flag field too?
> +	 */
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_choose_input_bus_cfg);
> +
> +/**
> + * drm_atomic_bridge_choose_output_bus_cfg() - Choose bus config for the output
> + *					       end
> + * @bridge_state: bridge state
> + * @crtc_state: CRTC state
> + * @conn_state: connector state
> + *
> + * Choose a bus format for the output side of a bridge based on what the next
> + * bridge in the chain and this bridge support. Can be called from bridge
> + * drivers' &drm_bridge_funcs.atomic_check() implementation.
> + *
> + * RETURNS:
> + * 0 if a matching format was found, a negative error code otherwise
> + */
> +int
> +drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state)
> +{
> +	struct drm_atomic_state *state = crtc_state->state;
> +	struct drm_bridge *self = bridge_state->bridge;
> +	struct drm_bridge_state *next_bridge_state;
> +	struct drm_bridge *next;
> +	u32 fmt;
> +
> +	next = drm_bridge_chain_get_next_bridge(self);
> +	if (!next) {
> +		struct drm_connector *conn = conn_state->connector;
> +		struct drm_display_info *di = &conn->display_info;
> +
> +		/*
> +		 * FIXME:
> +		 * We currently pick the first supported format
> +		 * unconditionally. It seems to fit all current use cases but
> +		 * might be too limited for panels/displays that can configure
> +		 * the bus format dynamically.
> +		 */
> +		if (di->num_bus_formats && di->bus_formats)
> +			bridge_state->output_bus_cfg.fmt = di->bus_formats[0];
> +		else
> +			bridge_state->output_bus_cfg.fmt = 0;

What is the bridge driver supposed to do in this case ?

> +
> +		bridge_state->output_bus_cfg.flags = di->bus_flags;
> +		return 0;
> +	}
> +
> +	/*
> +	 * We expect output_bus_caps to contain at least one format. Note
> +	 * that don't care about bus format negotiation can simply not
> +	 * call this helper.

I'm not sure to parse the second sentence correctly.

> +	 */
> +	if (!self->output_bus_caps.num_supported_fmts ||!

Extra ! at the end of the line ?

> +	    !self->output_bus_caps.supported_fmts)
> +		return -EINVAL;
> +
> +	next_bridge_state = drm_atomic_get_new_bridge_state(state, next);
> +
> +	/*
> +	 * The next bridge is expected to have called
> +	 * &drm_atomic_bridge_choose_input_bus_cfg() as part of its
> +	 * &drm_bridge_funcs.atomic_check() implementation, but this hook is
> +	 * optional, and even if it's implemented, calling
> +	 * &drm_atomic_bridge_choose_input_bus_cfg() is not mandated.
> +	 * If fmt is zero, that means the next element in the chain doesn't
> +	 * care about bus format negotiation (probably because there's only
> +	 * one possible setting). In that case, we still have to select one
> +	 * bus format for the output port of our bridge, and this is only
> +	 * possible if the bridge supports only one format.

Theoritically we could also just pick the first one (or actually any of
the supported formats), couldn't we ?


> +	 */
> +	fmt = next_bridge_state->input_bus_cfg.fmt;
> +	if (fmt) {
> +		unsigned int i;
> +
> +		for (i = 0; i < self->output_bus_caps.num_supported_fmts; i++) {
> +			if (self->output_bus_caps.supported_fmts[i] == fmt)
> +				break;
> +		}
> +
> +		if (i == self->output_bus_caps.num_supported_fmts)
> +			return -ENOTSUPP;
> +	} else if (self->output_bus_caps.num_supported_fmts == 1) {
> +		fmt = self->output_bus_caps.supported_fmts[0];
> +	} else {
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * TODO:
> +	 * Should we fill/check the ->flag field too?
> +	 */
> +	bridge_state->output_bus_cfg.fmt = fmt;
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_choose_output_bus_cfg);
> +
>  static int drm_atomic_bridge_check(struct drm_bridge *bridge,
>  				   struct drm_crtc_state *crtc_state,
>  				   struct drm_connector_state *conn_state)
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 2f69adb7b0f3..c578800a05e0 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -33,15 +33,45 @@ struct drm_bridge;
>  struct drm_bridge_timings;
>  struct drm_panel;
>  
> +/**
> + * struct drm_bus_cfg - bus configuration
> + * @fmt: format used on this bus
> + * @flags: DRM_BUS_ flags used on this bus
> + *
> + * Encodes the bus format and bus flags used by one end of the bridge or
> + * by the encoder output.
> + */
> +struct drm_bus_cfg {
> +	u32 fmt;
> +	u32 flags;
> +};
> +
> +/**
> + * struct drm_bus_caps - bus capabilities
> + * @supported_fmts: array of MEDIA_BUS_FMT_ formats
> + * @num_supported_fmts: size of the supported_fmts array
> + *
> + * Used by the core to negotiate the bus format at runtime.
> + */
> +struct drm_bus_caps {
> +	const u32 *supported_fmts;
> +	unsigned int num_supported_fmts;
> +};
> +
>  /**
>   * struct drm_bridge_state - Atomic bridge state object
>   * @base: inherit from &drm_private_state
>   * @bridge: the bridge this state refers to
> + * @input_bus_info: input bus information
> + * @output_bus_info: output bus information

I would make this an array, to prepare for bridges that will have more
than one input or one output.

>   */
>  struct drm_bridge_state {
>  	struct drm_private_state base;
>  
>  	struct drm_bridge *bridge;
> +
> +	struct drm_bus_cfg input_bus_cfg;
> +	struct drm_bus_cfg output_bus_cfg;
>  };
>  
>  static inline struct drm_bridge_state *
> @@ -465,6 +495,9 @@ struct drm_bridge {
>  	const struct drm_bridge_funcs *funcs;
>  	/** @driver_private: pointer to the bridge driver's internal context */
>  	void *driver_private;
> +
> +	struct drm_bus_caps input_bus_caps;
> +	struct drm_bus_caps output_bus_caps;
>  };
>  
>  static inline struct drm_bridge *
> @@ -479,6 +512,14 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
>  int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
>  		      struct drm_bridge *previous);
>  
> +int
> +drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
> +				       struct drm_crtc_state *crtc_state,
> +				       struct drm_connector_state *conn_state);
> +int
> +drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state);
>  struct drm_bridge *
>  drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder);
>  struct drm_bridge *
> @@ -562,6 +603,11 @@ drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
>  	return drm_priv_to_bridge_state(obj_state);
>  }
>  
> +int drm_find_best_bus_format(const struct drm_bus_caps *a,
> +			     const struct drm_bus_caps *b,
> +			     const struct drm_display_mode *mode,
> +			     u32 *selected_bus_fmt);
> +
>  #ifdef CONFIG_DRM_PANEL_BRIDGE
>  struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
>  					u32 connector_type);
> diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
> index 0899f7f34e3a..e891921b3aed 100644
> --- a/include/drm/drm_encoder.h
> +++ b/include/drm/drm_encoder.h
> @@ -25,6 +25,7 @@
>  
>  #include <linux/list.h>
>  #include <linux/ctype.h>
> +#include <drm/drm_bridge.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_mode.h>
>  #include <drm/drm_mode_object.h>
> @@ -184,6 +185,11 @@ struct drm_encoder {
>  	 * functions as part of its encoder enable/disable handling.
>  	 */
>  	uint32_t custom_bridge_enable_disable_seq : 1;
> +
> +	/**
> +	 * @output_bus_caps: Supported output bus caps
> +	 */
> +	struct drm_bus_caps output_bus_caps;
>  };
>  
>  #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
> 

-- 
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] 58+ messages in thread

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-22  0:55   ` Laurent Pinchart
@ 2019-08-22  7:48     ` Boris Brezillon
  2019-08-22  9:29       ` Neil Armstrong
  0 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22  7:48 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Thu, 22 Aug 2019 03:55:56 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:45PM +0200, Boris Brezillon wrote:
> > This takes the form of various helpers, plus the addition of 2 new
> > structs:
> > * drm_bus_caps: describe the bus capabilities of a bridge/encoder. For
> >   bridges we have one for the input port and one for the output port.
> >   Encoders just have one output port.
> > * drm_bus_cfg: added to the drm_bridge_state. It's supposed to store
> >   bus configuration information. For now we just have format and flags
> >   but more fields might be added in the future. Again, each
> >   drm_bridge_state contains 2 drm_bus_cfg elements: one for the output
> >   port and one for the input port
> > 
> > Helpers can be used from bridge drivers' ->atomic_check() implementation
> > to negotiate the bus format to use. Negotiation happens in reserve order,  
> 
> s/reserve/reverse/
> 
> > starting from the last element of the bridge chain (the one directly
> > connected to the display) to the first element of the chain (the one
> > connected to the encoder).
> > 
> > Negotiation usually takes place in 2 steps:
> > * make sure the input end of the next element in the chain picked a
> >   format that's supported by the output end of our bridge. That's done
> >   with drm_atomic_bridge_choose_output_bus_cfg().
> > * choose a format for the input end of our bridge based on what's
> >   supported by the previous bridge in the chain. This is achieved by
> >   calling drm_atomic_bridge_choose_input_bus_cfg()
> > 
> > Note that those helpers are a bit lax when it comes to unitialized
> > bus format validation. That's intentional. If we don't do that we'll
> > basically break things if we start adding support for bus format
> > negotiation to some elements of the pipeline leaving others on the
> > side, and that's likely to happen for all external bridges since we
> > can't necessarily tell where they are used.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > ---
> >  drivers/gpu/drm/drm_bridge.c | 187 +++++++++++++++++++++++++++++++++++
> >  include/drm/drm_bridge.h     |  46 +++++++++
> >  include/drm/drm_encoder.h    |   6 ++
> >  3 files changed, 239 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 9efb27087e70..ef072df42422 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -602,6 +602,193 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
> >  }
> >  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
> >  
> > +int drm_find_best_bus_format(const struct drm_bus_caps *a,
> > +			     const struct drm_bus_caps *b,
> > +			     const struct drm_display_mode *mode,
> > +			     u32 *selected_bus_fmt)
> > +{
> > +	unsigned int i, j;
> > +
> > +	/*
> > +	 * Some drm_bridge/drm_encoder don't care about the input/output bus
> > +	 * format, let's set the format to zero in that case (this is only
> > +	 * valid if both side of the link don't care).
> > +	 */
> > +	if (!a->num_supported_fmts && !b->num_supported_fmts) {
> > +		*selected_bus_fmt = 0;
> > +		return 0;
> > +	} else if (b->num_supported_fmts > 1 && b->supported_fmts) {
> > +		*selected_bus_fmt = b->supported_fmts[0];
> > +		return 0;
> > +	} else if (a->num_supported_fmts > 1 && a->supported_fmts) {
> > +		*selected_bus_fmt = a->supported_fmts[0];
> > +		return 0;
> > +	} else if (!a->num_supported_fmts || !a->supported_fmts ||
> > +		   !b->num_supported_fmts || !b->supported_fmts) {
> > +		return -EINVAL;
> > +	}
> > +
> > +	/*
> > +	 * TODO:
> > +	 * Dummy algo picking the first match. We probably want something
> > +	 * smarter where the narrowest format (in term of bus width) that
> > +	 * does not incur data loss is picked, and if all possible formats
> > +	 * are lossy, pick the one that's less lossy among all the choices
> > +	 * we have. In order to do that we'd need to convert MEDIA_BUS_FMT_
> > +	 * modes into something like drm_format_info.
> > +	 */
> > +	for (i = 0; i < a->num_supported_fmts; i++) {
> > +		for (j = 0; j < b->num_supported_fmts; j++) {
> > +			if (a->supported_fmts[i] == b->supported_fmts[j]) {
> > +				*selected_bus_fmt = a->supported_fmts[i];
> > +				return 0;
> > +			}
> > +		}
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +EXPORT_SYMBOL(drm_find_best_bus_format);
> > +
> > +/**
> > + * drm_atomic_bridge_choose_input_bus_cfg() - Choose bus config for the input
> > + *					      end
> > + * @bridge_state: bridge state
> > + * @crtc_state: CRTC state
> > + * @conn_state: connector state
> > + *
> > + * Choose a bus format for the input side of a bridge based on what the
> > + * previous bridge in the chain and this bridge support. Can be called from
> > + * bridge drivers' &drm_bridge_funcs.atomic_check() implementation.
> > + *
> > + * RETURNS:
> > + * 0 if a matching format was found, a negative error code otherwise
> > + */
> > +int
> > +drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
> > +				       struct drm_crtc_state *crtc_state,
> > +				       struct drm_connector_state *conn_state)
> > +{
> > +	struct drm_bridge *self = bridge_state->bridge;
> > +	struct drm_bus_caps *prev_output_bus_caps;
> > +	struct drm_bridge *prev;
> > +	int ret;
> > +
> > +	prev = drm_bridge_chain_get_prev_bridge(self);
> > +	if (!prev)
> > +		prev_output_bus_caps = &self->encoder->output_bus_caps;
> > +	else
> > +		prev_output_bus_caps = &prev->output_bus_caps;
> > +
> > +	ret = drm_find_best_bus_format(prev_output_bus_caps,
> > +				       &self->input_bus_caps, &crtc_state->mode,
> > +				       &bridge_state->input_bus_cfg.fmt);
> > +	if (ret)
> > +		return ret;  
> 
> I think most bridges that support multiple input and output formats will
> not necessarily be able to transcode, meaning that for a particular
> output format a particular corresponding input format will need to be
> picked (or possibly one of a subset of input formats). I'm thus not sure
> how useful this helper will be in practice.
> 
> I also fear that this negotiation mechanism is too simple and will lock
> is with support for very simple systems only :-S Let's assume a system
> with a display device (D), two bridges (B0 and B1) and a connector (C).
> Let's further assume that the bus format required by the connector is
> fixed. With this patch series, B1 will pick an output format identical
> to the format on the connector, and will then pick an input format among
> the ones supported by both B0 and B1. Let's assume there are multiple
> options, Fa and Fb, and drm_find_best_bus_format() will pick one of
> them, say Fa. Then B0 will configure its output with that format, and
> will proceed with finding an input format supported by D. It could be
> that the output format Fa for B0 requires an input format that is not
> supported by D, while Fb would have produced a working pipeline.

Yes, I assumed all pipeline elements would be able to convert any of
their supported input formats to any of the output ones, which might
not be the case in practice. I could add a matrix to expose the
supported conversions and add a pass of 'format eviction' at bridge
attach time, but I'm not sure that's enough.

> 
> I don't think this example is really far-fetched, and while we don't
> need to support it immediately, we need an API that makes it possible to
> support it, as changing the API later would require reworking all the
> drivers that use it.
> 
> > +
> > +	/*
> > +	 * TODO:
> > +	 * Should we fill/check the ->flag field too?
> > +	 */
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_bridge_choose_input_bus_cfg);
> > +
> > +/**
> > + * drm_atomic_bridge_choose_output_bus_cfg() - Choose bus config for the output
> > + *					       end
> > + * @bridge_state: bridge state
> > + * @crtc_state: CRTC state
> > + * @conn_state: connector state
> > + *
> > + * Choose a bus format for the output side of a bridge based on what the next
> > + * bridge in the chain and this bridge support. Can be called from bridge
> > + * drivers' &drm_bridge_funcs.atomic_check() implementation.
> > + *
> > + * RETURNS:
> > + * 0 if a matching format was found, a negative error code otherwise
> > + */
> > +int
> > +drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
> > +					struct drm_crtc_state *crtc_state,
> > +					struct drm_connector_state *conn_state)
> > +{
> > +	struct drm_atomic_state *state = crtc_state->state;
> > +	struct drm_bridge *self = bridge_state->bridge;
> > +	struct drm_bridge_state *next_bridge_state;
> > +	struct drm_bridge *next;
> > +	u32 fmt;
> > +
> > +	next = drm_bridge_chain_get_next_bridge(self);
> > +	if (!next) {
> > +		struct drm_connector *conn = conn_state->connector;
> > +		struct drm_display_info *di = &conn->display_info;
> > +
> > +		/*
> > +		 * FIXME:
> > +		 * We currently pick the first supported format
> > +		 * unconditionally. It seems to fit all current use cases but
> > +		 * might be too limited for panels/displays that can configure
> > +		 * the bus format dynamically.
> > +		 */
> > +		if (di->num_bus_formats && di->bus_formats)
> > +			bridge_state->output_bus_cfg.fmt = di->bus_formats[0];
> > +		else
> > +			bridge_state->output_bus_cfg.fmt = 0;  
> 
> What is the bridge driver supposed to do in this case ?

Pick a default value (or a something fixed by a FW property), as it used
to do before this patchset. There's no way we can convert all bridges at
once, so we need to support mixed chains formed of bridges that support
bus format negotiation and bridges that don't.

> 
> > +
> > +		bridge_state->output_bus_cfg.flags = di->bus_flags;
> > +		return 0;
> > +	}
> > +
> > +	/*
> > +	 * We expect output_bus_caps to contain at least one format. Note
> > +	 * that don't care about bus format negotiation can simply not
> > +	 * call this helper.  
> 
> I'm not sure to parse the second sentence correctly.

Oops.

"Note that drivers that don't care about ...".
I'm just trying to explain why EINVAL is returned when
->output_bus_caps is not populated.

> 
> > +	 */
> > +	if (!self->output_bus_caps.num_supported_fmts ||!  
> 
> Extra ! at the end of the line ?
> 
> > +	    !self->output_bus_caps.supported_fmts)
> > +		return -EINVAL;
> > +
> > +	next_bridge_state = drm_atomic_get_new_bridge_state(state, next);
> > +
> > +	/*
> > +	 * The next bridge is expected to have called
> > +	 * &drm_atomic_bridge_choose_input_bus_cfg() as part of its
> > +	 * &drm_bridge_funcs.atomic_check() implementation, but this hook is
> > +	 * optional, and even if it's implemented, calling
> > +	 * &drm_atomic_bridge_choose_input_bus_cfg() is not mandated.
> > +	 * If fmt is zero, that means the next element in the chain doesn't
> > +	 * care about bus format negotiation (probably because there's only
> > +	 * one possible setting). In that case, we still have to select one
> > +	 * bus format for the output port of our bridge, and this is only
> > +	 * possible if the bridge supports only one format.  
> 
> Theoritically we could also just pick the first one (or actually any of
> the supported formats), couldn't we ?

Hm, not really. I mean, if the bridge supports several output formats,
there's no way we can tell which one is the right one for this
specific setup. The idea being that drivers are responsible for picking
an appropriate output bus-format based on something else (DT prop?)
when drm_atomic_bridge_choose_output_bus_cfg() returns an error.

> 
> 
> > +	 */
> > +	fmt = next_bridge_state->input_bus_cfg.fmt;
> > +	if (fmt) {
> > +		unsigned int i;
> > +
> > +		for (i = 0; i < self->output_bus_caps.num_supported_fmts; i++) {
> > +			if (self->output_bus_caps.supported_fmts[i] == fmt)
> > +				break;
> > +		}
> > +
> > +		if (i == self->output_bus_caps.num_supported_fmts)
> > +			return -ENOTSUPP;
> > +	} else if (self->output_bus_caps.num_supported_fmts == 1) {
> > +		fmt = self->output_bus_caps.supported_fmts[0];
> > +	} else {
> > +		return -EINVAL;
> > +	}
> > +
> > +	/*
> > +	 * TODO:
> > +	 * Should we fill/check the ->flag field too?
> > +	 */
> > +	bridge_state->output_bus_cfg.fmt = fmt;
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_bridge_choose_output_bus_cfg);
> > +
> >  static int drm_atomic_bridge_check(struct drm_bridge *bridge,
> >  				   struct drm_crtc_state *crtc_state,
> >  				   struct drm_connector_state *conn_state)
> > diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> > index 2f69adb7b0f3..c578800a05e0 100644
> > --- a/include/drm/drm_bridge.h
> > +++ b/include/drm/drm_bridge.h
> > @@ -33,15 +33,45 @@ struct drm_bridge;
> >  struct drm_bridge_timings;
> >  struct drm_panel;
> >  
> > +/**
> > + * struct drm_bus_cfg - bus configuration
> > + * @fmt: format used on this bus
> > + * @flags: DRM_BUS_ flags used on this bus
> > + *
> > + * Encodes the bus format and bus flags used by one end of the bridge or
> > + * by the encoder output.
> > + */
> > +struct drm_bus_cfg {
> > +	u32 fmt;
> > +	u32 flags;
> > +};
> > +
> > +/**
> > + * struct drm_bus_caps - bus capabilities
> > + * @supported_fmts: array of MEDIA_BUS_FMT_ formats
> > + * @num_supported_fmts: size of the supported_fmts array
> > + *
> > + * Used by the core to negotiate the bus format at runtime.
> > + */
> > +struct drm_bus_caps {
> > +	const u32 *supported_fmts;
> > +	unsigned int num_supported_fmts;
> > +};
> > +
> >  /**
> >   * struct drm_bridge_state - Atomic bridge state object
> >   * @base: inherit from &drm_private_state
> >   * @bridge: the bridge this state refers to
> > + * @input_bus_info: input bus information
> > + * @output_bus_info: output bus information  
> 
> I would make this an array, to prepare for bridges that will have more
> than one input or one output.

Hm, not sure how you'd represent that. I guess you want to support
bridges that can activate several inputs+outputs in parallel. Do we
even support that right now?
Also, how do we link the input to the output in that case? By their
position in the array? And we'd need an extra field in bus_caps to
point to the corresponding bridge input/output port.

I'm glad we can discuss all those problems, but I'd like to focus on
what's needed right now, not what could potentially be needed in the
future. If we can design things to be more future-proof that's great,
but in my experience, trying to solve problems that do not exist yet
often leads to complex designs which prove to be wrong when we try to
apply them to real situations when they finally occur.

> 
> >   */
> >  struct drm_bridge_state {
> >  	struct drm_private_state base;
> >  
> >  	struct drm_bridge *bridge;
> > +
> > +	struct drm_bus_cfg input_bus_cfg;
> > +	struct drm_bus_cfg output_bus_cfg;
> >  };
> >  
> >  static inline struct drm_bridge_state *
> > @@ -465,6 +495,9 @@ struct drm_bridge {
> >  	const struct drm_bridge_funcs *funcs;
> >  	/** @driver_private: pointer to the bridge driver's internal context */
> >  	void *driver_private;
> > +
> > +	struct drm_bus_caps input_bus_caps;
> > +	struct drm_bus_caps output_bus_caps;
> >  };
> >  
> >  static inline struct drm_bridge *
> > @@ -479,6 +512,14 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> >  int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> >  		      struct drm_bridge *previous);
> >  
> > +int
> > +drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
> > +				       struct drm_crtc_state *crtc_state,
> > +				       struct drm_connector_state *conn_state);
> > +int
> > +drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
> > +					struct drm_crtc_state *crtc_state,
> > +					struct drm_connector_state *conn_state);
> >  struct drm_bridge *
> >  drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder);
> >  struct drm_bridge *
> > @@ -562,6 +603,11 @@ drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
> >  	return drm_priv_to_bridge_state(obj_state);
> >  }
> >  
> > +int drm_find_best_bus_format(const struct drm_bus_caps *a,
> > +			     const struct drm_bus_caps *b,
> > +			     const struct drm_display_mode *mode,
> > +			     u32 *selected_bus_fmt);
> > +
> >  #ifdef CONFIG_DRM_PANEL_BRIDGE
> >  struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
> >  					u32 connector_type);
> > diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
> > index 0899f7f34e3a..e891921b3aed 100644
> > --- a/include/drm/drm_encoder.h
> > +++ b/include/drm/drm_encoder.h
> > @@ -25,6 +25,7 @@
> >  
> >  #include <linux/list.h>
> >  #include <linux/ctype.h>
> > +#include <drm/drm_bridge.h>
> >  #include <drm/drm_crtc.h>
> >  #include <drm/drm_mode.h>
> >  #include <drm/drm_mode_object.h>
> > @@ -184,6 +185,11 @@ struct drm_encoder {
> >  	 * functions as part of its encoder enable/disable handling.
> >  	 */
> >  	uint32_t custom_bridge_enable_disable_seq : 1;
> > +
> > +	/**
> > +	 * @output_bus_caps: Supported output bus caps
> > +	 */
> > +	struct drm_bus_caps output_bus_caps;
> >  };
> >  
> >  #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
> >   
> 

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

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

* Re: [PATCH RFC 12/19] drm/bridge: Add an ->atomic_check() hook
  2019-08-22  0:12   ` Laurent Pinchart
@ 2019-08-22  7:58     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22  7:58 UTC (permalink / raw)
  To: Laurent Pinchart, Andrzej Hajda
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Thu, 22 Aug 2019 03:12:07 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:43PM +0200, Boris Brezillon wrote:
> > So that bridge drivers have a way to check/reject an atomic operation.
> > The drm_atomic_bridge_chain_check() (which is just a wrapper around
> > the ->atomic_check() hook) is called in place of
> > drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented,
> > the core falls back to ->mode_fixup(), so the behavior should stay
> > the same for existing bridge drivers).
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > ---
> >  drivers/gpu/drm/drm_atomic_helper.c | 11 +++---
> >  drivers/gpu/drm/drm_bridge.c        | 59 +++++++++++++++++++++++++++++
> >  include/drm/drm_bridge.h            | 23 +++++++++++
> >  3 files changed, 87 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index e76ec9648b6f..3fadde38ead7 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -445,12 +445,11 @@ mode_fixup(struct drm_atomic_state *state)
> >  		encoder = new_conn_state->best_encoder;
> >  		funcs = encoder->helper_private;
> >  
> > -		ret = drm_bridge_chain_mode_fixup(encoder,
> > -					&new_crtc_state->mode,
> > -					&new_crtc_state->adjusted_mode);
> > -		if (!ret) {
> > -			DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
> > -			return -EINVAL;
> > +		ret = drm_atomic_bridge_chain_check(encoder, new_crtc_state,
> > +						    new_conn_state);
> > +		if (ret) {
> > +			DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
> > +			return ret;
> >  		}
> >  
> >  		if (funcs && funcs->atomic_check) {
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 0528ca941855..dcad661daa74 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -583,6 +583,65 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
> >  }
> >  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
> >  
> > +static int drm_atomic_bridge_check(struct drm_bridge *bridge,
> > +				   struct drm_crtc_state *crtc_state,
> > +				   struct drm_connector_state *conn_state)
> > +{
> > +	if (bridge->funcs->atomic_check) {
> > +		struct drm_bridge_state *bridge_state;
> > +		int ret;
> > +
> > +		bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
> > +							       bridge);
> > +		if (WARN_ON(!bridge_state))
> > +			return -EINVAL;
> > +
> > +		ret = bridge->funcs->atomic_check(bridge, bridge_state,
> > +						  crtc_state, conn_state);
> > +		if (ret)
> > +			return ret;
> > +	} else if (bridge->funcs->mode_fixup) {
> > +		if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode,
> > +					       &crtc_state->adjusted_mode))
> > +			return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
> > + * @encoder: encoder object
> > + * @crtc_state: new CRTC state
> > + * @conn_state: new connector state
> > + *
> > + * Calls &drm_bridge_funcs.atomic_check() (falls back on
> > + * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
> > + * starting from the last bridge to the first. These are called before calling
> > + * &drm_encoder_helper_funcs.atomic_check()
> > + *
> > + * RETURNS:
> > + * 0 on success, a negative error code on failure
> > + */
> > +int drm_atomic_bridge_chain_check(struct drm_encoder *encoder,
> > +				  struct drm_crtc_state *crtc_state,
> > +				  struct drm_connector_state *conn_state)
> > +{
> > +	struct drm_bridge *bridge;
> > +
> > +	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
> > +				    chain_node) {
> > +		int ret;
> > +
> > +		ret = drm_atomic_bridge_check(bridge, crtc_state, conn_state);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_bridge_chain_check);
> > +
> >  /**
> >   * drm_atomic_helper_init_bridge_state() - Initializes a bridge state
> >   * @bridge this state is referring to
> > diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> > index 9383b4e4b853..5d8fe3709bde 100644
> > --- a/include/drm/drm_bridge.h
> > +++ b/include/drm/drm_bridge.h
> > @@ -379,6 +379,26 @@ struct drm_bridge_funcs {
> >  	 */
> >  	void (*atomic_destroy_state)(struct drm_bridge *bridge,
> >  				     struct drm_bridge_state *state);
> > +
> > +	/**
> > +	 * @atomic_check:
> > +	 *
> > +	 * This method is responsible for checking bridge state correctness.
> > +	 * It can also check the state of the surrounding components in chain
> > +	 * to make sure the whole pipeline can work properly.  
> 
> As this is meant to replace .mode_fixup() you should document that here
> and in the .mode_fixup() operation.
> 
> There's also the additional question of what parameters can be modified.
> Is a bridge .atomic_check() allowed to modify the CRTC or connector
> state ? Of so, what are the restrictions on how those can be modified ?
> For instance .mode_fixup() can change the pixel clock but isn't allowed
> to modify the h/v active values. Those restrictions were not clearly
> documented for .mode_fixup() and have led to grey areas. I don't want to
> repeat the same mistake for bridges, we need to be very explicit here.

Any recommendation? I didn't face this problem myself, so I'd need
inputs from those who did to take a decision.

> 
> In the list of open questions, what if a bridge changes the pixel clock
> to a value it supports (as .mode_fixup() does), and then the previous
> bridge in the chain (the next one in traversal order for the
> drm_atomic_bridge_chain_check() function) also changes the pixel clock,
> to a value that the current bridge doesn't support ? I think we really
> need to think about the semantic of this operation.

Don't we have the exact same problem right now with the ->mode_fixup()
hook when bridges are chained? Not sure why it suddenly becomes a
priority to clarify that, but if we quickly settle on this new semantic,
I'm fine integrating those changes in my patchset.

> 
> As the goal of your series is to implement configuration of bus formats
> between bridges, shouldn't a bridge .atomic_check() also receive the
> state of the next bridge in the chain ?

I thought we had enough arguments passed to the atomic_check() hook and
decided to let the driver retrieve the next state. I can pass the next
bridge state if you prefer.

> 
> > +	 *
> > +	 * &drm_bridge_funcs.atomic_check() hooks are called in reverse
> > +	 * order (from the last to the first bridge).
> > +	 *
> > +	 * This method is optional.
> > +	 *
> > +	 * RETURNS:
> > +	 * zero if the check passed, a negative error code otherwise.
> > +	 */
> > +	int (*atomic_check)(struct drm_bridge *bridge,
> > +			    struct drm_bridge_state *bridge_state,
> > +			    struct drm_crtc_state *crtc_state,
> > +			    struct drm_connector_state *conn_state);
> >  };
> >  
> >  /**
> > @@ -479,6 +499,9 @@ void drm_bridge_chain_mode_set(struct drm_encoder *encoder,
> >  void drm_bridge_chain_pre_enable(struct drm_encoder *encoder);
> >  void drm_bridge_chain_enable(struct drm_encoder *encoder);
> >  
> > +int drm_atomic_bridge_chain_check(struct drm_encoder *encoder,
> > +				  struct drm_crtc_state *crtc_state,
> > +				  struct drm_connector_state *conn_state);
> >  void drm_atomic_bridge_chain_disable(struct drm_encoder *encoder,
> >  				     struct drm_atomic_state *state);
> >  void drm_atomic_bridge_chain_post_disable(struct drm_encoder *encoder,  
> 

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

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

* Re: [PATCH RFC 13/19] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper
  2019-08-22  0:17   ` Laurent Pinchart
@ 2019-08-22  8:04     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22  8:04 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Thu, 22 Aug 2019 03:17:32 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:44PM +0200, Boris Brezillon wrote:
> > Will be useful for bridge drivers that want to do bus format
> > negotiation with their neighbours.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > ---
> >  drivers/gpu/drm/drm_bridge.c | 19 +++++++++++++++++++
> >  include/drm/drm_bridge.h     |  2 ++
> >  2 files changed, 21 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index dcad661daa74..9efb27087e70 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -271,6 +271,25 @@ drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge)
> >  }
> >  EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
> >  
> > +/**
> > + * drm_bridge_chain_get_prev_bridge() - Get the previous bridge in the chain
> > + * @bridge: bridge object
> > + *
> > + * RETURNS:
> > + * the previous bridge in the chain, or NULL if there's @bridge is the
> > + * last.  
> 
> Did you mean "if the @bridge is the first" ?

Yes, sorry about that, I meant "if @bridge is the first", indeed.

> 
> > + */
> > +struct drm_bridge *
> > +drm_bridge_chain_get_prev_bridge(struct drm_bridge *bridge)
> > +{
> > +	if (!bridge || !bridge->encoder ||  
> 
> Do we really need to protect against !bridge and !bridge->encoder, can
> that happen ?

Maybe not.

> Especially !bridge, are there use cases for potentially
> calling this function (and the other list traversal helpers in your
> previous patches) with a NULL bridge ?

I think this checks was done when bridge iteration was based on
recursivity, which is no longer the case.

> 
> > +	    list_is_first(&bridge->encoder->bridge_chain, &bridge->chain_node))
> > +                return NULL;
> > +
> > +	return list_prev_entry(bridge, chain_node);
> > +}
> > +EXPORT_SYMBOL(drm_bridge_chain_get_prev_bridge);
> > +
> >  /**
> >   * DOC: bridge callbacks
> >   *
> > diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> > index 5d8fe3709bde..2f69adb7b0f3 100644
> > --- a/include/drm/drm_bridge.h
> > +++ b/include/drm/drm_bridge.h
> > @@ -485,6 +485,8 @@ struct drm_bridge *
> >  drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder);
> >  struct drm_bridge *
> >  drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge);
> > +struct drm_bridge *
> > +drm_bridge_chain_get_prev_bridge(struct drm_bridge *bridge);
> >  bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
> >  				 const struct drm_display_mode *mode,
> >  				 struct drm_display_mode *adjusted_mode);  
> 

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

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

* Re: [PATCH RFC 17/19] drm/bridge: lvds-encoder: Implement bus format negotiation for sn75lvds83
  2019-08-22  0:32   ` Laurent Pinchart
@ 2019-08-22  8:12     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22  8:12 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Thu, 22 Aug 2019 03:32:10 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:48PM +0200, Boris Brezillon wrote:
> > The SN75LVDS83 bridge support several input formats except the input
> > format is directly related to the expected output format. Let's express
> > that constraint by setting the bridge_state->output_bus_cfg.fmt field
> > to the appropriate value.
> > 
> > The previous element in the chain might be able to use this information
> > to pick the appropriate output bus format.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>  
> 
> This driver is supposed to only support LVDS encoders that require no
> special configuration, and thus not contain device-specific code. I'm
> not sure I like departing from this :-S
> 
> Would there be a way to make this more generic ? Do you think the code
> below could be generalized, or is it really device-specific ?

The list of supported formats is likely to differ, so you'd at least
need to attach that to the compat. Also not sure the RGB -> LVDS format
conversion always follow the same logic, hence the decision to let
bridges implement ->atomic_check() if they want/need to.

Should I create a new driver for this bridge?

> 
> > ---
> >  drivers/gpu/drm/bridge/lvds-encoder.c | 48 +++++++++++++++++++++++++++
> >  1 file changed, 48 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
> > index da7013c5faf1..8d399d1828b0 100644
> > --- a/drivers/gpu/drm/bridge/lvds-encoder.c
> > +++ b/drivers/gpu/drm/bridge/lvds-encoder.c
> > @@ -159,9 +159,57 @@ static int lvds_encoder_remove(struct platform_device *pdev)
> >  	return 0;
> >  }
> >  
> > +static int sn75lvds83_atomic_check(struct drm_bridge *bridge,
> > +				   struct drm_bridge_state *bridge_state,
> > +				   struct drm_crtc_state *crtc_state,
> > +				   struct drm_connector_state *conn_state)
> > +{
> > +	int ret;
> > +
> > +	ret = drm_atomic_bridge_choose_output_bus_cfg(bridge_state, crtc_state,
> > +						      conn_state);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/*
> > +	 * The output bus format has a direct impact on the expected input bus
> > +	 * format.
> > +	 */
> > +	switch (bridge_state->output_bus_cfg.fmt) {
> > +	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
> > +	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
> > +		/*
> > +		 * JEIDA and SPWG variants theoretically require different pin
> > +		 * mapping, but MEDIA_BUS_FMT_ definitions do not allow
> > +		 * fined-grained pin placement definition, and this is
> > +		 * something we expect to be taken care of at board design
> > +		 * time, so let's ignore this for now.
> > +		 * If it becomes a problem, we can always add a way to override
> > +		 * the bus format with a FW property.
> > +		 */
> > +		bridge_state->input_bus_cfg.fmt = MEDIA_BUS_FMT_RGB888_1X24;
> > +		break;
> > +	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
> > +		bridge_state->input_bus_cfg.fmt = MEDIA_BUS_FMT_RGB666_1X18;
> > +		break;
> > +	default:
> > +		bridge_state->input_bus_cfg.fmt = 0;
> > +		break;
> > +	}  
> 
> These seems a bit fragile. The SN75LVDS83 has a 28-bit input data bus,
> and maps those bits to 3x8 RGB data + 1x4 control signals. It serialises
> the data and outputs them on 4 LVDS pairs. When a panel uses
> MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA or MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, the
> 4 LVDS pairs are used, and MEDIA_BUS_FMT_RGB888_1X24 is required. When
> outputting MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, the fourth LVDS pair is
> ignored, but the 3x8 RGB input bus can still receive
> MEDIA_BUS_FMT_RGB888_1X24, the 2 LSBs of each component will just be
> discarded. The source can thus ignore those 3x2 LSBs, but it still has
> to map the 3x6 MSBs to the high order bits of the 3x8 signals.
> *However*, if the hardware designs wires the 3x6 MSBs of the SN75LVDS83
> to the 3x6 LSBs of the source, then the source will have to produce
> MEDIA_BUS_FMT_RGB666_1X18. Hardcoding the mapping as done here thus
> seems to be system-specific. I think you need to check how signals are
> connected (through DT properties, bus-width and data-shift come to
> mind).

True, I just wanted to keep it simple until the need for the other
case arises. Should we make the bus-width/data-shift mandatory for that
bridge, or can we have a default behavior (like the one proposed here)
when the props are missing?

> 
> > +
> > +	/* Propagate the bus_flags. */
> > +	bridge_state->input_bus_cfg.flags = bridge_state->output_bus_cfg.flags;
> > +	return 0;
> > +}
> > +
> > +static const struct lvds_encoder_ops sn75lvds83_ops = {
> > +	.atomic_check = sn75lvds83_atomic_check,
> > +};
> > +
> >  static const struct of_device_id lvds_encoder_match[] = {
> >  	{ .compatible = "lvds-encoder" },
> >  	{ .compatible = "thine,thc63lvdm83d" },
> > +	{ .compatible = "ti,sn75lvds83", .data = &sn75lvds83_ops },
> >  	{},
> >  };
> >  MODULE_DEVICE_TABLE(of, lvds_encoder_match);  
> 

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

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

* Re: [PATCH RFC 18/19] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel
  2019-08-22  0:36   ` Laurent Pinchart
@ 2019-08-22  8:15     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22  8:15 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Thu, 22 Aug 2019 03:36:32 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Thu, Aug 08, 2019 at 05:11:49PM +0200, Boris Brezillon wrote:
> > Add a new entry for the Toshiba LTA089AC29000 panel.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
> > ---
> >  .../display/panel/toshiba,lt089ac29000.txt    |  5 ++-
> >  drivers/gpu/drm/panel/panel-simple.c          | 36 +++++++++++++++++++
> >  2 files changed, 40 insertions(+), 1 deletion(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
> > index 89826116628c..26ebfa098966 100644
> > --- a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
> > +++ b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
> > @@ -1,7 +1,10 @@
> >  Toshiba 8.9" WXGA (1280x768) TFT LCD panel
> >  
> >  Required properties:
> > -- compatible: should be "toshiba,lt089ac29000"
> > +- compatible: should be one of the following
> > +	      "toshiba,lt089ac29000"
> > +	      "toshiba,lta089ac29000"
> > +
> >  - power-supply: as specified in the base binding
> >  
> >  This binding is compatible with the simple-panel binding, which is specified  
> 
> While at it, any change to convert this binding to .yaml ? For panels
> it's fairly easy.

I'll add a patch doing that.

> 
> > diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
> > index bff7578f84dd..4c1deed44ce2 100644
> > --- a/drivers/gpu/drm/panel/panel-simple.c
> > +++ b/drivers/gpu/drm/panel/panel-simple.c
> > @@ -2857,6 +2857,39 @@ static const struct panel_desc toshiba_lt089ac29000 = {
> >  	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
> >  };
> >  
> > +static const struct drm_display_mode toshiba_lta089ac29000_mode = {
> > +	.clock = 79500,
> > +	.hdisplay = 1280,
> > +	.hsync_start = 1280 + 192,
> > +	.hsync_end = 1280 + 192 + 128,
> > +	.htotal = 1280 + 192 + 128 + 64,
> > +	.vdisplay = 768,
> > +	.vsync_start = 768 + 20,
> > +	.vsync_end = 768 + 20 + 7,
> > +	.vtotal = 768 + 20 + 7 + 3,
> > +	.vrefresh = 60,
> > +};
> > +
> > +static const struct panel_desc toshiba_lta089ac29000 = {
> > +	.modes = &toshiba_lta089ac29000_mode,
> > +	.num_modes = 1,
> > +	.size = {
> > +		.width = 194,
> > +		.height = 116,
> > +	},
> > +	/*
> > +	 * FIXME:
> > +	 * The panel supports 2 bus formats: jeida-24 and jeida-18. The
> > +	 * mode is selected through the 8b6b_SEL pin. If anyone ever needs
> > +	 * support for jeida-18 we should probably parse the 'data-mapping'
> > +	 * property.
> > +	 * In the unlikely event where 8b6b_SEL is connected to a GPIO, we'd
> > +	 * need a new infra to allow bus format negotiation at the panel level.  
> 
> I would also leave the GPIO case for later, but it would be nice to already
> implement reading the data-mapping property, in order to validate the DT
> (you should add the data-mapping property to the bindings by the way).

I'll do that.

> Bonus points if it can be done in a way that is also usable by other
> panels.

Sure, I'll make that code generic.

> 
> > +	 */
> > +	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
> > +	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
> > +};
> > +
> >  static const struct drm_display_mode tpk_f07a_0102_mode = {
> >  	.clock = 33260,
> >  	.hdisplay = 800,
> > @@ -3305,6 +3338,9 @@ static const struct of_device_id platform_of_match[] = {
> >  	}, {
> >  		.compatible = "toshiba,lt089ac29000",
> >  		.data = &toshiba_lt089ac29000,
> > +	}, {
> > +		.compatible = "toshiba,lta089ac29000",
> > +		.data = &toshiba_lta089ac29000,
> >  	}, {
> >  		.compatible = "tpk,f07a-0102",
> >  		.data = &tpk_f07a_0102,  
> 

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

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

* Re: [PATCH RFC 11/19] drm/bridge: Patch atomic hooks to take a drm_bridge_state
  2019-08-22  0:02   ` Laurent Pinchart
@ 2019-08-22  8:25     ` Boris Brezillon
  0 siblings, 0 replies; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22  8:25 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Thu, 22 Aug 2019 03:02:17 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> >  }
> >  EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
> > @@ -518,10 +535,18 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_encoder *encoder,
> >  
> >  	list_for_each_entry_reverse(bridge, &encoder->bridge_chain,
> >  				    chain_node) {
> > -		if (bridge->funcs->atomic_pre_enable)
> > -			bridge->funcs->atomic_pre_enable(bridge, state);
> > -		else if (bridge->funcs->pre_enable)
> > +		if (bridge->funcs->atomic_pre_enable) {
> > +			struct drm_bridge_state *bridge_state;
> > +
> > +			bridge_state = drm_atomic_get_new_bridge_state(state,
> > +								       bridge);  
> 
> Shouldn't you get the old state here ? The new state in commit-related
> operations is supposed to be obtained from the object itself, and the
> old state is passed to the function. See how the CRTC and encoder
> .atomic_enable() are called in drm_atomic_helper_commit_modeset_enables
> (drm_atomic_helper.c) for instance.
> 
> You should update the documentation of the bridge atomic operations to
> makes this explicit. The documentation of the bridge helpers
> (drm_atomic_bridge_enable() & co.) is also misleading, they get passed
> the old state, while the documentation states "atomic state being
> committed". I think you should rename all those state parameters to
> old_state to make this clearer.
> 
> Last but not least, the implementation in the analogix bridge driver
> seems to expect the new state, so I think it's buggy.

I based that decision on the only driver implementing those hooks. I
can pass the old_state instead.

> 
> > +			if (WARN_ON(!bridge_state))
> > +				return;
> > +
> > +			bridge->funcs->atomic_pre_enable(bridge, bridge_state);
> > +		} else if (bridge->funcs->pre_enable) {
> >  			bridge->funcs->pre_enable(bridge);
> > +		}
> >  	}
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object
  2019-08-21 20:14   ` Laurent Pinchart
@ 2019-08-22  9:00     ` Boris Brezillon
  2019-12-02 15:52       ` Laurent Pinchart
  0 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22  9:00 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jernej Skrabec, Neil Armstrong, Jonas Karlman, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

On Wed, 21 Aug 2019 23:14:56 +0300
Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:

> > +int
> > +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
> > +			       struct drm_encoder *encoder)
> > +{
> > +	struct drm_bridge_state *bridge_state;
> > +	struct drm_bridge *bridge;
> > +
> > +	if (!encoder)
> > +		return 0;
> > +
> > +	DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n",
> > +			 encoder->base.id, encoder->name, state);
> > +
> > +	for (bridge = drm_bridge_chain_get_first_bridge(encoder); bridge;
> > +	     bridge = drm_bridge_chain_get_next_bridge(bridge)) {  
> 
> Would a for_each_bridge() macro make sense ? I'd implement it on top of
> list_for_each_entry() to make it simple.

I can add this helper. Note that for_each_bridge() will iterate over
the whole bridge chain, and we might need a for_each_bridge_from() at
some point if we want to iterate over a sub-chain.

> 
> > +		bridge_state = drm_atomic_get_bridge_state(state, bridge);
> > +		if (IS_ERR(bridge_state))
> > +			return PTR_ERR(bridge_state);
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);

[...]

> >  
> > +/**
> > + * drm_atomic_helper_init_bridge_state() - Initializes a bridge state  
> 
> s/Initializes/Initialize/
> 
> > + * @bridge this state is referring to  
> 
> Did you mean
> 
>  * @bridge: the bridge this state is referring to ?

Yes.

> 
> > + * @state: bridge state to initialize
> > + *
> > + * For now it's just a memset(0) plus a state->bridge assignment. Might
> > + * be extended in the future.
> > + */
> > +void drm_atomic_helper_init_bridge_state(struct drm_bridge *bridge,
> > +					 struct drm_bridge_state *state)
> > +{
> > +	memset(state, 0, sizeof(*state));
> > +	state->bridge = bridge;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_helper_init_bridge_state);  
> 
> Other objects don't export a state init function helper, but state reset
> and state duplicate helpers. Is there a reason to depart from that model
> ? Same for the copy helper below.

I thought those names better reflect what the helpers do.
__drm_atomic_helper_crtc_duplicate_state() for instance, it actually
does not duplicate the state, but just copies current state info into
the new state object which has been allocated by the caller. Same for
the reset helpers, they actually do not reset anything but just
initialize the state to a default. I also try to avoid prefixing
functions with __ when I can (names can be clarified/extended to avoid
conflicts most of the time).
Will switch back to reset/dup names if you prefer.

> 
> > +
> > +/**
> > + * drm_atomic_helper_copy_bridge_state() - Copy the content of a bridge state
> > + * @bridge: bridge the old and new state are referring to
> > + * @old: previous bridge state to copy from
> > + * @new: new bridge state to copy to
> > + *
> > + * Should be used by custom &drm_bridge_funcs.atomic_duplicate() implementation
> > + * to copy the previous state into the new object.
> > + */
> > +void drm_atomic_helper_copy_bridge_state(struct drm_bridge *bridge,
> > +					 const struct drm_bridge_state *old,
> > +					 struct drm_bridge_state *new)
> > +{
> > +	*new = *old;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_helper_copy_bridge_state);
> > +
> > +/**
> > + * drm_atomic_helper_duplicate_bridge_state() - Default duplicate state helper
> > + * @bridge: bridge containing the state to duplicate
> > + *
> > + * Default implementation of &drm_bridge_funcs.atomic_duplicate().
> > + *
> > + * RETURNS:
> > + * a valid state object or NULL if the allocation fails.
> > + */
> > +struct drm_bridge_state *
> > +drm_atomic_helper_duplicate_bridge_state(struct drm_bridge *bridge)
> > +{
> > +	struct drm_bridge_state *old = NULL, *new;
> > +
> > +	new = kzalloc(sizeof(*new), GFP_KERNEL);
> > +	if (!new)
> > +		return NULL;
> > +
> > +	if (bridge->base.state) {
> > +		old = drm_priv_to_bridge_state(bridge->base.state);
> > +		drm_atomic_helper_copy_bridge_state(bridge, old, new);
> > +	} else {
> > +		drm_atomic_helper_init_bridge_state(bridge, new);
> > +	}
> > +
> > +	return new;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_helper_duplicate_bridge_state);
> > +
> > +/**
> > + * drm_atomic_helper_destroy_bridge_state() - Default destroy state helper
> > + * @bridge: the bridge this state refers to
> > + * @state: state object to destroy
> > + *
> > + * Just a simple kfree() for now.
> > + */
> > +void drm_atomic_helper_destroy_bridge_state(struct drm_bridge *bridge,
> > +					    struct drm_bridge_state *state)
> > +{
> > +	kfree(state);
> > +}
> > +EXPORT_SYMBOL(drm_atomic_helper_destroy_bridge_state);
> > +
> >  #ifdef CONFIG_OF
> >  /**
> >   * of_drm_find_bridge - find the bridge corresponding to the device node in
> > diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> > index 927e1205d7aa..5ee25fd51e80 100644
> > --- a/include/drm/drm_atomic.h
> > +++ b/include/drm/drm_atomic.h
> > @@ -660,6 +660,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
> >  	return plane->state;
> >  }
> >  
> > +int __must_check
> > +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
> > +                               struct drm_encoder *encoder);
> >  int __must_check
> >  drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
> >  				   struct drm_crtc *crtc);
> > diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> > index f40181274ed7..8ca25d266d0c 100644
> > --- a/include/drm/drm_bridge.h
> > +++ b/include/drm/drm_bridge.h
> > @@ -25,6 +25,7 @@
> >  
> >  #include <linux/list.h>
> >  #include <linux/ctype.h>
> > +#include <drm/drm_atomic.h>
> >  #include <drm/drm_mode_object.h>
> >  #include <drm/drm_modes.h>
> >  
> > @@ -32,6 +33,23 @@ struct drm_bridge;
> >  struct drm_bridge_timings;
> >  struct drm_panel;
> >  
> > +/**
> > + * struct drm_bridge_state - Atomic bridge state object
> > + * @base: inherit from &drm_private_state
> > + * @bridge: the bridge this state refers to
> > + */
> > +struct drm_bridge_state {
> > +	struct drm_private_state base;
> > +
> > +	struct drm_bridge *bridge;
> > +};
> > +
> > +static inline struct drm_bridge_state *
> > +drm_priv_to_bridge_state(struct drm_private_state *priv)
> > +{
> > +	return container_of(priv, struct drm_bridge_state, base);
> > +}
> > +
> >  /**
> >   * struct drm_bridge_funcs - drm_bridge control functions
> >   */
> > @@ -337,6 +355,30 @@ struct drm_bridge_funcs {
> >  	 */
> >  	void (*atomic_post_disable)(struct drm_bridge *bridge,
> >  				    struct drm_atomic_state *state);
> > +
> > +	/**
> > +	 * @atomic_duplicate_state:
> > +	 *
> > +	 * Duplicate the current bridge state object.
> > +	 *
> > +	 * Note that this function can be called when current bridge state is
> > +	 * NULL. In this case, implementations should either implement HW
> > +	 * readback or initialize the state with sensible default values.  
> 
> Related to the question above, shouldn't we have a reset state operation
> instead ?

I had a version with a reset hook and a helper that was falling back to
->duplicate_state() when not specified, but I decided to drop it to
simplify things (I think most drivers will just use the default
helper, and those that actually want to implement HW readback can
easily do it from their ->duplicate_state() hook by testing
bridge->state value).
I can re-introduce it if you like.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-22  7:48     ` Boris Brezillon
@ 2019-08-22  9:29       ` Neil Armstrong
  2019-08-22 10:09         ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Neil Armstrong @ 2019-08-22  9:29 UTC (permalink / raw)
  To: Boris Brezillon, Laurent Pinchart
  Cc: Jernej Skrabec, Jonas Karlman, Seung-Woo Kim, dri-devel,
	Kyungmin Park, Thierry Reding, Chris Healy, kernel, Sam Ravnborg

On 22/08/2019 09:48, Boris Brezillon wrote:
> On Thu, 22 Aug 2019 03:55:56 +0300
> Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> 
>> Hi Boris,
>>
>> Thank you for the patch.
>>
>> On Thu, Aug 08, 2019 at 05:11:45PM +0200, Boris Brezillon wrote:
>>> This takes the form of various helpers, plus the addition of 2 new
>>> structs:
>>> * drm_bus_caps: describe the bus capabilities of a bridge/encoder. For
>>>   bridges we have one for the input port and one for the output port.
>>>   Encoders just have one output port.
>>> * drm_bus_cfg: added to the drm_bridge_state. It's supposed to store
>>>   bus configuration information. For now we just have format and flags
>>>   but more fields might be added in the future. Again, each
>>>   drm_bridge_state contains 2 drm_bus_cfg elements: one for the output
>>>   port and one for the input port
>>>
>>> Helpers can be used from bridge drivers' ->atomic_check() implementation
>>> to negotiate the bus format to use. Negotiation happens in reserve order,  
>>
>> s/reserve/reverse/
>>
>>> starting from the last element of the bridge chain (the one directly
>>> connected to the display) to the first element of the chain (the one
>>> connected to the encoder).
>>>
>>> Negotiation usually takes place in 2 steps:
>>> * make sure the input end of the next element in the chain picked a
>>>   format that's supported by the output end of our bridge. That's done
>>>   with drm_atomic_bridge_choose_output_bus_cfg().
>>> * choose a format for the input end of our bridge based on what's
>>>   supported by the previous bridge in the chain. This is achieved by
>>>   calling drm_atomic_bridge_choose_input_bus_cfg()
>>>
>>> Note that those helpers are a bit lax when it comes to unitialized
>>> bus format validation. That's intentional. If we don't do that we'll
>>> basically break things if we start adding support for bus format
>>> negotiation to some elements of the pipeline leaving others on the
>>> side, and that's likely to happen for all external bridges since we
>>> can't necessarily tell where they are used.
>>>
>>> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
>>> ---
>>>  drivers/gpu/drm/drm_bridge.c | 187 +++++++++++++++++++++++++++++++++++
>>>  include/drm/drm_bridge.h     |  46 +++++++++
>>>  include/drm/drm_encoder.h    |   6 ++
>>>  3 files changed, 239 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
>>> index 9efb27087e70..ef072df42422 100644
>>> --- a/drivers/gpu/drm/drm_bridge.c
>>> +++ b/drivers/gpu/drm/drm_bridge.c
>>> @@ -602,6 +602,193 @@ void drm_atomic_bridge_chain_enable(struct drm_encoder *encoder,
>>>  }
>>>  EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
>>>  
>>> +int drm_find_best_bus_format(const struct drm_bus_caps *a,
>>> +			     const struct drm_bus_caps *b,
>>> +			     const struct drm_display_mode *mode,
>>> +			     u32 *selected_bus_fmt)
>>> +{
>>> +	unsigned int i, j;
>>> +
>>> +	/*
>>> +	 * Some drm_bridge/drm_encoder don't care about the input/output bus
>>> +	 * format, let's set the format to zero in that case (this is only
>>> +	 * valid if both side of the link don't care).
>>> +	 */
>>> +	if (!a->num_supported_fmts && !b->num_supported_fmts) {
>>> +		*selected_bus_fmt = 0;
>>> +		return 0;
>>> +	} else if (b->num_supported_fmts > 1 && b->supported_fmts) {
>>> +		*selected_bus_fmt = b->supported_fmts[0];
>>> +		return 0;
>>> +	} else if (a->num_supported_fmts > 1 && a->supported_fmts) {
>>> +		*selected_bus_fmt = a->supported_fmts[0];
>>> +		return 0;
>>> +	} else if (!a->num_supported_fmts || !a->supported_fmts ||
>>> +		   !b->num_supported_fmts || !b->supported_fmts) {
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	/*
>>> +	 * TODO:
>>> +	 * Dummy algo picking the first match. We probably want something
>>> +	 * smarter where the narrowest format (in term of bus width) that
>>> +	 * does not incur data loss is picked, and if all possible formats
>>> +	 * are lossy, pick the one that's less lossy among all the choices
>>> +	 * we have. In order to do that we'd need to convert MEDIA_BUS_FMT_
>>> +	 * modes into something like drm_format_info.
>>> +	 */
>>> +	for (i = 0; i < a->num_supported_fmts; i++) {
>>> +		for (j = 0; j < b->num_supported_fmts; j++) {
>>> +			if (a->supported_fmts[i] == b->supported_fmts[j]) {
>>> +				*selected_bus_fmt = a->supported_fmts[i];
>>> +				return 0;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	return -EINVAL;
>>> +}
>>> +EXPORT_SYMBOL(drm_find_best_bus_format);
>>> +
>>> +/**
>>> + * drm_atomic_bridge_choose_input_bus_cfg() - Choose bus config for the input
>>> + *					      end
>>> + * @bridge_state: bridge state
>>> + * @crtc_state: CRTC state
>>> + * @conn_state: connector state
>>> + *
>>> + * Choose a bus format for the input side of a bridge based on what the
>>> + * previous bridge in the chain and this bridge support. Can be called from
>>> + * bridge drivers' &drm_bridge_funcs.atomic_check() implementation.
>>> + *
>>> + * RETURNS:
>>> + * 0 if a matching format was found, a negative error code otherwise
>>> + */
>>> +int
>>> +drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
>>> +				       struct drm_crtc_state *crtc_state,
>>> +				       struct drm_connector_state *conn_state)
>>> +{
>>> +	struct drm_bridge *self = bridge_state->bridge;
>>> +	struct drm_bus_caps *prev_output_bus_caps;
>>> +	struct drm_bridge *prev;
>>> +	int ret;
>>> +
>>> +	prev = drm_bridge_chain_get_prev_bridge(self);
>>> +	if (!prev)
>>> +		prev_output_bus_caps = &self->encoder->output_bus_caps;
>>> +	else
>>> +		prev_output_bus_caps = &prev->output_bus_caps;
>>> +
>>> +	ret = drm_find_best_bus_format(prev_output_bus_caps,
>>> +				       &self->input_bus_caps, &crtc_state->mode,
>>> +				       &bridge_state->input_bus_cfg.fmt);
>>> +	if (ret)
>>> +		return ret;  
>>
>> I think most bridges that support multiple input and output formats will
>> not necessarily be able to transcode, meaning that for a particular
>> output format a particular corresponding input format will need to be
>> picked (or possibly one of a subset of input formats). I'm thus not sure
>> how useful this helper will be in practice.
>>
>> I also fear that this negotiation mechanism is too simple and will lock
>> is with support for very simple systems only :-S Let's assume a system
>> with a display device (D), two bridges (B0 and B1) and a connector (C).
>> Let's further assume that the bus format required by the connector is
>> fixed. With this patch series, B1 will pick an output format identical
>> to the format on the connector, and will then pick an input format among
>> the ones supported by both B0 and B1. Let's assume there are multiple
>> options, Fa and Fb, and drm_find_best_bus_format() will pick one of
>> them, say Fa. Then B0 will configure its output with that format, and
>> will proceed with finding an input format supported by D. It could be
>> that the output format Fa for B0 requires an input format that is not
>> supported by D, while Fb would have produced a working pipeline.
> 
> Yes, I assumed all pipeline elements would be able to convert any of
> their supported input formats to any of the output ones, which might
> not be the case in practice. I could add a matrix to expose the
> supported conversions and add a pass of 'format eviction' at bridge
> attach time, but I'm not sure that's enough.
> 
>>
>> I don't think this example is really far-fetched, and while we don't
>> need to support it immediately, we need an API that makes it possible to
>> support it, as changing the API later would require reworking all the
>> drivers that use it.
>>
>>> +
>>> +	/*
>>> +	 * TODO:
>>> +	 * Should we fill/check the ->flag field too?
>>> +	 */
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL(drm_atomic_bridge_choose_input_bus_cfg);
>>> +
>>> +/**
>>> + * drm_atomic_bridge_choose_output_bus_cfg() - Choose bus config for the output
>>> + *					       end
>>> + * @bridge_state: bridge state
>>> + * @crtc_state: CRTC state
>>> + * @conn_state: connector state
>>> + *
>>> + * Choose a bus format for the output side of a bridge based on what the next
>>> + * bridge in the chain and this bridge support. Can be called from bridge
>>> + * drivers' &drm_bridge_funcs.atomic_check() implementation.
>>> + *
>>> + * RETURNS:
>>> + * 0 if a matching format was found, a negative error code otherwise
>>> + */
>>> +int
>>> +drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
>>> +					struct drm_crtc_state *crtc_state,
>>> +					struct drm_connector_state *conn_state)
>>> +{
>>> +	struct drm_atomic_state *state = crtc_state->state;
>>> +	struct drm_bridge *self = bridge_state->bridge;
>>> +	struct drm_bridge_state *next_bridge_state;
>>> +	struct drm_bridge *next;
>>> +	u32 fmt;
>>> +
>>> +	next = drm_bridge_chain_get_next_bridge(self);
>>> +	if (!next) {
>>> +		struct drm_connector *conn = conn_state->connector;
>>> +		struct drm_display_info *di = &conn->display_info;
>>> +
>>> +		/*
>>> +		 * FIXME:
>>> +		 * We currently pick the first supported format
>>> +		 * unconditionally. It seems to fit all current use cases but
>>> +		 * might be too limited for panels/displays that can configure
>>> +		 * the bus format dynamically.
>>> +		 */
>>> +		if (di->num_bus_formats && di->bus_formats)
>>> +			bridge_state->output_bus_cfg.fmt = di->bus_formats[0];
>>> +		else
>>> +			bridge_state->output_bus_cfg.fmt = 0;  
>>
>> What is the bridge driver supposed to do in this case ?
> 
> Pick a default value (or a something fixed by a FW property), as it used
> to do before this patchset. There's no way we can convert all bridges at
> once, so we need to support mixed chains formed of bridges that support
> bus format negotiation and bridges that don't.
> 
>>
>>> +
>>> +		bridge_state->output_bus_cfg.flags = di->bus_flags;
>>> +		return 0;
>>> +	}
>>> +
>>> +	/*
>>> +	 * We expect output_bus_caps to contain at least one format. Note
>>> +	 * that don't care about bus format negotiation can simply not
>>> +	 * call this helper.  
>>
>> I'm not sure to parse the second sentence correctly.
> 
> Oops.
> 
> "Note that drivers that don't care about ...".
> I'm just trying to explain why EINVAL is returned when
> ->output_bus_caps is not populated.
> 
>>
>>> +	 */
>>> +	if (!self->output_bus_caps.num_supported_fmts ||!  
>>
>> Extra ! at the end of the line ?
>>
>>> +	    !self->output_bus_caps.supported_fmts)
>>> +		return -EINVAL;
>>> +
>>> +	next_bridge_state = drm_atomic_get_new_bridge_state(state, next);
>>> +
>>> +	/*
>>> +	 * The next bridge is expected to have called
>>> +	 * &drm_atomic_bridge_choose_input_bus_cfg() as part of its
>>> +	 * &drm_bridge_funcs.atomic_check() implementation, but this hook is
>>> +	 * optional, and even if it's implemented, calling
>>> +	 * &drm_atomic_bridge_choose_input_bus_cfg() is not mandated.
>>> +	 * If fmt is zero, that means the next element in the chain doesn't
>>> +	 * care about bus format negotiation (probably because there's only
>>> +	 * one possible setting). In that case, we still have to select one
>>> +	 * bus format for the output port of our bridge, and this is only
>>> +	 * possible if the bridge supports only one format.  
>>
>> Theoritically we could also just pick the first one (or actually any of
>> the supported formats), couldn't we ?
> 
> Hm, not really. I mean, if the bridge supports several output formats,
> there's no way we can tell which one is the right one for this
> specific setup. The idea being that drivers are responsible for picking
> an appropriate output bus-format based on something else (DT prop?)
> when drm_atomic_bridge_choose_output_bus_cfg() returns an error.
> 
>>
>>
>>> +	 */
>>> +	fmt = next_bridge_state->input_bus_cfg.fmt;
>>> +	if (fmt) {
>>> +		unsigned int i;
>>> +
>>> +		for (i = 0; i < self->output_bus_caps.num_supported_fmts; i++) {
>>> +			if (self->output_bus_caps.supported_fmts[i] == fmt)
>>> +				break;
>>> +		}
>>> +
>>> +		if (i == self->output_bus_caps.num_supported_fmts)
>>> +			return -ENOTSUPP;
>>> +	} else if (self->output_bus_caps.num_supported_fmts == 1) {
>>> +		fmt = self->output_bus_caps.supported_fmts[0];
>>> +	} else {
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	/*
>>> +	 * TODO:
>>> +	 * Should we fill/check the ->flag field too?
>>> +	 */
>>> +	bridge_state->output_bus_cfg.fmt = fmt;
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL(drm_atomic_bridge_choose_output_bus_cfg);
>>> +
>>>  static int drm_atomic_bridge_check(struct drm_bridge *bridge,
>>>  				   struct drm_crtc_state *crtc_state,
>>>  				   struct drm_connector_state *conn_state)
>>> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
>>> index 2f69adb7b0f3..c578800a05e0 100644
>>> --- a/include/drm/drm_bridge.h
>>> +++ b/include/drm/drm_bridge.h
>>> @@ -33,15 +33,45 @@ struct drm_bridge;
>>>  struct drm_bridge_timings;
>>>  struct drm_panel;
>>>  
>>> +/**
>>> + * struct drm_bus_cfg - bus configuration
>>> + * @fmt: format used on this bus
>>> + * @flags: DRM_BUS_ flags used on this bus
>>> + *
>>> + * Encodes the bus format and bus flags used by one end of the bridge or
>>> + * by the encoder output.
>>> + */
>>> +struct drm_bus_cfg {
>>> +	u32 fmt;
>>> +	u32 flags;
>>> +};
>>> +
>>> +/**
>>> + * struct drm_bus_caps - bus capabilities
>>> + * @supported_fmts: array of MEDIA_BUS_FMT_ formats
>>> + * @num_supported_fmts: size of the supported_fmts array
>>> + *
>>> + * Used by the core to negotiate the bus format at runtime.
>>> + */
>>> +struct drm_bus_caps {
>>> +	const u32 *supported_fmts;
>>> +	unsigned int num_supported_fmts;
>>> +};
>>> +
>>>  /**
>>>   * struct drm_bridge_state - Atomic bridge state object
>>>   * @base: inherit from &drm_private_state
>>>   * @bridge: the bridge this state refers to
>>> + * @input_bus_info: input bus information
>>> + * @output_bus_info: output bus information  
>>
>> I would make this an array, to prepare for bridges that will have more
>> than one input or one output.
> 
> Hm, not sure how you'd represent that. I guess you want to support
> bridges that can activate several inputs+outputs in parallel. Do we
> even support that right now?
> Also, how do we link the input to the output in that case? By their
> position in the array? And we'd need an extra field in bus_caps to
> point to the corresponding bridge input/output port.
> 
> I'm glad we can discuss all those problems, but I'd like to focus on
> what's needed right now, not what could potentially be needed in the
> future. If we can design things to be more future-proof that's great,
> but in my experience, trying to solve problems that do not exist yet
> often leads to complex designs which prove to be wrong when we try to
> apply them to real situations when they finally occur.

I had a thought when implementing bus format negotiation for dw-hdmi.

Depending on the output bus-format, we could have different sets of possible
input drm_bus_caps.

For example, if output is MEDIA_BUS_FMT_RGB888_1X24,
the input bus formats could only be MEDIA_BUS_FMT_RGB888_1X24 or MEDIA_BUS_FMT_YUV8_1X24.
Same for MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_RGB121212_1X36, MEDIA_BUS_FMT_RGB161616_1X48...
And the special MEDIA_BUS_FMT_UYYVYY8_0_5X24, where input must be output.

How could we handle this ? I mean, could we have a fixed
output drm_bus_caps and be able to dynamically change the input drm_bus_caps ?

Adding matrix in struct drm_bridge seems over-engineered, no ? Since it should take
in account the actual drm_display_mode.

Maybe by passing a dynamic input drm_bus_caps to drm_atomic_bridge_choose_input_bus_cfg()
and take the default struct drm_bridge one if not provided ?
This would really simplify the bridge atomic_check implementation by reusing
the drm_atomic_bridge_choose_*() functions.

Neil

> 
>>
>>>   */
>>>  struct drm_bridge_state {
>>>  	struct drm_private_state base;
>>>  
>>>  	struct drm_bridge *bridge;
>>> +
>>> +	struct drm_bus_cfg input_bus_cfg;
>>> +	struct drm_bus_cfg output_bus_cfg;
>>>  };
>>>  
>>>  static inline struct drm_bridge_state *
>>> @@ -465,6 +495,9 @@ struct drm_bridge {
>>>  	const struct drm_bridge_funcs *funcs;
>>>  	/** @driver_private: pointer to the bridge driver's internal context */
>>>  	void *driver_private;
>>> +
>>> +	struct drm_bus_caps input_bus_caps;
>>> +	struct drm_bus_caps output_bus_caps;
>>>  };
>>>  
>>>  static inline struct drm_bridge *
>>> @@ -479,6 +512,14 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
>>>  int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
>>>  		      struct drm_bridge *previous);
>>>  
>>> +int
>>> +drm_atomic_bridge_choose_input_bus_cfg(struct drm_bridge_state *bridge_state,
>>> +				       struct drm_crtc_state *crtc_state,
>>> +				       struct drm_connector_state *conn_state);
>>> +int
>>> +drm_atomic_bridge_choose_output_bus_cfg(struct drm_bridge_state *bridge_state,
>>> 					struct drm_crtc_state *crtc_state,
>>> +					struct drm_connector_state *conn_state);
>>>  struct drm_bridge *
>>>  drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder);
>>>  struct drm_bridge *
>>> @@ -562,6 +603,11 @@ drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
>>>  	return drm_priv_to_bridge_state(obj_state);
>>>  }
>>>  
>>> +int drm_find_best_bus_format(const struct drm_bus_caps *a,
>>> +			     const struct drm_bus_caps *b,
>>> +			     const struct drm_display_mode *mode,
>>> +			     u32 *selected_bus_fmt);
>>> +
>>>  #ifdef CONFIG_DRM_PANEL_BRIDGE
>>>  struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
>>>  					u32 connector_type);
>>> diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
>>> index 0899f7f34e3a..e891921b3aed 100644
>>> --- a/include/drm/drm_encoder.h
>>> +++ b/include/drm/drm_encoder.h
>>> @@ -25,6 +25,7 @@
>>>  
>>>  #include <linux/list.h>
>>>  #include <linux/ctype.h>
>>> +#include <drm/drm_bridge.h>
>>>  #include <drm/drm_crtc.h>
>>>  #include <drm/drm_mode.h>
>>>  #include <drm/drm_mode_object.h>
>>> @@ -184,6 +185,11 @@ struct drm_encoder {
>>>  	 * functions as part of its encoder enable/disable handling.
>>>  	 */
>>>  	uint32_t custom_bridge_enable_disable_seq : 1;
>>> +
>>> +	/**
>>> +	 * @output_bus_caps: Supported output bus caps
>>> +	 */
>>> +	struct drm_bus_caps output_bus_caps;
>>>  };
>>>  
>>>  #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
>>>   
>>
> 

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

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

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-22  9:29       ` Neil Armstrong
@ 2019-08-22 10:09         ` Boris Brezillon
  2019-08-22 10:22           ` Neil Armstrong
  0 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22 10:09 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Jernej Skrabec, Jonas Karlman, Seung-Woo Kim, dri-devel,
	Kyungmin Park, Thierry Reding, Chris Healy, kernel, Sam Ravnborg,
	Laurent Pinchart

On Thu, 22 Aug 2019 11:29:40 +0200
Neil Armstrong <narmstrong@baylibre.com> wrote:

> >>> +/**
> >>> + * struct drm_bus_caps - bus capabilities
> >>> + * @supported_fmts: array of MEDIA_BUS_FMT_ formats
> >>> + * @num_supported_fmts: size of the supported_fmts array
> >>> + *
> >>> + * Used by the core to negotiate the bus format at runtime.
> >>> + */
> >>> +struct drm_bus_caps {
> >>> +	const u32 *supported_fmts;
> >>> +	unsigned int num_supported_fmts;
> >>> +};
> >>> +
> >>>  /**
> >>>   * struct drm_bridge_state - Atomic bridge state object
> >>>   * @base: inherit from &drm_private_state
> >>>   * @bridge: the bridge this state refers to
> >>> + * @input_bus_info: input bus information
> >>> + * @output_bus_info: output bus information    
> >>
> >> I would make this an array, to prepare for bridges that will have more
> >> than one input or one output.  
> > 
> > Hm, not sure how you'd represent that. I guess you want to support
> > bridges that can activate several inputs+outputs in parallel. Do we
> > even support that right now?
> > Also, how do we link the input to the output in that case? By their
> > position in the array? And we'd need an extra field in bus_caps to
> > point to the corresponding bridge input/output port.
> > 
> > I'm glad we can discuss all those problems, but I'd like to focus on
> > what's needed right now, not what could potentially be needed in the
> > future. If we can design things to be more future-proof that's great,
> > but in my experience, trying to solve problems that do not exist yet
> > often leads to complex designs which prove to be wrong when we try to
> > apply them to real situations when they finally occur.  
> 
> I had a thought when implementing bus format negotiation for dw-hdmi.
> 
> Depending on the output bus-format, we could have different sets of possible
> input drm_bus_caps.
> 
> For example, if output is MEDIA_BUS_FMT_RGB888_1X24,
> the input bus formats could only be MEDIA_BUS_FMT_RGB888_1X24 or MEDIA_BUS_FMT_YUV8_1X24.
> Same for MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_RGB121212_1X36, MEDIA_BUS_FMT_RGB161616_1X48...
> And the special MEDIA_BUS_FMT_UYYVYY8_0_5X24, where input must be output.

Sounds exactly like what Laurent was describing.

> 
> How could we handle this ? I mean, could we have a fixed
> output drm_bus_caps and be able to dynamically change the input drm_bus_caps ?

If all output ends of bridges have fixed formats (meaning that
something sets it to a fixed value, like a DT prop), there's no need
for negotiation at all, since the output of the previous element in
the chain will force input format of the current element.

> 
> Adding matrix in struct drm_bridge seems over-engineered, no ?

Will have to try it to give an answer to that question :).

> Since it should take
> in account the actual drm_display_mode.

Taking the display_mode into account is yet another thing, though it
might impact the way we want to handle bus-format negotiation. The way
I see it, we have 2 issues to solve:

1/ make sure the atomic modeset does not fail if there's at least one
   bus-format combination that works (this is what the
   supported-transcoding matrix is for)
2/ make sure that we pick the best option among all the possibilities.
   That requires defining what 'best' means. In some cases you might
   want to reduce power-consumption/bandwidth in others you might want
   to preserve image-quality (relative to the selected mode of course)

I decided to ignore problem #2 for now, but that's definitely something
we should work on at some point. Problem #1 is a problem we should
solve now. If we find a solution that solves both it's even better :-).

> 
> Maybe by passing a dynamic input drm_bus_caps to drm_atomic_bridge_choose_input_bus_cfg()
> and take the default struct drm_bridge one if not provided ?

IIUC, you propose to restrict the set of input formats based on the
selected output format from inside the driver ->atomic_check()
implementation. That's basically like open-coding the
supported-transcoding matrix: you'll have to have a list of supported
input formats for each output format (or set of output formats), right?

Note that we could implement the supported-transcoding thing with a hook
instead of a matrix, but, no matter the solution we pick, it will always
be something that can answer this question "is bridge X able to convert
input format A into output format B?".

The nice thing about having the transcoding matrix calculated at attach
time is that you reject combinations that are not possible early instead
of having to do this work at each atomic_check(). Also, if you're not
rejecting impossible combinations early, I think you still have the
problem Laurent was talking about when you have more than 2 elements in
the chain.

> This would really simplify the bridge atomic_check implementation by reusing
> the drm_atomic_bridge_choose_*() functions.
> 

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

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

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-22 10:09         ` Boris Brezillon
@ 2019-08-22 10:22           ` Neil Armstrong
  2019-08-22 10:34             ` Boris Brezillon
  0 siblings, 1 reply; 58+ messages in thread
From: Neil Armstrong @ 2019-08-22 10:22 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Jonas Karlman, Seung-Woo Kim, dri-devel,
	Kyungmin Park, Thierry Reding, Chris Healy, kernel, Sam Ravnborg,
	Laurent Pinchart

On 22/08/2019 12:09, Boris Brezillon wrote:
> On Thu, 22 Aug 2019 11:29:40 +0200
> Neil Armstrong <narmstrong@baylibre.com> wrote:
> 
>>>>> +/**
>>>>> + * struct drm_bus_caps - bus capabilities
>>>>> + * @supported_fmts: array of MEDIA_BUS_FMT_ formats
>>>>> + * @num_supported_fmts: size of the supported_fmts array
>>>>> + *
>>>>> + * Used by the core to negotiate the bus format at runtime.
>>>>> + */
>>>>> +struct drm_bus_caps {
>>>>> +	const u32 *supported_fmts;
>>>>> +	unsigned int num_supported_fmts;
>>>>> +};
>>>>> +
>>>>>  /**
>>>>>   * struct drm_bridge_state - Atomic bridge state object
>>>>>   * @base: inherit from &drm_private_state
>>>>>   * @bridge: the bridge this state refers to
>>>>> + * @input_bus_info: input bus information
>>>>> + * @output_bus_info: output bus information    
>>>>
>>>> I would make this an array, to prepare for bridges that will have more
>>>> than one input or one output.  
>>>
>>> Hm, not sure how you'd represent that. I guess you want to support
>>> bridges that can activate several inputs+outputs in parallel. Do we
>>> even support that right now?
>>> Also, how do we link the input to the output in that case? By their
>>> position in the array? And we'd need an extra field in bus_caps to
>>> point to the corresponding bridge input/output port.
>>>
>>> I'm glad we can discuss all those problems, but I'd like to focus on
>>> what's needed right now, not what could potentially be needed in the
>>> future. If we can design things to be more future-proof that's great,
>>> but in my experience, trying to solve problems that do not exist yet
>>> often leads to complex designs which prove to be wrong when we try to
>>> apply them to real situations when they finally occur.  
>>
>> I had a thought when implementing bus format negotiation for dw-hdmi.
>>
>> Depending on the output bus-format, we could have different sets of possible
>> input drm_bus_caps.
>>
>> For example, if output is MEDIA_BUS_FMT_RGB888_1X24,
>> the input bus formats could only be MEDIA_BUS_FMT_RGB888_1X24 or MEDIA_BUS_FMT_YUV8_1X24.
>> Same for MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_RGB121212_1X36, MEDIA_BUS_FMT_RGB161616_1X48...
>> And the special MEDIA_BUS_FMT_UYYVYY8_0_5X24, where input must be output.
> 
> Sounds exactly like what Laurent was describing.
> 
>>
>> How could we handle this ? I mean, could we have a fixed
>> output drm_bus_caps and be able to dynamically change the input drm_bus_caps ?
> 
> If all output ends of bridges have fixed formats (meaning that
> something sets it to a fixed value, like a DT prop), there's no need
> for negotiation at all, since the output of the previous element in
> the chain will force input format of the current element.
> 
>>
>> Adding matrix in struct drm_bridge seems over-engineered, no ?
> 
> Will have to try it to give an answer to that question :).

Another thought, I was thinking about a matrix with an optional callback checking
is this particular matrix line is possible, an example :

struct drm_bridge_bus_fmt_assoc dw_hdmi_bus_fmt_matrix[] = {
	{ MEDIA_BUS_FMT_RGB888_1X24,
		{MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24, 0},
		{dw_hdmi_bus_fmt_no_yuv420_check, NULL},
	},
	{ MEDIA_BUS_FMT_YUV8_1X24,
		{MEDIA_BUS_FMT_YUV8_1X24, 0},
		{dw_hdmi_bus_fmt_no_yuv420_check,
		 dw_hdmi_bus_fmt_yuv444_check,
		 NULL},
	},
	{ MEDIA_BUS_FMT_RGB101010_1X30,
		{MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_YUV10_1X30, 0},
		{dw_hdmi_bus_fmt_no_yuv420_check,
		 dw_hdmi_bus_fmt_rgb_10bit_check,
		 NULL},
	},
	{ MEDIA_BUS_FMT_UYYVYY8_0_5X24,
		{MEDIA_BUS_FMT_UYYVYY8_0_5X24, 0},
		dw_hdmi_bus_fmt_yuv420_check,
	},
	{ MEDIA_BUS_FMT_UYYVYY10_0_5X30,
		{MEDIA_BUS_FMT_UYYVYY8_0_5X24, 0},
		{dw_hdmi_bus_fmt_yuv420_check,
		 dw_hdmi_bus_fmt_yuv420_10bit_check,
		 NULL},
	},
};

Or with some flags combinations to check on the mode and some on the edid ?

Neil

> 
>> Since it should take
>> in account the actual drm_display_mode.
> 
> Taking the display_mode into account is yet another thing, though it
> might impact the way we want to handle bus-format negotiation. The way
> I see it, we have 2 issues to solve:
> 
> 1/ make sure the atomic modeset does not fail if there's at least one
>    bus-format combination that works (this is what the
>    supported-transcoding matrix is for)
> 2/ make sure that we pick the best option among all the possibilities.
>    That requires defining what 'best' means. In some cases you might
>    want to reduce power-consumption/bandwidth in others you might want
>    to preserve image-quality (relative to the selected mode of course)
> 
> I decided to ignore problem #2 for now, but that's definitely something
> we should work on at some point. Problem #1 is a problem we should
> solve now. If we find a solution that solves both it's even better :-).
> 
>>
>> Maybe by passing a dynamic input drm_bus_caps to drm_atomic_bridge_choose_input_bus_cfg()
>> and take the default struct drm_bridge one if not provided ?
> 
> IIUC, you propose to restrict the set of input formats based on the
> selected output format from inside the driver ->atomic_check()
> implementation. That's basically like open-coding the
> supported-transcoding matrix: you'll have to have a list of supported
> input formats for each output format (or set of output formats), right?
> 
> Note that we could implement the supported-transcoding thing with a hook
> instead of a matrix, but, no matter the solution we pick, it will always
> be something that can answer this question "is bridge X able to convert
> input format A into output format B?".
> 
> The nice thing about having the transcoding matrix calculated at attach
> time is that you reject combinations that are not possible early instead
> of having to do this work at each atomic_check(). Also, if you're not
> rejecting impossible combinations early, I think you still have the
> problem Laurent was talking about when you have more than 2 elements in
> the chain.
> 
>> This would really simplify the bridge atomic_check implementation by reusing
>> the drm_atomic_bridge_choose_*() functions.
>>
> 

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

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

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-22 10:22           ` Neil Armstrong
@ 2019-08-22 10:34             ` Boris Brezillon
  2019-08-22 11:30               ` Neil Armstrong
  0 siblings, 1 reply; 58+ messages in thread
From: Boris Brezillon @ 2019-08-22 10:34 UTC (permalink / raw)
  To: Neil Armstrong, Jernej Skrabec
  Cc: Jonas Karlman, Seung-Woo Kim, dri-devel, Kyungmin Park,
	Thierry Reding, Chris Healy, kernel, Sam Ravnborg,
	Laurent Pinchart

On Thu, 22 Aug 2019 12:22:02 +0200
Neil Armstrong <narmstrong@baylibre.com> wrote:

> On 22/08/2019 12:09, Boris Brezillon wrote:
> > On Thu, 22 Aug 2019 11:29:40 +0200
> > Neil Armstrong <narmstrong@baylibre.com> wrote:
> >   
> >>>>> +/**
> >>>>> + * struct drm_bus_caps - bus capabilities
> >>>>> + * @supported_fmts: array of MEDIA_BUS_FMT_ formats
> >>>>> + * @num_supported_fmts: size of the supported_fmts array
> >>>>> + *
> >>>>> + * Used by the core to negotiate the bus format at runtime.
> >>>>> + */
> >>>>> +struct drm_bus_caps {
> >>>>> +	const u32 *supported_fmts;
> >>>>> +	unsigned int num_supported_fmts;
> >>>>> +};
> >>>>> +
> >>>>>  /**
> >>>>>   * struct drm_bridge_state - Atomic bridge state object
> >>>>>   * @base: inherit from &drm_private_state
> >>>>>   * @bridge: the bridge this state refers to
> >>>>> + * @input_bus_info: input bus information
> >>>>> + * @output_bus_info: output bus information      
> >>>>
> >>>> I would make this an array, to prepare for bridges that will have more
> >>>> than one input or one output.    
> >>>
> >>> Hm, not sure how you'd represent that. I guess you want to support
> >>> bridges that can activate several inputs+outputs in parallel. Do we
> >>> even support that right now?
> >>> Also, how do we link the input to the output in that case? By their
> >>> position in the array? And we'd need an extra field in bus_caps to
> >>> point to the corresponding bridge input/output port.
> >>>
> >>> I'm glad we can discuss all those problems, but I'd like to focus on
> >>> what's needed right now, not what could potentially be needed in the
> >>> future. If we can design things to be more future-proof that's great,
> >>> but in my experience, trying to solve problems that do not exist yet
> >>> often leads to complex designs which prove to be wrong when we try to
> >>> apply them to real situations when they finally occur.    
> >>
> >> I had a thought when implementing bus format negotiation for dw-hdmi.
> >>
> >> Depending on the output bus-format, we could have different sets of possible
> >> input drm_bus_caps.
> >>
> >> For example, if output is MEDIA_BUS_FMT_RGB888_1X24,
> >> the input bus formats could only be MEDIA_BUS_FMT_RGB888_1X24 or MEDIA_BUS_FMT_YUV8_1X24.
> >> Same for MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_RGB121212_1X36, MEDIA_BUS_FMT_RGB161616_1X48...
> >> And the special MEDIA_BUS_FMT_UYYVYY8_0_5X24, where input must be output.  
> > 
> > Sounds exactly like what Laurent was describing.
> >   
> >>
> >> How could we handle this ? I mean, could we have a fixed
> >> output drm_bus_caps and be able to dynamically change the input drm_bus_caps ?  
> > 
> > If all output ends of bridges have fixed formats (meaning that
> > something sets it to a fixed value, like a DT prop), there's no need
> > for negotiation at all, since the output of the previous element in
> > the chain will force input format of the current element.
> >   
> >>
> >> Adding matrix in struct drm_bridge seems over-engineered, no ?  
> > 
> > Will have to try it to give an answer to that question :).  
> 
> Another thought, I was thinking about a matrix with an optional callback checking
> is this particular matrix line is possible, an example :
> 
> struct drm_bridge_bus_fmt_assoc dw_hdmi_bus_fmt_matrix[] = {
> 	{ MEDIA_BUS_FMT_RGB888_1X24,
> 		{MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24, 0},
> 		{dw_hdmi_bus_fmt_no_yuv420_check, NULL},
> 	},
> 	{ MEDIA_BUS_FMT_YUV8_1X24,
> 		{MEDIA_BUS_FMT_YUV8_1X24, 0},
> 		{dw_hdmi_bus_fmt_no_yuv420_check,
> 		 dw_hdmi_bus_fmt_yuv444_check,
> 		 NULL},
> 	},
> 	{ MEDIA_BUS_FMT_RGB101010_1X30,
> 		{MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_YUV10_1X30, 0},
> 		{dw_hdmi_bus_fmt_no_yuv420_check,
> 		 dw_hdmi_bus_fmt_rgb_10bit_check,
> 		 NULL},
> 	},
> 	{ MEDIA_BUS_FMT_UYYVYY8_0_5X24,
> 		{MEDIA_BUS_FMT_UYYVYY8_0_5X24, 0},
> 		dw_hdmi_bus_fmt_yuv420_check,
> 	},
> 	{ MEDIA_BUS_FMT_UYYVYY10_0_5X30,
> 		{MEDIA_BUS_FMT_UYYVYY8_0_5X24, 0},
> 		{dw_hdmi_bus_fmt_yuv420_check,
> 		 dw_hdmi_bus_fmt_yuv420_10bit_check,
> 		 NULL},
> 	},
> };
> 
> Or with some flags combinations to check on the mode and some on the edid ?

Okay, so you need to check/reject bus-formats at runtime (the mode is
not known at attach time). Do you have an idea of what would be checked
in those hooks?

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

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

* Re: [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation
  2019-08-22 10:34             ` Boris Brezillon
@ 2019-08-22 11:30               ` Neil Armstrong
  0 siblings, 0 replies; 58+ messages in thread
From: Neil Armstrong @ 2019-08-22 11:30 UTC (permalink / raw)
  To: Boris Brezillon, Jernej Skrabec
  Cc: Jonas Karlman, Seung-Woo Kim, dri-devel, Kyungmin Park,
	Thierry Reding, Chris Healy, kernel, Sam Ravnborg,
	Laurent Pinchart

On 22/08/2019 12:34, Boris Brezillon wrote:
> On Thu, 22 Aug 2019 12:22:02 +0200
> Neil Armstrong <narmstrong@baylibre.com> wrote:
> 
>> On 22/08/2019 12:09, Boris Brezillon wrote:
>>> On Thu, 22 Aug 2019 11:29:40 +0200
>>> Neil Armstrong <narmstrong@baylibre.com> wrote:
>>>   
>>>>>>> +/**
>>>>>>> + * struct drm_bus_caps - bus capabilities
>>>>>>> + * @supported_fmts: array of MEDIA_BUS_FMT_ formats
>>>>>>> + * @num_supported_fmts: size of the supported_fmts array
>>>>>>> + *
>>>>>>> + * Used by the core to negotiate the bus format at runtime.
>>>>>>> + */
>>>>>>> +struct drm_bus_caps {
>>>>>>> +	const u32 *supported_fmts;
>>>>>>> +	unsigned int num_supported_fmts;
>>>>>>> +};
>>>>>>> +
>>>>>>>  /**
>>>>>>>   * struct drm_bridge_state - Atomic bridge state object
>>>>>>>   * @base: inherit from &drm_private_state
>>>>>>>   * @bridge: the bridge this state refers to
>>>>>>> + * @input_bus_info: input bus information
>>>>>>> + * @output_bus_info: output bus information      
>>>>>>
>>>>>> I would make this an array, to prepare for bridges that will have more
>>>>>> than one input or one output.    
>>>>>
>>>>> Hm, not sure how you'd represent that. I guess you want to support
>>>>> bridges that can activate several inputs+outputs in parallel. Do we
>>>>> even support that right now?
>>>>> Also, how do we link the input to the output in that case? By their
>>>>> position in the array? And we'd need an extra field in bus_caps to
>>>>> point to the corresponding bridge input/output port.
>>>>>
>>>>> I'm glad we can discuss all those problems, but I'd like to focus on
>>>>> what's needed right now, not what could potentially be needed in the
>>>>> future. If we can design things to be more future-proof that's great,
>>>>> but in my experience, trying to solve problems that do not exist yet
>>>>> often leads to complex designs which prove to be wrong when we try to
>>>>> apply them to real situations when they finally occur.    
>>>>
>>>> I had a thought when implementing bus format negotiation for dw-hdmi.
>>>>
>>>> Depending on the output bus-format, we could have different sets of possible
>>>> input drm_bus_caps.
>>>>
>>>> For example, if output is MEDIA_BUS_FMT_RGB888_1X24,
>>>> the input bus formats could only be MEDIA_BUS_FMT_RGB888_1X24 or MEDIA_BUS_FMT_YUV8_1X24.
>>>> Same for MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_RGB121212_1X36, MEDIA_BUS_FMT_RGB161616_1X48...
>>>> And the special MEDIA_BUS_FMT_UYYVYY8_0_5X24, where input must be output.  
>>>
>>> Sounds exactly like what Laurent was describing.
>>>   
>>>>
>>>> How could we handle this ? I mean, could we have a fixed
>>>> output drm_bus_caps and be able to dynamically change the input drm_bus_caps ?  
>>>
>>> If all output ends of bridges have fixed formats (meaning that
>>> something sets it to a fixed value, like a DT prop), there's no need
>>> for negotiation at all, since the output of the previous element in
>>> the chain will force input format of the current element.
>>>   
>>>>
>>>> Adding matrix in struct drm_bridge seems over-engineered, no ?  
>>>
>>> Will have to try it to give an answer to that question :).  
>>
>> Another thought, I was thinking about a matrix with an optional callback checking
>> is this particular matrix line is possible, an example :
>>
>> struct drm_bridge_bus_fmt_assoc dw_hdmi_bus_fmt_matrix[] = {
>> 	{ MEDIA_BUS_FMT_RGB888_1X24,
>> 		{MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24, 0},
>> 		{dw_hdmi_bus_fmt_no_yuv420_check, NULL},
>> 	},
>> 	{ MEDIA_BUS_FMT_YUV8_1X24,
>> 		{MEDIA_BUS_FMT_YUV8_1X24, 0},
>> 		{dw_hdmi_bus_fmt_no_yuv420_check,
>> 		 dw_hdmi_bus_fmt_yuv444_check,
>> 		 NULL},
>> 	},
>> 	{ MEDIA_BUS_FMT_RGB101010_1X30,
>> 		{MEDIA_BUS_FMT_RGB101010_1X30, MEDIA_BUS_FMT_YUV10_1X30, 0},
>> 		{dw_hdmi_bus_fmt_no_yuv420_check,
>> 		 dw_hdmi_bus_fmt_rgb_10bit_check,
>> 		 NULL},
>> 	},
>> 	{ MEDIA_BUS_FMT_UYYVYY8_0_5X24,
>> 		{MEDIA_BUS_FMT_UYYVYY8_0_5X24, 0},
>> 		dw_hdmi_bus_fmt_yuv420_check,
>> 	},
>> 	{ MEDIA_BUS_FMT_UYYVYY10_0_5X30,
>> 		{MEDIA_BUS_FMT_UYYVYY8_0_5X24, 0},
>> 		{dw_hdmi_bus_fmt_yuv420_check,
>> 		 dw_hdmi_bus_fmt_yuv420_10bit_check,
>> 		 NULL},
>> 	},
>> };
>>
>> Or with some flags combinations to check on the mode and some on the edid ?
> 
> Okay, so you need to check/reject bus-formats at runtime (the mode is
> not known at attach time). Do you have an idea of what would be checked
> in those hooks?
> 

The output bus format is dependent on the mode (drm_mode_is_420_only() and drm_mode_is_420_also())
and the display info(info->hdmi.scdc.supported, info->bpc and info->color_formats).

dw_hdmi_bus_fmt_yuv420_check would check :
drm_mode_is_420_only(info, mode) || (!info->hdmi.scdc.supported && drm_mode_is_420_also(info, mode))
and if encoder supports the corresponding input mode

dw_hdmi_bus_fmt_no_yuv420_check would be reverse.

dw_hdmi_bus_fmt_yuv444_check would check :
info->color_formats & DRM_COLOR_FORMAT_YCRCB444
and if encoder supports the corresponding input mode

dw_hdmi_bus_fmt_rgb_10bit_check would check:
info->bpc >= 10
and if encoder supports the corresponding input mode

10/12/16 bit selection is best-effort (at least how intel implemented it), this means
we would put the 16/12/10bits bus-formats first and 8bit last.

Same for YUV vs RGB, we should select YUV first if encoder supports it, otherwise RGB.

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

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

* Re: [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object
  2019-08-22  9:00     ` Boris Brezillon
@ 2019-12-02 15:52       ` Laurent Pinchart
  0 siblings, 0 replies; 58+ messages in thread
From: Laurent Pinchart @ 2019-12-02 15:52 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jernej Skrabec, Jonas Karlman, Neil Armstrong, Seung-Woo Kim,
	dri-devel, Kyungmin Park, Thierry Reding, Chris Healy, kernel,
	Sam Ravnborg

Hi Boris,

On Thu, Aug 22, 2019 at 11:00:56AM +0200, Boris Brezillon wrote:
> On Wed, 21 Aug 2019 23:14:56 +0300 Laurent Pinchart wrote:
> 
> > > +int
> > > +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
> > > +			       struct drm_encoder *encoder)
> > > +{
> > > +	struct drm_bridge_state *bridge_state;
> > > +	struct drm_bridge *bridge;
> > > +
> > > +	if (!encoder)
> > > +		return 0;
> > > +
> > > +	DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n",
> > > +			 encoder->base.id, encoder->name, state);
> > > +
> > > +	for (bridge = drm_bridge_chain_get_first_bridge(encoder); bridge;
> > > +	     bridge = drm_bridge_chain_get_next_bridge(bridge)) {  
> > 
> > Would a for_each_bridge() macro make sense ? I'd implement it on top of
> > list_for_each_entry() to make it simple.
> 
> I can add this helper. Note that for_each_bridge() will iterate over
> the whole bridge chain, and we might need a for_each_bridge_from() at
> some point if we want to iterate over a sub-chain.
> 
> > > +		bridge_state = drm_atomic_get_bridge_state(state, bridge);
> > > +		if (IS_ERR(bridge_state))
> > > +			return PTR_ERR(bridge_state);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
> 
> [...]
> 
> > > +/**
> > > + * drm_atomic_helper_init_bridge_state() - Initializes a bridge state  
> > 
> > s/Initializes/Initialize/
> > 
> > > + * @bridge this state is referring to  
> > 
> > Did you mean
> > 
> >  * @bridge: the bridge this state is referring to ?
> 
> Yes.
> 
> > > + * @state: bridge state to initialize
> > > + *
> > > + * For now it's just a memset(0) plus a state->bridge assignment. Might
> > > + * be extended in the future.
> > > + */
> > > +void drm_atomic_helper_init_bridge_state(struct drm_bridge *bridge,
> > > +					 struct drm_bridge_state *state)
> > > +{
> > > +	memset(state, 0, sizeof(*state));
> > > +	state->bridge = bridge;
> > > +}
> > > +EXPORT_SYMBOL(drm_atomic_helper_init_bridge_state);  
> > 
> > Other objects don't export a state init function helper, but state reset
> > and state duplicate helpers. Is there a reason to depart from that model
> > ? Same for the copy helper below.
> 
> I thought those names better reflect what the helpers do.
> __drm_atomic_helper_crtc_duplicate_state() for instance, it actually
> does not duplicate the state, but just copies current state info into
> the new state object which has been allocated by the caller. Same for
> the reset helpers, they actually do not reset anything but just
> initialize the state to a default. I also try to avoid prefixing
> functions with __ when I can (names can be clarified/extended to avoid
> conflicts most of the time).
> Will switch back to reset/dup names if you prefer.

I think consistency would help. Regarding the reset operation, unless
I'm mistaken, it got its name from the fact that it should create a
software state that reflects the current hardware state, in order to
support fastboot (taking over a running display controller started by
the boot loader without causing any glitch). That being said, I'm not
sure reset was the best name even for that :-)

> > > +
> > > +/**
> > > + * drm_atomic_helper_copy_bridge_state() - Copy the content of a bridge state
> > > + * @bridge: bridge the old and new state are referring to
> > > + * @old: previous bridge state to copy from
> > > + * @new: new bridge state to copy to
> > > + *
> > > + * Should be used by custom &drm_bridge_funcs.atomic_duplicate() implementation
> > > + * to copy the previous state into the new object.
> > > + */
> > > +void drm_atomic_helper_copy_bridge_state(struct drm_bridge *bridge,
> > > +					 const struct drm_bridge_state *old,
> > > +					 struct drm_bridge_state *new)
> > > +{
> > > +	*new = *old;
> > > +}
> > > +EXPORT_SYMBOL(drm_atomic_helper_copy_bridge_state);
> > > +
> > > +/**
> > > + * drm_atomic_helper_duplicate_bridge_state() - Default duplicate state helper
> > > + * @bridge: bridge containing the state to duplicate
> > > + *
> > > + * Default implementation of &drm_bridge_funcs.atomic_duplicate().
> > > + *
> > > + * RETURNS:
> > > + * a valid state object or NULL if the allocation fails.
> > > + */
> > > +struct drm_bridge_state *
> > > +drm_atomic_helper_duplicate_bridge_state(struct drm_bridge *bridge)
> > > +{
> > > +	struct drm_bridge_state *old = NULL, *new;
> > > +
> > > +	new = kzalloc(sizeof(*new), GFP_KERNEL);
> > > +	if (!new)
> > > +		return NULL;
> > > +
> > > +	if (bridge->base.state) {
> > > +		old = drm_priv_to_bridge_state(bridge->base.state);
> > > +		drm_atomic_helper_copy_bridge_state(bridge, old, new);
> > > +	} else {
> > > +		drm_atomic_helper_init_bridge_state(bridge, new);
> > > +	}
> > > +
> > > +	return new;
> > > +}
> > > +EXPORT_SYMBOL(drm_atomic_helper_duplicate_bridge_state);
> > > +
> > > +/**
> > > + * drm_atomic_helper_destroy_bridge_state() - Default destroy state helper
> > > + * @bridge: the bridge this state refers to
> > > + * @state: state object to destroy
> > > + *
> > > + * Just a simple kfree() for now.
> > > + */
> > > +void drm_atomic_helper_destroy_bridge_state(struct drm_bridge *bridge,
> > > +					    struct drm_bridge_state *state)
> > > +{
> > > +	kfree(state);
> > > +}
> > > +EXPORT_SYMBOL(drm_atomic_helper_destroy_bridge_state);
> > > +
> > >  #ifdef CONFIG_OF
> > >  /**
> > >   * of_drm_find_bridge - find the bridge corresponding to the device node in
> > > diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> > > index 927e1205d7aa..5ee25fd51e80 100644
> > > --- a/include/drm/drm_atomic.h
> > > +++ b/include/drm/drm_atomic.h
> > > @@ -660,6 +660,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
> > >  	return plane->state;
> > >  }
> > >  
> > > +int __must_check
> > > +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
> > > +                               struct drm_encoder *encoder);
> > >  int __must_check
> > >  drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
> > >  				   struct drm_crtc *crtc);
> > > diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> > > index f40181274ed7..8ca25d266d0c 100644
> > > --- a/include/drm/drm_bridge.h
> > > +++ b/include/drm/drm_bridge.h
> > > @@ -25,6 +25,7 @@
> > >  
> > >  #include <linux/list.h>
> > >  #include <linux/ctype.h>
> > > +#include <drm/drm_atomic.h>
> > >  #include <drm/drm_mode_object.h>
> > >  #include <drm/drm_modes.h>
> > >  
> > > @@ -32,6 +33,23 @@ struct drm_bridge;
> > >  struct drm_bridge_timings;
> > >  struct drm_panel;
> > >  
> > > +/**
> > > + * struct drm_bridge_state - Atomic bridge state object
> > > + * @base: inherit from &drm_private_state
> > > + * @bridge: the bridge this state refers to
> > > + */
> > > +struct drm_bridge_state {
> > > +	struct drm_private_state base;
> > > +
> > > +	struct drm_bridge *bridge;
> > > +};
> > > +
> > > +static inline struct drm_bridge_state *
> > > +drm_priv_to_bridge_state(struct drm_private_state *priv)
> > > +{
> > > +	return container_of(priv, struct drm_bridge_state, base);
> > > +}
> > > +
> > >  /**
> > >   * struct drm_bridge_funcs - drm_bridge control functions
> > >   */
> > > @@ -337,6 +355,30 @@ struct drm_bridge_funcs {
> > >  	 */
> > >  	void (*atomic_post_disable)(struct drm_bridge *bridge,
> > >  				    struct drm_atomic_state *state);
> > > +
> > > +	/**
> > > +	 * @atomic_duplicate_state:
> > > +	 *
> > > +	 * Duplicate the current bridge state object.
> > > +	 *
> > > +	 * Note that this function can be called when current bridge state is
> > > +	 * NULL. In this case, implementations should either implement HW
> > > +	 * readback or initialize the state with sensible default values.  
> > 
> > Related to the question above, shouldn't we have a reset state operation
> > instead ?
> 
> I had a version with a reset hook and a helper that was falling back to
> ->duplicate_state() when not specified, but I decided to drop it to
> simplify things (I think most drivers will just use the default
> helper, and those that actually want to implement HW readback can
> easily do it from their ->duplicate_state() hook by testing
> bridge->state value).
> I can re-introduce it if you like.

It would help with consistency, but I'll leave that to you.

-- 
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] 58+ messages in thread

end of thread, other threads:[~2019-12-02 15:52 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-08 15:11 [PATCH RFC 00/19] drm: Add support for bus-format negotiation Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 01/19] drm: Stop including drm_bridge.h from drm_crtc.h Boris Brezillon
2019-08-08 18:05   ` Sam Ravnborg
2019-08-20 18:53   ` Laurent Pinchart
2019-08-21 15:44     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 02/19] drm: Support custom encoder/bridge enable/disable sequences officially Boris Brezillon
2019-08-20 19:05   ` Laurent Pinchart
2019-08-21  8:21     ` Daniel Vetter
2019-08-21 13:57       ` Laurent Pinchart
2019-08-21 15:39       ` Boris Brezillon
2019-08-21 15:30     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 03/19] drm/vc4: Get rid of the dsi->bridge field Boris Brezillon
2019-08-08 20:31   ` Eric Anholt
2019-08-08 15:11 ` [PATCH RFC 04/19] drm/exynos: Get rid of exynos_dsi->out_bridge Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 05/19] drm/exynos: Don't reset bridge->next Boris Brezillon
2019-08-08 21:04   ` Boris Brezillon
2019-08-21 14:01   ` Laurent Pinchart
2019-08-08 15:11 ` [PATCH RFC 06/19] drm/bridge: Create drm_bridge_chain_xx() wrappers Boris Brezillon
2019-08-21 14:45   ` Laurent Pinchart
2019-08-21 15:53     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 07/19] drm/msm: Use drm_attach_bridge() to attach a bridge to an encoder Boris Brezillon
2019-08-19 17:19   ` Sam Ravnborg
2019-08-21 14:46     ` Laurent Pinchart
2019-08-08 15:11 ` [PATCH RFC 08/19] drm/bridge: Introduce drm_bridge_chain_get_{first, last, next}_bridge() Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 09/19] drm/bridge: Make the bridge chain a double-linked list Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 10/19] drm/bridge: Add a drm_bridge_state object Boris Brezillon
2019-08-21 20:14   ` Laurent Pinchart
2019-08-22  9:00     ` Boris Brezillon
2019-12-02 15:52       ` Laurent Pinchart
2019-08-08 15:11 ` [PATCH RFC 11/19] drm/bridge: Patch atomic hooks to take a drm_bridge_state Boris Brezillon
2019-08-22  0:02   ` Laurent Pinchart
2019-08-22  8:25     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 12/19] drm/bridge: Add an ->atomic_check() hook Boris Brezillon
2019-08-22  0:12   ` Laurent Pinchart
2019-08-22  7:58     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 13/19] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper Boris Brezillon
2019-08-22  0:17   ` Laurent Pinchart
2019-08-22  8:04     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 14/19] drm/bridge: Add the necessary bits to support bus format negotiation Boris Brezillon
2019-08-14  7:51   ` Neil Armstrong
2019-08-21 18:31     ` Boris Brezillon
2019-08-22  0:55   ` Laurent Pinchart
2019-08-22  7:48     ` Boris Brezillon
2019-08-22  9:29       ` Neil Armstrong
2019-08-22 10:09         ` Boris Brezillon
2019-08-22 10:22           ` Neil Armstrong
2019-08-22 10:34             ` Boris Brezillon
2019-08-22 11:30               ` Neil Armstrong
2019-08-08 15:11 ` [PATCH RFC 15/19] drm/imx: pd: Use bus format/flags provided by the bridge when available Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 16/19] drm/bridge: lvds-encoder: Add a way to support custom ->atomic_check() implem Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 17/19] drm/bridge: lvds-encoder: Implement bus format negotiation for sn75lvds83 Boris Brezillon
2019-08-22  0:32   ` Laurent Pinchart
2019-08-22  8:12     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 18/19] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel Boris Brezillon
2019-08-22  0:36   ` Laurent Pinchart
2019-08-22  8:15     ` Boris Brezillon
2019-08-08 15:11 ` [PATCH RFC 19/19] ARM: dts: imx: imx51-zii-rdu1: Fix the display pipeline definition Boris Brezillon
2019-08-09  6:58 ` [PATCH RFC 00/19] drm: Add support for bus-format negotiation Neil Armstrong

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.